From 296c4bfe52a3132adc5eec9f7f04e400c471cd77 Mon Sep 17 00:00:00 2001 From: Kolby Moroz Liebl <31669092+KolbyML@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:00:49 -0700 Subject: [PATCH] Run pebble database tests in Nightly CI Builds --- .github/workflows/gotestsum.sh | 11 +++ .github/workflows/nightly-ci.yml | 7 +- cmd/nitro/init_test.go | 2 + system_tests/archival_path_scheme_test.go | 4 +- system_tests/block_validator_test.go | 2 +- system_tests/bold_challenge_protocol_test.go | 7 +- system_tests/common_test.go | 86 ++++++++++++++------ system_tests/fees_test.go | 5 +- system_tests/finality_data_test.go | 2 +- system_tests/forwarder_test.go | 3 +- system_tests/multigas_dump_test.go | 4 +- system_tests/program_gas_test.go | 3 +- system_tests/program_test.go | 49 +++++++---- system_tests/pruning_test.go | 2 +- system_tests/recreatestate_rpc_test.go | 4 +- system_tests/retryable_test.go | 9 +- system_tests/revalidation_test.go | 5 +- system_tests/seq_nonce_test.go | 5 +- system_tests/seqcompensation_test.go | 3 +- system_tests/seqfeed_test.go | 3 +- system_tests/snap_sync_test.go | 4 +- system_tests/staterecovery_test.go | 2 +- system_tests/timeboost_test.go | 3 +- util/testhelpers/env/env.go | 22 ++++- util/testhelpers/flag/flag.go | 1 + util/testhelpers/stackconfig.go | 4 +- 26 files changed, 183 insertions(+), 69 deletions(-) diff --git a/.github/workflows/gotestsum.sh b/.github/workflows/gotestsum.sh index 2e1e4494fc..611cd90de5 100755 --- a/.github/workflows/gotestsum.sh +++ b/.github/workflows/gotestsum.sh @@ -12,6 +12,7 @@ tags="" run="" skip="" test_state_scheme="" +test_database_engine="" junitfile="" log=true race=false @@ -49,6 +50,12 @@ while [[ $# -gt 0 ]]; do test_state_scheme=$1 shift ;; + --test_database_engine) + shift + check_missing_value $# "$1" "--test_database_engine" + test_database_engine=$1 + shift + ;; --race) race=true shift @@ -130,6 +137,10 @@ else cmd="$cmd -args -- --test_loglevel=8" # Use error log level, which is the value 8 in the slog level enum for tests. fi +if [ "$test_database_engine" != "" ]; then + cmd="$cmd --test_database_engine=$test_database_engine" +fi + if [ "$log" == true ]; then cmd="$cmd > >(stdbuf -oL tee -a full.log | grep -vE \"DEBUG|TRACE|INFO|seal\")" else diff --git a/.github/workflows/nightly-ci.yml b/.github/workflows/nightly-ci.yml index 4b74e872d6..11cad22e36 100644 --- a/.github/workflows/nightly-ci.yml +++ b/.github/workflows/nightly-ci.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - test-mode: [legacychallenge, long, challenge, l3challenge, execution-spec-tests] + test-mode: [legacychallenge, long, challenge, l3challenge, execution-spec-tests, pebble] steps: - name: Checkout @@ -85,6 +85,11 @@ jobs: if: matrix.test-mode == 'execution-spec-tests' run: ${{ github.workspace }}/.github/workflows/runExecutionSpecTests.sh + - name: run tests with pebble db + if: matrix.test-mode == 'pebble' + run: | + ${{ github.workspace }}/.github/workflows/gotestsum.sh --timeout 90m --test_database_engine pebble + - name: Archive detailed run log uses: actions/upload-artifact@v5 with: diff --git a/cmd/nitro/init_test.go b/cmd/nitro/init_test.go index e79d2ab95e..77210a506c 100644 --- a/cmd/nitro/init_test.go +++ b/cmd/nitro/init_test.go @@ -418,6 +418,7 @@ func TestOpenInitializeChainDbIncompatibleStateScheme(t *testing.T) { defer cancel() stackConfig := testhelpers.CreateStackConfigForTest(t.TempDir()) + stackConfig.DBEngine = rawdb.DBPebble stack, err := node.New(stackConfig) Require(t, err) defer stack.Close() @@ -685,6 +686,7 @@ func TestOpenInitializeChainDbEmptyInit(t *testing.T) { defer cancel() stackConfig := testhelpers.CreateStackConfigForTest(t.TempDir()) + stackConfig.DBEngine = rawdb.DBPebble stack, err := node.New(stackConfig) Require(t, err) defer stack.Close() diff --git a/system_tests/archival_path_scheme_test.go b/system_tests/archival_path_scheme_test.go index e3a4808753..64b1a64488 100644 --- a/system_tests/archival_path_scheme_test.go +++ b/system_tests/archival_path_scheme_test.go @@ -14,7 +14,7 @@ import ( func TestAccessingPathSchemeState(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) // This test is PathScheme specific, it shouldn't be run with HashScheme builder.RequireScheme(t, rawdb.PathScheme) @@ -56,7 +56,7 @@ func TestAccessingPathSchemeState(t *testing.T) { func TestAccessingPathSchemeArchivalState(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) builder.execConfig.Caching.Archive = true builder.execConfig.Caching.StateHistory = 2 diff --git a/system_tests/block_validator_test.go b/system_tests/block_validator_test.go index 4fc3e40cee..6bb4d60b2d 100644 --- a/system_tests/block_validator_test.go +++ b/system_tests/block_validator_test.go @@ -28,7 +28,7 @@ import ( "github.com/offchainlabs/nitro/solgen/go/precompilesgen" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/redisutil" - "github.com/offchainlabs/nitro/util/testhelpers/flag" + testflag "github.com/offchainlabs/nitro/util/testhelpers/flag" "github.com/offchainlabs/nitro/util/testhelpers/github" "github.com/offchainlabs/nitro/validator/client/redis" ) diff --git a/system_tests/bold_challenge_protocol_test.go b/system_tests/bold_challenge_protocol_test.go index 50cfc46ea9..e5a8f4b411 100644 --- a/system_tests/bold_challenge_protocol_test.go +++ b/system_tests/bold_challenge_protocol_test.go @@ -568,7 +568,7 @@ func createTestNodeOnL1ForBoldProtocol( nodeConfig.BatchPoster.DataPoster.MaxMempoolTransactions = 18 fatalErrChan := make(chan error, 10) withoutClientWrapper := false - l1info, l1client, l1backend, l1stack, _, _ = createTestL1BlockChain(t, nil, withoutClientWrapper) + l1info, l1client, l1backend, l1stack, _, _ = createTestL1BlockChain(t, nil, withoutClientWrapper, testhelpers.CreateStackConfigForTest("")) var l2chainDb ethdb.Database var l2arbDb ethdb.Database var l2blockchain *core.BlockChain @@ -636,8 +636,10 @@ func createTestNodeOnL1ForBoldProtocol( execConfig := ExecConfigDefaultNonSequencerTest(t, rawdb.HashScheme) Require(t, execConfig.Validate()) + stackConfig := testhelpers.CreateStackConfigForTest("") + stackConfig.DBEngine = rawdb.DBPebble initMessage := getInitMessage(ctx, t, l1client, addresses) - _, l2stack, l2chainDb, l2arbDb, l2blockchain = createNonL1BlockChainWithStackConfig(t, l2info, "", chainConfig, nil, initMessage, nil, execConfig) + _, l2stack, l2chainDb, l2arbDb, l2blockchain = createNonL1BlockChainWithStackConfig(t, l2info, "", chainConfig, nil, initMessage, stackConfig, execConfig) var sequencerTxOptsPtr *bind.TransactOpts var dataSigner signature.DataSignerFunc if isSequencer { @@ -848,6 +850,7 @@ func create2ndNodeWithConfigForBoldProtocol( nodeConfig.BatchPoster.DataPoster.MaxMempoolTransactions = 18 if stackConfig == nil { stackConfig = testhelpers.CreateStackConfigForTest(t.TempDir()) + stackConfig.DBEngine = rawdb.DBPebble } l2stack, err := node.New(stackConfig) Require(t, err) diff --git a/system_tests/common_test.go b/system_tests/common_test.go index 7c29caeb18..6b749a16ec 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -289,7 +289,7 @@ type NodeBuilder struct { isSequencer bool takeOwnership bool withL1 bool - defaultDbScheme string + defaultStateScheme string addresses *chaininfo.RollupAddresses l3Addresses *chaininfo.RollupAddresses initMessage *arbostypes.ParsedInitMessage @@ -377,12 +377,27 @@ func (b *NodeBuilder) DefaultConfig(t *testing.T, withL1 bool) *NodeBuilder { b.l2StackConfig = testhelpers.CreateStackConfigForTest(b.dataDir) cp := valnode.TestValidationConfig b.valnodeConfig = &cp - b.defaultDbScheme = rawdb.HashScheme + b.defaultStateScheme = rawdb.HashScheme if *testflag.StateSchemeFlag == rawdb.PathScheme || *testflag.StateSchemeFlag == rawdb.HashScheme { - b.defaultDbScheme = *testflag.StateSchemeFlag + b.defaultStateScheme = *testflag.StateSchemeFlag } - b.execConfig = ExecConfigDefaultTest(t, b.defaultDbScheme) + b.execConfig = ExecConfigDefaultTest(t, b.defaultStateScheme) b.l3Config = L3NitroConfigDefaultTest(t) + + return b +} + +// Overrides the database selected with `--test_database_engine` flag +// +// Useful if the test needs a specific database engine to be used +func (b *NodeBuilder) WithDatabase(database string) *NodeBuilder { + if database != env.MemoryDB && database != rawdb.DBPebble && database != rawdb.DBLeveldb { + panic("unknown database engine: " + database) + } + + b.l1StackConfig.DBEngine = database + b.l2StackConfig.DBEngine = database + b.l3Config.stackConfig.DBEngine = database return b } @@ -435,19 +450,19 @@ func (b *NodeBuilder) RequireScheme(t *testing.T, scheme string) *NodeBuilder { if testflag.StateSchemeFlag != nil && *testflag.StateSchemeFlag != "" && *testflag.StateSchemeFlag != scheme { t.Skip("skipping because db scheme is set and not ", scheme) } - if b.defaultDbScheme != scheme && b.execConfig != nil { + if b.defaultStateScheme != scheme && b.execConfig != nil { b.execConfig.Caching.StateScheme = scheme Require(t, b.execConfig.Validate()) } - b.defaultDbScheme = scheme + b.defaultStateScheme = scheme return b } func (b *NodeBuilder) ExecConfigDefaultTest(t *testing.T, sequencer bool) *gethexec.Config { if sequencer { - ExecConfigDefaultTest(t, b.defaultDbScheme) + ExecConfigDefaultTest(t, b.defaultStateScheme) } - return ExecConfigDefaultNonSequencerTest(t, b.defaultDbScheme) + return ExecConfigDefaultNonSequencerTest(t, b.defaultStateScheme) } // WithL1ClientWrapper creates a ClientWrapper for the L1 RPC client before passing it to the L2 node. @@ -584,8 +599,8 @@ func (b *NodeBuilder) CheckConfig(t *testing.T) { // validation currently requires hash b.RequireScheme(t, rawdb.HashScheme) } - if b.defaultDbScheme == "" { - b.defaultDbScheme = env.GetTestStateScheme() + if b.defaultStateScheme == "" { + b.defaultStateScheme = env.GetTestStateScheme() } if b.execConfig == nil { b.execConfig = b.ExecConfigDefaultTest(t, true) @@ -615,7 +630,7 @@ func (b *NodeBuilder) BuildL1(t *testing.T) { t.Fatal(err) } b.L1 = NewTestClient(b.ctx) - b.L1Info, b.L1.Client, b.L1.L1Backend, b.L1.Stack, b.L1.ClientWrapper, b.L1.L1BlobReader = createTestL1BlockChain(t, b.L1Info, b.withL1ClientWrapper) + b.L1Info, b.L1.Client, b.L1.L1Backend, b.L1.Stack, b.L1.ClientWrapper, b.L1.L1BlobReader = createTestL1BlockChain(t, b.L1Info, b.withL1ClientWrapper, b.l1StackConfig) locator, err := server_common.NewMachineLocator(b.valnodeConfig.Wasm.RootPath) Require(t, err) b.addresses, b.initMessage = deployOnParentChain( @@ -1399,7 +1414,7 @@ func createTestValidationNode(t *testing.T, ctx context.Context, config *valnode stackConf.WSModules = []string{server_api.Namespace} stackConf.P2P.NoDiscovery = true stackConf.P2P.ListenAddr = "" - stackConf.DBEngine = "leveldb" // TODO Try pebble again in future once iterator race condition issues are fixed + stackConf.DBEngine = env.GetTestDatabaseEngine() valnode.EnsureValidationExposedViaAuthRPC(&stackConf) @@ -1484,11 +1499,10 @@ func AddValNode(t *testing.T, ctx context.Context, nodeConfig *arbnode.Config, u configByValidationNode(nodeConfig, valStack) } -func createTestL1BlockChain(t *testing.T, l1info info, withClientWrapper bool) (info, *ethclient.Client, *eth.Ethereum, *node.Node, *ClientWrapper, daprovider.BlobReader) { +func createTestL1BlockChain(t *testing.T, l1info info, withClientWrapper bool, stackConfig *node.Config) (info, *ethclient.Client, *eth.Ethereum, *node.Node, *ClientWrapper, daprovider.BlobReader) { if l1info == nil { l1info = NewL1TestInfo(t) } - stackConfig := testhelpers.CreateStackConfigForTest("") l1info.GenerateAccount("Faucet") for _, acct := range DefaultChainAccounts { l1info.GenerateAccount(acct) @@ -1497,6 +1511,7 @@ func createTestL1BlockChain(t *testing.T, l1info info, withClientWrapper bool) ( chainConfig := chaininfo.ArbitrumDevTestChainConfig() chainConfig.ArbitrumChainParams = params.ArbitrumChainParams{} + stackConfig.DataDir = "" stack, err := node.New(stackConfig) Require(t, err) @@ -1738,15 +1753,23 @@ func createNonL1BlockChainWithStackConfig( stack, err := node.New(stackConfig) Require(t, err) - chainData, err := stack.OpenDatabaseWithOptions("l2chaindata", node.DatabaseOptions{MetricsNamespace: "l2chaindata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("l2chaindata")}) - Require(t, err) - - wasmData, err := stack.OpenDatabaseWithOptions("wasm", node.DatabaseOptions{MetricsNamespace: "wasm/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("wasm"), NoFreezer: true}) - Require(t, err) + chainData := rawdb.NewMemoryDatabase() + if stack.Config().DBEngine != env.MemoryDB { + chainData, err = stack.OpenDatabaseWithOptions("l2chaindata", node.DatabaseOptions{MetricsNamespace: "l2chaindata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("l2chaindata")}) + Require(t, err) + } + wasmData := rawdb.NewMemoryDatabase() + if stack.Config().DBEngine != env.MemoryDB { + wasmData, err = stack.OpenDatabaseWithOptions("wasm", node.DatabaseOptions{MetricsNamespace: "wasm/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("wasm"), NoFreezer: true}) + Require(t, err) + } chainDb := rawdb.WrapDatabaseWithWasm(chainData, wasmData) - arbDb, err := stack.OpenDatabaseWithOptions("arbitrumdata", node.DatabaseOptions{MetricsNamespace: "arbitrumdata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("arbitrumdata"), NoFreezer: true}) - Require(t, err) + arbDb := rawdb.NewMemoryDatabase() + if stack.Config().DBEngine != env.MemoryDB { + arbDb, err = stack.OpenDatabaseWithOptions("arbitrumdata", node.DatabaseOptions{MetricsNamespace: "arbitrumdata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("arbitrumdata"), NoFreezer: true}) + Require(t, err) + } initReader := statetransfer.NewMemoryInitDataReader(&info.ArbInitData) if initMessage == nil { @@ -1836,14 +1859,23 @@ func Create2ndNodeWithConfig( chainStack, err := node.New(stackConfig) Require(t, err) - chainData, err := chainStack.OpenDatabaseWithOptions("l2chaindata", node.DatabaseOptions{MetricsNamespace: "l2chaindata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("l2chaindata")}) - Require(t, err) - wasmData, err := chainStack.OpenDatabaseWithOptions("wasm", node.DatabaseOptions{MetricsNamespace: "wasm/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("wasm"), NoFreezer: true}) - Require(t, err) + chainData := rawdb.NewMemoryDatabase() + if chainStack.Config().DBEngine != env.MemoryDB { + chainData, err = chainStack.OpenDatabaseWithOptions("l2chaindata", node.DatabaseOptions{MetricsNamespace: "l2chaindata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("l2chaindata")}) + Require(t, err) + } + wasmData := rawdb.NewMemoryDatabase() + if chainStack.Config().DBEngine != env.MemoryDB { + wasmData, err = chainStack.OpenDatabaseWithOptions("wasm", node.DatabaseOptions{MetricsNamespace: "wasm/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("wasm"), NoFreezer: true}) + Require(t, err) + } chainDb := rawdb.WrapDatabaseWithWasm(chainData, wasmData) - arbDb, err := chainStack.OpenDatabaseWithOptions("arbitrumdata", node.DatabaseOptions{MetricsNamespace: "arbitrumdata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("arbitrumdata"), NoFreezer: true}) - Require(t, err) + arbDb := rawdb.NewMemoryDatabase() + if chainStack.Config().DBEngine != env.MemoryDB { + arbDb, err = chainStack.OpenDatabaseWithOptions("arbitrumdata", node.DatabaseOptions{MetricsNamespace: "arbitrumdata/", PebbleExtraOptions: conf.PersistentConfigDefault.Pebble.ExtraOptions("arbitrumdata"), NoFreezer: true}) + Require(t, err) + } initReader := statetransfer.NewMemoryInitDataReader(chainInitData) dataSigner := signature.DataSignerFromPrivateKey(parentChainInfo.GetInfoWithPrivKey("Sequencer").PrivateKey) diff --git a/system_tests/fees_test.go b/system_tests/fees_test.go index 22875fbebd..b139f4ad59 100644 --- a/system_tests/fees_test.go +++ b/system_tests/fees_test.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -33,7 +34,7 @@ func TestSequencerFeePaid(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) cleanup := builder.Build(t) defer cleanup() @@ -135,7 +136,7 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) builder.nodeConfig.DelayedSequencer.FinalizeDistance = 1 cleanup := builder.Build(t) defer cleanup() diff --git a/system_tests/finality_data_test.go b/system_tests/finality_data_test.go index 34b5542006..0383a4563d 100644 --- a/system_tests/finality_data_test.go +++ b/system_tests/finality_data_test.go @@ -36,7 +36,7 @@ func TestFinalizedBlocksMovedToAncients(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) // The procedure that periodically pushes finality data, from consensus to execution, // will not be able to get finalized/safe block numbers since UseFinalityData is false. // Therefore, with UseFinalityData set to false, ExecutionEngine will not be able to move data to ancients by itself, diff --git a/system_tests/forwarder_test.go b/system_tests/forwarder_test.go index fae585b9c0..ba1191b59a 100644 --- a/system_tests/forwarder_test.go +++ b/system_tests/forwarder_test.go @@ -16,6 +16,7 @@ import ( "github.com/alicebob/miniredis/v2" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethclient" "github.com/offchainlabs/nitro/arbnode" @@ -299,7 +300,7 @@ func TestRedisForwarderFallbackNoRedis(t *testing.T) { ipcPath: fallbackIpcPath, redisUrl: redisUrl, enableSecCoordinator: false, - }) + }).WithDatabase(rawdb.DBPebble) cleanup := builder.Build(t) defer cleanup() fallbackClient := builder.L2.Client diff --git a/system_tests/multigas_dump_test.go b/system_tests/multigas_dump_test.go index d4ee610498..da2a0caa25 100644 --- a/system_tests/multigas_dump_test.go +++ b/system_tests/multigas_dump_test.go @@ -9,6 +9,8 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/core/rawdb" ) // TestMultigasDataFromReceipts spins up an L2 node with ancd checks if multigas data is present in receipts @@ -44,7 +46,7 @@ func TestMultigasDataCanBeDisabled(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, false) + builder := NewNodeBuilder(ctx).DefaultConfig(t, false).WithDatabase(rawdb.DBPebble) builder.execConfig.ExposeMultiGas = false cleanup := builder.Build(t) defer cleanup() diff --git a/system_tests/program_gas_test.go b/system_tests/program_gas_test.go index fd5995a1f0..095be3a5b5 100644 --- a/system_tests/program_gas_test.go +++ b/system_tests/program_gas_test.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -275,7 +276,7 @@ func TestProgramKeccakCost(t *testing.T) { func setupGasCostTest(t *testing.T) *NodeBuilder { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) cleanup := builder.Build(t) t.Cleanup(cleanup) return builder diff --git a/system_tests/program_test.go b/system_tests/program_test.go index 06cfbb4fd7..5bcbd3f961 100644 --- a/system_tests/program_test.go +++ b/system_tests/program_test.go @@ -509,7 +509,9 @@ func TestProgramMath(t *testing.T) { } func fastMathTest(t *testing.T, jit bool) { - builder, auth, cleanup := setupProgramTest(t, jit) + builder, auth, cleanup := setupProgramTest(t, jit, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2client := builder.L2.Client defer cleanup() @@ -806,7 +808,9 @@ func TestProgramLogsWithTracing(t *testing.T) { } func testLogs(t *testing.T, jit, tracing bool) { - builder, auth, cleanup := setupProgramTest(t, jit) + builder, auth, cleanup := setupProgramTest(t, jit, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2info := builder.L2Info l2client := builder.L2.Client @@ -1036,7 +1040,9 @@ func TestProgramMemory(t *testing.T) { } func testMemory(t *testing.T, jit bool) { - builder, auth, cleanup := setupProgramTest(t, jit) + builder, auth, cleanup := setupProgramTest(t, jit, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2info := builder.L2Info l2client := builder.L2.Client @@ -1195,7 +1201,9 @@ func TestProgramActivateFails(t *testing.T) { } func testActivateFails(t *testing.T, jit bool) { - builder, auth, cleanup := setupProgramTest(t, jit) + builder, auth, cleanup := setupProgramTest(t, jit, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2client := builder.L2.Client defer cleanup() @@ -1293,7 +1301,7 @@ func TestStylusPrecompileMethodsSimple(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) cleanup := builder.Build(t) defer cleanup() @@ -1933,7 +1941,7 @@ func formatTime(duration time.Duration) string { return fmt.Sprintf("%.2f%s", span, units[unit]) } -func testWasmRecreate(t *testing.T, builder *NodeBuilder, targetsBefore, targetsAfter []string, numModules int, removeWasmDbBetween bool, storeTx, loadTx *types.Transaction, want []byte) { +func testWasmRecreate(t *testing.T, builder *NodeBuilder, targetsBefore, targetsAfter []string, numModules int, removeWasmDbBetween bool, storeTx, loadTx *types.Transaction, want []byte, databaseEngine string) { ctx := builder.ctx l2info := builder.L2Info l2client := builder.L2.Client @@ -1945,6 +1953,7 @@ func testWasmRecreate(t *testing.T, builder *NodeBuilder, targetsBefore, targets testDir := t.TempDir() nodeBStack := testhelpers.CreateStackConfigForTest(testDir) + nodeBStack.DBEngine = databaseEngine nodeBExecConfigBefore := *builder.execConfig nodeBExecConfigBefore.StylusTarget.ExtraArchs = targetsBefore nodeB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{stackConfig: nodeBStack, execConfig: &nodeBExecConfigBefore}) @@ -2067,18 +2076,21 @@ func TestWasmRecreate(t *testing.T) { targetsAfter: localTargetOnly, }, } + databaseEngine := rawdb.DBPebble for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - testWasmRecreateWithCall(t, tc.targetsBefore, tc.targetsAfter, tc.removeWasmDbBetween) + testWasmRecreateWithCall(t, tc.targetsBefore, tc.targetsAfter, tc.removeWasmDbBetween, databaseEngine) }) t.Run(tc.name+" with delegate call", func(t *testing.T) { - testWasmRecreateWithDelegatecall(t, tc.targetsBefore, tc.targetsAfter, tc.removeWasmDbBetween) + testWasmRecreateWithDelegatecall(t, tc.targetsBefore, tc.targetsAfter, tc.removeWasmDbBetween, databaseEngine) }) } } -func testWasmRecreateWithCall(t *testing.T, targetsBefore, targetsAfter []string, removeWasmDbBetween bool) { - builder, auth, cleanup := setupProgramTest(t, true) +func testWasmRecreateWithCall(t *testing.T, targetsBefore, targetsAfter []string, removeWasmDbBetween bool, databaseEngine string) { + builder, auth, cleanup := setupProgramTest(t, true, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2info := builder.L2Info l2client := builder.L2.Client @@ -2092,11 +2104,13 @@ func testWasmRecreateWithCall(t *testing.T, targetsBefore, targetsAfter []string storeTx := l2info.PrepareTxTo("Owner", &storage, l2info.TransferGas, nil, argsForStorageWrite(zero, val)) loadTx := l2info.PrepareTxTo("Owner", &storage, l2info.TransferGas, nil, argsForStorageRead(zero)) - testWasmRecreate(t, builder, localTargetOnly, allWasmTargets, 1, false, storeTx, loadTx, val[:]) + testWasmRecreate(t, builder, localTargetOnly, allWasmTargets, 1, false, storeTx, loadTx, val[:], databaseEngine) } -func testWasmRecreateWithDelegatecall(t *testing.T, targetsBefore, targetsAfter []string, removeWasmDbBetween bool) { - builder, auth, cleanup := setupProgramTest(t, true) +func testWasmRecreateWithDelegatecall(t *testing.T, targetsBefore, targetsAfter []string, removeWasmDbBetween bool, databaseEngine string) { + builder, auth, cleanup := setupProgramTest(t, true, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx l2info := builder.L2Info l2client := builder.L2.Client @@ -2114,7 +2128,7 @@ func testWasmRecreateWithDelegatecall(t *testing.T, targetsBefore, targetsAfter data = argsForMulticall(vm.DELEGATECALL, storage, big.NewInt(0), argsForStorageRead(zero)) loadTx := l2info.PrepareTxTo("Owner", &multicall, l2info.TransferGas, nil, data) - testWasmRecreate(t, builder, localTargetOnly, allWasmTargets, 2, true, storeTx, loadTx, val[:]) + testWasmRecreate(t, builder, localTargetOnly, allWasmTargets, 2, true, storeTx, loadTx, val[:], databaseEngine) } // createMapFromDb is used in verifying if wasm store rebuilding works @@ -2139,8 +2153,10 @@ func createMapFromDb(db ethdb.KeyValueStore) (map[string][]byte, error) { } func TestWasmStoreRebuilding(t *testing.T) { + databaseEngine := rawdb.DBLeveldb builder, auth, cleanup := setupProgramTest(t, true, func(b *NodeBuilder) { b.WithExtraArchs(allWasmTargets) + b.WithDatabase(databaseEngine) }) ctx := builder.ctx l2info := builder.L2Info @@ -2160,6 +2176,7 @@ func TestWasmStoreRebuilding(t *testing.T) { testDir := t.TempDir() nodeBStack := testhelpers.CreateStackConfigForTest(testDir) + nodeBStack.DBEngine = databaseEngine nodeB, cleanupB := builder.Build2ndNode(t, &SecondNodeParams{stackConfig: nodeBStack}) _, err = EnsureTxSucceeded(ctx, nodeB.Client, storeTx) @@ -2716,7 +2733,9 @@ func TestRepopulateWasmLongTermCacheFromLru(t *testing.T) { func TestOutOfGasInStorageCacheFlush(t *testing.T) { jit := false - builder, auth, cleanup := setupProgramTest(t, jit) + builder, auth, cleanup := setupProgramTest(t, jit, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) ctx := builder.ctx defer cleanup() diff --git a/system_tests/pruning_test.go b/system_tests/pruning_test.go index a1e3dbf1a6..21e06b5e1a 100644 --- a/system_tests/pruning_test.go +++ b/system_tests/pruning_test.go @@ -44,7 +44,7 @@ func testPruning(t *testing.T, mode string, pruneParallelStorageTraversal bool) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) // PathScheme prunes the state trie by itself, so only HashScheme should be tested builder.RequireScheme(t, rawdb.HashScheme) diff --git a/system_tests/recreatestate_rpc_test.go b/system_tests/recreatestate_rpc_test.go index c3bc53ee37..08e73129ca 100644 --- a/system_tests/recreatestate_rpc_test.go +++ b/system_tests/recreatestate_rpc_test.go @@ -170,7 +170,7 @@ func TestRecreateStateForRPCBigEnoughDepthLimit(t *testing.T) { func TestRecreateStateForRPCDepthLimitExceeded(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithTakeOwnership(false) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble).WithTakeOwnership(false) builder.RequireScheme(t, rawdb.HashScheme) builder.execConfig.RPC.MaxRecreateStateDepth = int64(200) builder.execConfig.Sequencer.MaxBlockSpeed = 0 @@ -335,7 +335,7 @@ func testSkippingSavingStateAndRecreatingAfterRestart(t *testing.T, cacheConfig maxRecreateStateDepth := int64(30 * 1000 * 1000) ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, false) + builder := NewNodeBuilder(ctx).DefaultConfig(t, false).WithDatabase(rawdb.DBPebble) builder.execConfig.RPC.MaxRecreateStateDepth = maxRecreateStateDepth builder.execConfig.Sequencer.MaxBlockSpeed = 0 diff --git a/system_tests/retryable_test.go b/system_tests/retryable_test.go index c389d14aca..e0be75ca34 100644 --- a/system_tests/retryable_test.go +++ b/system_tests/retryable_test.go @@ -268,6 +268,7 @@ func TestSubmitRetryableImmediateSuccess(t *testing.T) { func testSubmitRetryableEmptyEscrow(t *testing.T, arbosVersion uint64) { builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t, func(builder *NodeBuilder) { builder.WithArbOSVersion(arbosVersion) + builder.WithDatabase(rawdb.DBPebble) }) defer teardown() @@ -510,7 +511,9 @@ func insertRetriables( } func TestSubmitManyRetryableFailThenRetry(t *testing.T) { - builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t) + builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) defer teardown() infraFeeAddr, networkFeeAddr := setupFeeAddresses(t, ctx, builder) elevateL2Basefee(t, ctx, builder) @@ -1294,7 +1297,9 @@ func TestL1FundedUnsignedTransaction(t *testing.T) { } func TestRetryableSubmissionAndRedeemFees(t *testing.T) { - builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t) + builder, delayedInbox, lookupL2Tx, ctx, teardown := retryableSetup(t, func(b *NodeBuilder) { + b.WithDatabase(rawdb.DBPebble) + }) defer teardown() infraFeeAddr, networkFeeAddr := setupFeeAddresses(t, ctx, builder) diff --git a/system_tests/revalidation_test.go b/system_tests/revalidation_test.go index 57283b6794..2ef7c28d58 100644 --- a/system_tests/revalidation_test.go +++ b/system_tests/revalidation_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -22,7 +23,8 @@ func TestRevalidationForSpecifiedRange(t *testing.T) { var transferGas = util.NormalizeL2GasForL1GasInitial(800_000, params.GWei) // include room for aggregator L1 costs // 1st node with sequencer, stays up all the time. - builder := NewNodeBuilder(ctx).DefaultConfig(t, true).DontParalellise() + databaseEngine := rawdb.DBPebble + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).DontParalellise().WithDatabase(databaseEngine) builder.nodeConfig.BlockValidator.Enable = true builder.L2Info = NewBlockChainTestInfo( t, @@ -36,6 +38,7 @@ func TestRevalidationForSpecifiedRange(t *testing.T) { // This node will be stopped in middle. testDir := t.TempDir() nodeBStack := testhelpers.CreateStackConfigForTest(testDir) + nodeBStack.DBEngine = databaseEngine nodeBConfig := builder.nodeConfig nodeBConfig.BatchPoster.Enable = false nodeBParams := &SecondNodeParams{ diff --git a/system_tests/seq_nonce_test.go b/system_tests/seq_nonce_test.go index 85b5b15fd3..e7409789a1 100644 --- a/system_tests/seq_nonce_test.go +++ b/system_tests/seq_nonce_test.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/offchainlabs/nitro/util/arbmath" @@ -24,7 +25,7 @@ func TestSequencerParallelNonces(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, false) + builder := NewNodeBuilder(ctx).DefaultConfig(t, false).WithDatabase(rawdb.DBPebble) builder.takeOwnership = false builder.execConfig.Sequencer.NonceFailureCacheExpiry = time.Minute cleanup := builder.Build(t) @@ -127,7 +128,7 @@ func TestSequencerNonceHandling(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) builder.execConfig.Sequencer.MaxBlockSpeed = time.Second builder.execConfig.Sequencer.NonceFailureCacheExpiry = 4 * time.Second cleanup := builder.Build(t) diff --git a/system_tests/seqcompensation_test.go b/system_tests/seqcompensation_test.go index 34e478fb73..53202d4c1d 100644 --- a/system_tests/seqcompensation_test.go +++ b/system_tests/seqcompensation_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/offchainlabs/nitro/arbos/l1pricing" @@ -18,7 +19,7 @@ import ( func TestSequencerCompensation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) cleanup := builder.Build(t) defer cleanup() diff --git a/system_tests/seqfeed_test.go b/system_tests/seqfeed_test.go index c4aaa63519..975b9702a8 100644 --- a/system_tests/seqfeed_test.go +++ b/system_tests/seqfeed_test.go @@ -12,6 +12,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" @@ -439,7 +440,7 @@ func TestPopulateFeedBacklog(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) builder.BuildL1(t) userAccount := "User2" diff --git a/system_tests/snap_sync_test.go b/system_tests/snap_sync_test.go index 0f2d616dd7..adbfa07839 100644 --- a/system_tests/snap_sync_test.go +++ b/system_tests/snap_sync_test.go @@ -28,7 +28,8 @@ func TestSnapSync(t *testing.T) { var transferGas = util.NormalizeL2GasForL1GasInitial(800_000, params.GWei) // include room for aggregator L1 costs // 1st node with sequencer, stays up all the time. - builder := NewNodeBuilder(ctx).DefaultConfig(t, true).DontParalellise() + databaseEngine := rawdb.DBPebble + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).DontParalellise().WithDatabase(databaseEngine) // only supported for hash scheme builder.RequireScheme(t, rawdb.HashScheme) builder.L2Info = NewBlockChainTestInfo( @@ -43,6 +44,7 @@ func TestSnapSync(t *testing.T) { // This node will be stopped in middle and arbitrumdata will be deleted. testDir := t.TempDir() nodeBStack := testhelpers.CreateStackConfigForTest(testDir) + nodeBStack.DBEngine = databaseEngine nodeBConfig := builder.nodeConfig nodeBConfig.BatchPoster.Enable = false nodeBParams := &SecondNodeParams{ diff --git a/system_tests/staterecovery_test.go b/system_tests/staterecovery_test.go index ed68dcfa44..5b403b339f 100644 --- a/system_tests/staterecovery_test.go +++ b/system_tests/staterecovery_test.go @@ -19,7 +19,7 @@ import ( func TestRecreateMissingStates(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder := NewNodeBuilder(ctx).DefaultConfig(t, true).WithDatabase(rawdb.DBPebble) builder.RequireScheme(t, rawdb.HashScheme) builder.execConfig.Caching.Archive = true builder.execConfig.Caching.MaxNumberOfBlocksToSkipStateSaving = 16 diff --git a/system_tests/timeboost_test.go b/system_tests/timeboost_test.go index 00d13aeade..b2feecb77b 100644 --- a/system_tests/timeboost_test.go +++ b/system_tests/timeboost_test.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" @@ -922,7 +923,7 @@ func TestTimeboostBulkBlockMetadataAPI(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - builder := NewNodeBuilder(ctx).DefaultConfig(t, false).DontParalellise() + builder := NewNodeBuilder(ctx).DefaultConfig(t, false).DontParalellise().WithDatabase(rawdb.DBPebble) builder.nodeConfig.TransactionStreamer.TrackBlockMetadataFrom = 1 builder.execConfig.BlockMetadataApiCacheSize = 0 // Caching is disabled cleanup := builder.Build(t) diff --git a/util/testhelpers/env/env.go b/util/testhelpers/env/env.go index 80aaf80756..eebc137a70 100644 --- a/util/testhelpers/env/env.go +++ b/util/testhelpers/env/env.go @@ -7,9 +7,11 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/log" - "github.com/offchainlabs/nitro/util/testhelpers/flag" + testflag "github.com/offchainlabs/nitro/util/testhelpers/flag" ) +const MemoryDB = "in-memory" + // There are two CI steps, one to run tests using the path state scheme, and one to run tests using the hash state scheme. // An environment variable controls that behavior. func GetTestStateScheme() string { @@ -20,3 +22,21 @@ func GetTestStateScheme() string { log.Debug("test state scheme", "testStateScheme", stateScheme) return stateScheme } + +func GetTestDatabaseEngine() string { + engineFlag := *testflag.DatabaseEngineFlag + databaseEngine := MemoryDB + + switch engineFlag { + case rawdb.DBLeveldb, rawdb.DBPebble, MemoryDB: + databaseEngine = engineFlag + default: + log.Warn("invalid test database engine flag; using default", + "provided", engineFlag, + "default", MemoryDB, + ) + } + + log.Debug("test database scheme", "testDatabaseEngine", databaseEngine) + return databaseEngine +} diff --git a/util/testhelpers/flag/flag.go b/util/testhelpers/flag/flag.go index 8f526c5d4b..33e758fce4 100644 --- a/util/testhelpers/flag/flag.go +++ b/util/testhelpers/flag/flag.go @@ -9,6 +9,7 @@ import ( var ( fs = flag.NewFlagSet("test", flag.ExitOnError) StateSchemeFlag = fs.String("test_state_scheme", "", "State scheme to use for tests") + DatabaseEngineFlag = fs.String("test_database_engine", "", "Database engine to use for tests") RedisFlag = fs.String("test_redis", "", "Redis URL for testing") RecordBlockInputsEnable = fs.Bool("recordBlockInputs.enable", false, "Whether to record block inputs as a json file") RecordBlockInputsWithSlug = fs.String("recordBlockInputs.WithSlug", "", "Slug directory for validationInputsWriter") diff --git a/util/testhelpers/stackconfig.go b/util/testhelpers/stackconfig.go index baebae302c..a1ec318310 100644 --- a/util/testhelpers/stackconfig.go +++ b/util/testhelpers/stackconfig.go @@ -5,6 +5,8 @@ package testhelpers import ( "github.com/ethereum/go-ethereum/node" + + "github.com/offchainlabs/nitro/util/testhelpers/env" ) func CreateStackConfigForTest(dataDir string) *node.Config { @@ -26,6 +28,6 @@ func CreateStackConfigForTest(dataDir string) *node.Config { stackConf.P2P.NoDial = true stackConf.P2P.ListenAddr = "" stackConf.P2P.NAT = nil - stackConf.DBEngine = "leveldb" + stackConf.DBEngine = env.GetTestDatabaseEngine() return &stackConf }