From d586a671a383312f32c980d9a8476a8eb3d94f1c Mon Sep 17 00:00:00 2001 From: devopsbo3 <69951731+devopsbo3@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:27:53 -0600 Subject: [PATCH] Revert "all: activate pbss as experimental feature (#26274)" This reverts commit 105352624675e54eee6d26b70f5bc69c64a38352. --- cmd/evm/blockrunner.go | 3 +- cmd/evm/runner.go | 18 +- cmd/evm/staterunner.go | 35 +- cmd/geth/chaincmd.go | 30 +- cmd/geth/dbcmd.go | 6 +- cmd/geth/genesis_test.go | 4 +- cmd/geth/main.go | 3 - cmd/geth/snapshot.go | 54 +- cmd/utils/flags.go | 185 +---- cmd/utils/flags_legacy.go | 9 - core/block_validator_test.go | 7 +- core/blockchain.go | 163 ++-- core/blockchain_reader.go | 14 +- core/blockchain_repair_test.go | 56 +- core/blockchain_sethead_test.go | 33 +- core/blockchain_snapshot_test.go | 260 +++---- core/blockchain_test.go | 701 ++++-------------- core/chain_makers.go | 16 +- core/chain_makers_test.go | 11 +- core/dao_test.go | 8 +- core/genesis.go | 14 +- core/genesis_test.go | 53 +- core/headerchain_test.go | 2 +- core/rawdb/accessors_chain_test.go | 2 +- core/rawdb/accessors_trie.go | 26 +- core/rawdb/ancient_scheme.go | 8 +- core/rawdb/ancient_utils.go | 56 +- core/rawdb/database.go | 21 +- core/rawdb/schema.go | 26 +- core/state/database.go | 4 +- core/state/iterator_test.go | 15 +- core/state/pruner/pruner.go | 13 +- core/state/snapshot/generate.go | 3 +- core/state/snapshot/generate_test.go | 142 +--- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_test.go | 57 +- core/state/sync_test.go | 169 ++--- core/types/hashing_test.go | 8 +- eth/api_backend.go | 2 +- eth/api_debug.go | 2 +- eth/backend.go | 16 +- eth/downloader/testchain_test.go | 3 +- eth/ethconfig/config.go | 10 +- eth/ethconfig/gen_config.go | 18 - eth/fetcher/block_fetcher_test.go | 2 +- eth/filters/filter_test.go | 4 +- eth/handler.go | 15 +- eth/protocols/eth/handler_test.go | 2 +- eth/protocols/eth/handlers.go | 7 +- eth/protocols/snap/handler.go | 8 +- eth/protocols/snap/sync_test.go | 204 ++--- eth/state_accessor.go | 91 +-- .../internal/tracetest/calltrace_test.go | 13 +- .../internal/tracetest/flat_calltrace_test.go | 3 +- .../internal/tracetest/prestate_test.go | 4 +- eth/tracers/tracers_test.go | 4 +- internal/flags/categories.go | 2 +- les/client.go | 3 +- les/handler_test.go | 8 +- les/odr_test.go | 2 +- les/server_handler.go | 3 +- les/server_requests.go | 5 +- les/test_helper.go | 5 +- light/lightchain_test.go | 5 +- light/odr_test.go | 3 +- light/postprocess.go | 4 +- light/trie.go | 6 +- light/trie_test.go | 2 +- light/txpool_test.go | 3 +- miner/miner_test.go | 5 +- tests/block_test.go | 16 +- tests/block_test_util.go | 29 +- tests/fuzzers/les/les-fuzzer.go | 4 +- tests/fuzzers/rangeproof/rangeproof-fuzzer.go | 2 +- tests/fuzzers/stacktrie/trie_fuzzer.go | 4 +- tests/fuzzers/trie/trie-fuzzer.go | 2 +- tests/state_test.go | 56 +- tests/state_test_util.go | 71 +- trie/database.go | 107 +-- trie/database_test.go | 2 +- trie/iterator_test.go | 113 ++- trie/proof_test.go | 20 +- trie/secure_trie_test.go | 4 +- trie/stacktrie_test.go | 12 +- trie/sync_test.go | 4 +- trie/tracer_test.go | 10 +- trie/trie_reader.go | 16 - trie/trie_test.go | 63 +- trie/triedb/hashdb/database.go | 33 +- trie/triedb/pathdb/database.go | 76 +- trie/triedb/pathdb/database_test.go | 5 +- trie/triedb/pathdb/difflayer_test.go | 2 +- trie/triedb/pathdb/disklayer.go | 20 +- trie/triedb/pathdb/history_test.go | 2 +- trie/triedb/pathdb/testutils.go | 4 +- trie/triestate/state.go | 17 +- 96 files changed, 1022 insertions(+), 2373 deletions(-) diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 0be5f69711..ffd3165f55 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -22,7 +22,6 @@ import ( "fmt" "os" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" @@ -65,7 +64,7 @@ func blockTestCmd(ctx *cli.Context) error { return err } for i, test := range tests { - if err := test.Run(false, rawdb.HashScheme, tracer); err != nil { + if err := test.Run(false, tracer); err != nil { return fmt.Errorf("test %v: %w", i, err) } } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index ac8432badb..ed7989e872 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -42,7 +42,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" "github.com/urfave/cli/v2" ) @@ -143,23 +142,12 @@ func runCmd(ctx *cli.Context) error { gen := readGenesis(ctx.String(GenesisFlag.Name)) genesisConfig = gen db := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(db, &trie.Config{ - Preimages: preimages, - HashDB: hashdb.Defaults, - }) - defer triedb.Close() - genesis := gen.MustCommit(db, triedb) - sdb := state.NewDatabaseWithNodeDB(db, triedb) + genesis := gen.MustCommit(db) + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages}) statedb, _ = state.New(genesis.Root(), sdb, nil) chainConfig = gen.Config } else { - db := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(db, &trie.Config{ - Preimages: preimages, - HashDB: hashdb.Defaults, - }) - defer triedb.Close() - sdb := state.NewDatabaseWithNodeDB(db, triedb) + sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) statedb, _ = state.New(types.EmptyRootHash, sdb, nil) genesisConfig = new(core.Genesis) } diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index a29c4b18f6..231830f6d7 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -23,9 +23,7 @@ import ( "os" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/log" @@ -106,22 +104,25 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { for _, st := range test.Subtests() { // Run the test and aggregate the result result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} - test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { - if err != nil { - // Test failed, mark as so and dump any state to aid debugging - result.Pass, result.Error = false, err.Error() - if dump { - dump := state.RawDump(nil) - result.State = &dump - } - } else { - root := state.IntermediateRoot(false) - result.Root = &root - if jsonOut { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) - } + _, s, err := test.Run(st, cfg, false) + // print state root for evmlab tracing + if s != nil { + root := s.IntermediateRoot(false) + result.Root = &root + if jsonOut { + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) } - }) + } + if err != nil { + // Test failed, mark as so and dump any state to aid debugging + result.Pass, result.Error = false, err.Error() + if dump && s != nil { + s, _ = state.New(*result.Root, s.Database(), nil) + dump := s.RawDump(nil) + result.State = &dump + } + } + results = append(results, *result) } } diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index fad2c71e68..41591ac138 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -39,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/trie" "github.com/urfave/cli/v2" ) @@ -48,10 +49,7 @@ var ( Name: "init", Usage: "Bootstrap and initialize a new genesis block", ArgsUsage: "", - Flags: flags.Merge([]cli.Flag{ - utils.CachePreimagesFlag, - utils.StateSchemeFlag, - }, utils.DatabasePathFlags), + Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags), Description: ` The init command initializes a new genesis block and definition for the network. This is a destructive action and changes the network in which you will be @@ -96,9 +94,6 @@ if one is set. Otherwise it prints the genesis from the datadir.`, utils.MetricsInfluxDBBucketFlag, utils.MetricsInfluxDBOrganizationFlag, utils.TxLookupLimitFlag, - utils.TransactionHistoryFlag, - utils.StateSchemeFlag, - utils.StateHistoryFlag, }, utils.DatabasePathFlags), Description: ` The import command imports blocks from an RLP-encoded form. The form can be one file @@ -115,7 +110,6 @@ processing will proceed even if an individual RLP-file import failure occurs.`, Flags: flags.Merge([]cli.Flag{ utils.CacheFlag, utils.SyncModeFlag, - utils.StateSchemeFlag, }, utils.DatabasePathFlags), Description: ` Requires a first argument of the file to write to. @@ -165,7 +159,6 @@ It's deprecated, please use "geth db export" instead. utils.IncludeIncompletesFlag, utils.StartKeyFlag, utils.DumpLimitFlag, - utils.StateSchemeFlag, }, utils.DatabasePathFlags), Description: ` This command dumps out the state for a given block (or latest, if none provided). @@ -202,15 +195,14 @@ func initGenesis(ctx *cli.Context) error { if err != nil { utils.Fatalf("Failed to open database: %v", err) } - defer chaindb.Close() - - triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false) - defer triedb.Close() - + triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{ + Preimages: ctx.Bool(utils.CachePreimagesFlag.Name), + }) _, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } + chaindb.Close() log.Info("Successfully wrote genesis state", "database", name, "hash", hash) } return nil @@ -249,7 +241,7 @@ func dumpGenesis(ctx *cli.Context) error { if ctx.IsSet(utils.DataDirFlag.Name) { utils.Fatalf("no existing datadir at %s", stack.Config().DataDir) } - utils.Fatalf("no network preset provided, no existing genesis in the default datadir") + utils.Fatalf("no network preset provided. no exisiting genesis in the default datadir") return nil } @@ -473,10 +465,10 @@ func dump(ctx *cli.Context) error { if err != nil { return err } - triedb := utils.MakeTrieDatabase(ctx, db, true, false) // always enable preimage lookup - defer triedb.Close() - - state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil) + config := &trie.Config{ + Preimages: true, // always enable preimage lookup + } + state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil) if err != nil { return err } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index a1868eb8c3..aa7939851d 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -151,7 +151,6 @@ WARNING: This is a low-level operation which may cause database corruption!`, ArgsUsage: " ", Flags: flags.Merge([]cli.Flag{ utils.SyncModeFlag, - utils.StateSchemeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: "This command looks up the specified database key from the database.", } @@ -483,9 +482,6 @@ func dbDumpTrie(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - triedb := utils.MakeTrieDatabase(ctx, db, false, true) - defer triedb.Close() - var ( state []byte storage []byte @@ -519,7 +515,7 @@ func dbDumpTrie(ctx *cli.Context) error { } } id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage)) - theTrie, err := trie.New(id, triedb) + theTrie, err := trie.New(id, trie.NewDatabase(db)) if err != nil { return err } diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index 2506b42d1e..ffe8176b01 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -176,12 +176,12 @@ func TestCustomBackend(t *testing.T) { { // Can't start pebble on top of leveldb initArgs: []string{"--db.engine", "leveldb"}, execArgs: []string{"--db.engine", "pebble"}, - execExpect: `Fatal: Could not open database: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`, + execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`, }, { // Can't start leveldb on top of pebble initArgs: []string{"--db.engine", "pebble"}, execArgs: []string{"--db.engine", "leveldb"}, - execExpect: `Fatal: Could not open database: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`, + execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`, }, { // Reject invalid backend choice initArgs: []string{"--db.engine", "mssql"}, diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f544dfe757..568aec4b8b 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -88,9 +88,6 @@ var ( utils.GCModeFlag, utils.SnapshotFlag, utils.TxLookupLimitFlag, - utils.TransactionHistoryFlag, - utils.StateSchemeFlag, - utils.StateHistoryFlag, utils.LightServeFlag, utils.LightIngressFlag, utils.LightEgressFlag, diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 5e1c784730..fafc827604 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -61,7 +61,10 @@ two version states are available: genesis and the specific one. The default pruning target is the HEAD-127 state. -WARNING: it's only supported in hash mode(--state.scheme=hash)". +WARNING: It's necessary to delete the trie clean cache after the pruning. +If you specify another directory for the trie clean cache via "--cache.trie.journal" +during the use of Geth, please also specify it here for correct deletion. Otherwise +the trie clean cache with default directory will be deleted. `, }, { @@ -69,9 +72,7 @@ WARNING: it's only supported in hash mode(--state.scheme=hash)". Usage: "Recalculate state hash based on the snapshot for verification", ArgsUsage: "", Action: verifyState, - Flags: flags.Merge([]cli.Flag{ - utils.StateSchemeFlag, - }, utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot verify-state will traverse the whole accounts and storages set based on the specified @@ -106,9 +107,7 @@ information about the specified address. Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", Action: traverseState, - Flags: flags.Merge([]cli.Flag{ - utils.StateSchemeFlag, - }, utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-state will traverse the whole state from the given state root and will abort if any @@ -123,9 +122,7 @@ It's also usable without snapshot enabled. Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", Action: traverseRawState, - Flags: flags.Merge([]cli.Flag{ - utils.StateSchemeFlag, - }, utils.NetworkFlags, utils.DatabasePathFlags), + Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags), Description: ` geth snapshot traverse-rawstate will traverse the whole state from the given root and will abort if any referenced @@ -146,7 +143,6 @@ It's also usable without snapshot enabled. utils.ExcludeStorageFlag, utils.StartKeyFlag, utils.DumpLimitFlag, - utils.StateSchemeFlag, }, utils.NetworkFlags, utils.DatabasePathFlags), Description: ` This command is semantically equivalent to 'geth dump', but uses the snapshots @@ -169,9 +165,6 @@ func pruneState(ctx *cli.Context) error { chaindb := utils.MakeChainDatabase(ctx, stack, false) defer chaindb.Close() - if rawdb.ReadStateScheme(chaindb) != rawdb.HashScheme { - log.Crit("Offline pruning is not required for path scheme") - } prunerconfig := pruner.Config{ Datadir: stack.ResolvePath(""), BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name), @@ -212,16 +205,13 @@ func verifyState(ctx *cli.Context) error { log.Error("Failed to load head block") return errors.New("no head block") } - triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) - defer triedb.Close() - - snapConfig := snapshot.Config{ + snapconfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapConfig, chaindb, triedb, headBlock.Root()) + snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root()) if err != nil { log.Error("Failed to open snapshot tree", "err", err) return err @@ -263,11 +253,6 @@ func traverseState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, true) - defer chaindb.Close() - - triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) - defer triedb.Close() - headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -292,6 +277,7 @@ func traverseState(ctx *cli.Context) error { root = headBlock.Root() log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } + triedb := trie.NewDatabase(chaindb) t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) @@ -367,11 +353,6 @@ func traverseRawState(ctx *cli.Context) error { defer stack.Close() chaindb := utils.MakeChainDatabase(ctx, stack, true) - defer chaindb.Close() - - triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true) - defer triedb.Close() - headBlock := rawdb.ReadHeadBlock(chaindb) if headBlock == nil { log.Error("Failed to load head block") @@ -396,6 +377,7 @@ func traverseRawState(ctx *cli.Context) error { root = headBlock.Root() log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64()) } + triedb := trie.NewDatabase(chaindb) t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb) if err != nil { log.Error("Failed to open trie", "root", root, "err", err) @@ -416,11 +398,6 @@ func traverseRawState(ctx *cli.Context) error { log.Error("Failed to open iterator", "root", root, "err", err) return err } - reader, err := triedb.Reader(root) - if err != nil { - log.Error("State is non-existent", "root", root) - return nil - } for accIter.Next(true) { nodes += 1 node := accIter.Hash() @@ -428,7 +405,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob, _ := reader.Node(common.Hash{}, accIter.Path(), node) + blob := rawdb.ReadLegacyTrieNode(chaindb, node) if len(blob) == 0 { log.Error("Missing trie node(account)", "hash", node) return errors.New("missing account") @@ -469,7 +446,7 @@ func traverseRawState(ctx *cli.Context) error { // Check the presence for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - blob, _ := reader.Node(common.BytesToHash(accIter.LeafKey()), storageIter.Path(), node) + blob := rawdb.ReadLegacyTrieNode(chaindb, node) if len(blob) == 0 { log.Error("Missing trie node(storage)", "hash", node) return errors.New("missing storage") @@ -529,16 +506,13 @@ func dumpState(ctx *cli.Context) error { if err != nil { return err } - triedb := utils.MakeTrieDatabase(ctx, db, false, true) - defer triedb.Close() - snapConfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapConfig, db, triedb, root) + snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db), root) if err != nil { return err } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3f1d0c0971..e0c7a42670 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -48,7 +48,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/catalyst" + ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/filters" @@ -74,9 +74,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" pcsclite "github.com/gballet/go-libpcsclite" gopsutil "github.com/shirou/gopsutil/mem" "github.com/urfave/cli/v2" @@ -221,12 +218,30 @@ var ( } defaultSyncMode = ethconfig.Defaults.SyncMode - SnapshotFlag = &cli.BoolFlag{ + SyncModeFlag = &flags.TextMarshalerFlag{ + Name: "syncmode", + Usage: `Blockchain sync mode ("snap", "full" or "light")`, + Value: &defaultSyncMode, + Category: flags.EthCategory, + } + GCModeFlag = &cli.StringFlag{ + Name: "gcmode", + Usage: `Blockchain garbage collection mode ("full", "archive")`, + Value: "full", + Category: flags.EthCategory, + } + SnapshotFlag = &cli.BoolFlag{ Name: "snapshot", Usage: `Enables snapshot-database mode (default = enable)`, Value: true, Category: flags.EthCategory, } + TxLookupLimitFlag = &cli.Uint64Flag{ + Name: "txlookuplimit", + Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", + Value: ethconfig.Defaults.TxLookupLimit, + Category: flags.EthCategory, + } LightKDFFlag = &cli.BoolFlag{ Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", @@ -253,36 +268,6 @@ var ( Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", Category: flags.EthCategory, } - SyncModeFlag = &flags.TextMarshalerFlag{ - Name: "syncmode", - Usage: `Blockchain sync mode ("snap", "full" or "light")`, - Value: &defaultSyncMode, - Category: flags.StateCategory, - } - GCModeFlag = &cli.StringFlag{ - Name: "gcmode", - Usage: `Blockchain garbage collection mode, only relevant in state.scheme=hash ("full", "archive")`, - Value: "full", - Category: flags.StateCategory, - } - StateSchemeFlag = &cli.StringFlag{ - Name: "state.scheme", - Usage: "Scheme to use for storing ethereum state ('hash' or 'path')", - Value: rawdb.HashScheme, - Category: flags.StateCategory, - } - StateHistoryFlag = &cli.Uint64Flag{ - Name: "history.state", - Usage: "Number of recent blocks to retain state history for (default = 90,000 blocks, 0 = entire chain)", - Value: ethconfig.Defaults.StateHistory, - Category: flags.StateCategory, - } - TransactionHistoryFlag = &cli.Uint64Flag{ - Name: "history.transactions", - Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", - Value: ethconfig.Defaults.TransactionHistory, - Category: flags.StateCategory, - } // Light server and client settings LightServeFlag = &cli.IntFlag{ Name: "light.serve", @@ -1639,8 +1624,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { CheckExclusive(ctx, MainnetFlag, DeveloperFlag, GoerliFlag, SepoliaFlag) CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer - - // Set configurations from CLI flags + if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { + ctx.Set(TxLookupLimitFlag.Name, "0") + log.Warn("Disable transaction unindexing for archive node") + } + if ctx.IsSet(LightServeFlag.Name) && ctx.Uint64(TxLookupLimitFlag.Name) != 0 { + log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") + } setEtherbase(ctx, cfg) setGPO(ctx, &cfg.GPO, ctx.String(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) @@ -1697,36 +1687,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.Preimages = true log.Info("Enabling recording of key preimages since archive mode is used") } - if ctx.IsSet(StateHistoryFlag.Name) { - cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name) - } - // Parse state scheme, abort the process if it's not compatible. - chaindb := tryMakeReadOnlyDatabase(ctx, stack) - scheme, err := ParseStateScheme(ctx, chaindb) - chaindb.Close() - if err != nil { - Fatalf("%v", err) - } - cfg.StateScheme = scheme - - // Parse transaction history flag, if user is still using legacy config - // file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'. - if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit { - log.Warn("The config option 'TxLookupLimit' is deprecated and will be removed, please use 'TransactionHistory'") - cfg.TransactionHistory = cfg.TxLookupLimit - } - if ctx.IsSet(TransactionHistoryFlag.Name) { - cfg.TransactionHistory = ctx.Uint64(TransactionHistoryFlag.Name) - } else if ctx.IsSet(TxLookupLimitFlag.Name) { - log.Warn("The flag --txlookuplimit is deprecated and will be removed, please use --history.transactions") - cfg.TransactionHistory = ctx.Uint64(TransactionHistoryFlag.Name) - } - if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 { - cfg.TransactionHistory = 0 - log.Warn("Disabled transaction unindexing for archive node") - } - if ctx.IsSet(LightServeFlag.Name) && cfg.TransactionHistory != 0 { - log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") + if ctx.IsSet(TxLookupLimitFlag.Name) { + cfg.TxLookupLimit = ctx.Uint64(TxLookupLimitFlag.Name) } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 @@ -1852,7 +1814,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Create a new developer genesis block or reuse existing one cfg.Genesis = core.DeveloperGenesisBlock(ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address) if ctx.IsSet(DataDirFlag.Name) { - chaindb := tryMakeReadOnlyDatabase(ctx, stack) + // If datadir doesn't exist we need to open db in write-mode + // so leveldb can create files. + readonly := true + if !common.FileExist(stack.ResolvePath("chaindata")) { + readonly = false + } + // Check if we have an already initialized chain and fall back to + // that if so. Otherwise we need to generate a new genesis spec. + chaindb := MakeChainDatabase(ctx, stack, readonly) if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { cfg.Genesis = nil // fallback to db content } @@ -1960,7 +1930,7 @@ func RegisterFullSyncTester(stack *node.Node, eth *eth.Ethereum, path string) { if err := rlp.DecodeBytes(rlpBlob, &block); err != nil { Fatalf("Failed to decode block: %v", err) } - catalyst.RegisterFullSyncTester(stack, eth, &block) + ethcatalyst.RegisterFullSyncTester(stack, eth, &block) log.Info("Registered full-sync tester", "number", block.NumberU64(), "hash", block.Hash()) } @@ -2070,18 +2040,6 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. return chainDb } -// tryMakeReadOnlyDatabase try to open the chain database in read-only mode, -// or fallback to write mode if the database is not initialized. -func tryMakeReadOnlyDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { - // If datadir doesn't exist we need to open db in write-mode - // so database engine can create files. - readonly := true - if !common.FileExist(stack.ResolvePath("chaindata")) { - readonly = false - } - return MakeChainDatabase(ctx, stack, readonly) -} - func IsNetworkPreset(ctx *cli.Context) bool { for _, flag := range NetworkFlags { bFlag, _ := flag.(*cli.BoolFlag) @@ -2148,10 +2106,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } - scheme, err := ParseStateScheme(ctx, chainDb) - if err != nil { - Fatalf("%v", err) - } cache := &core.CacheConfig{ TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), @@ -2160,8 +2114,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh TrieTimeLimit: ethconfig.Defaults.TrieTimeout, SnapshotLimit: ethconfig.Defaults.SnapshotCache, Preimages: ctx.Bool(CachePreimagesFlag.Name), - StateScheme: scheme, - StateHistory: ctx.Uint64(StateHistoryFlag.Name), } if cache.TrieDirtyDisabled && !cache.Preimages { cache.Preimages = true @@ -2206,62 +2158,3 @@ func MakeConsolePreloads(ctx *cli.Context) []string { } return preloads } - -// ParseStateScheme resolves scheme identifier from CLI flag. If the provided -// state scheme is not compatible with the one of persistent scheme, an error -// will be returned. -// -// - none: use the scheme consistent with persistent state, or fallback -// to hash-based scheme if state is empty. -// - hash: use hash-based scheme or error out if not compatible with -// persistent state scheme. -// - path: use path-based scheme or error out if not compatible with -// persistent state scheme. -func ParseStateScheme(ctx *cli.Context, disk ethdb.Database) (string, error) { - // If state scheme is not specified, use the scheme consistent - // with persistent state, or fallback to hash mode if database - // is empty. - stored := rawdb.ReadStateScheme(disk) - if !ctx.IsSet(StateSchemeFlag.Name) { - if stored == "" { - // use default scheme for empty database, flip it when - // path mode is chosen as default - log.Info("State schema set to default", "scheme", "hash") - return rawdb.HashScheme, nil - } - log.Info("State scheme set to already existing", "scheme", stored) - return stored, nil // reuse scheme of persistent scheme - } - // If state scheme is specified, ensure it's compatible with - // persistent state. - scheme := ctx.String(StateSchemeFlag.Name) - if stored == "" || scheme == stored { - log.Info("State scheme set by user", "scheme", scheme) - return scheme, nil - } - return "", fmt.Errorf("incompatible state scheme, stored: %s, provided: %s", stored, scheme) -} - -// MakeTrieDatabase constructs a trie database based on the configured scheme. -func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database { - config := &trie.Config{ - Preimages: preimage, - } - scheme, err := ParseStateScheme(ctx, disk) - if err != nil { - Fatalf("%v", err) - } - if scheme == rawdb.HashScheme { - // Read-only mode is not implemented in hash mode, - // ignore the parameter silently. TODO(rjl493456442) - // please config it if read mode is implemented. - config.HashDB = hashdb.Defaults - return trie.NewDatabase(disk, config) - } - if readOnly { - config.PathDB = pathdb.ReadOnly - } else { - config.PathDB = pathdb.Defaults - } - return trie.NewDatabase(disk, config) -} diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 6669ff176f..cf51b51936 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -19,7 +19,6 @@ package utils import ( "fmt" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2" ) @@ -38,7 +37,6 @@ var DeprecatedFlags = []cli.Flag{ CacheTrieJournalFlag, CacheTrieRejournalFlag, LegacyDiscoveryV5Flag, - TxLookupLimitFlag, } var ( @@ -70,13 +68,6 @@ var ( Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism (deprecated, use --discv5 instead)", Category: flags.DeprecatedCategory, } - // Deprecated August 2023 - TxLookupLimitFlag = &cli.Uint64Flag{ - Name: "txlookuplimit", - Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain) (deprecated, use history.transactions instead)", - Value: ethconfig.Defaults.TransactionHistory, - Category: flags.DeprecatedCategory, - } ) // showDeprecated displays deprecated flags that will be soon removed from the codebase. diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 48bdceff62..460eaad21c 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -35,11 +35,6 @@ import ( // Tests that simple header verification works, for both good and bad blocks. func TestHeaderVerification(t *testing.T) { - testHeaderVerification(t, rawdb.HashScheme) - testHeaderVerification(t, rawdb.PathScheme) -} - -func testHeaderVerification(t *testing.T, scheme string) { // Create a simple chain to verify var ( gspec = &Genesis{Config: params.TestChainConfig} @@ -50,7 +45,7 @@ func testHeaderVerification(t *testing.T, scheme string) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { diff --git a/core/blockchain.go b/core/blockchain.go index 65bcbbacc9..3952c31b68 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -48,8 +48,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "golang.org/x/exp/slices" ) @@ -130,7 +128,7 @@ const ( ) // CacheConfig contains the configuration values for the trie database -// and state snapshot these are resident in a blockchain. +// that's resident in a blockchain. type CacheConfig struct { TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory TrieCleanNoPrefetch bool // Whether to disable heuristic state prefetching for followup blocks @@ -139,31 +137,11 @@ type CacheConfig struct { TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory Preimages bool // Whether to store preimage of trie key to the disk - StateHistory uint64 // Number of blocks from head whose state histories are reserved. - StateScheme string // Scheme used to store ethereum states and merkle tree nodes on top SnapshotNoBuild bool // Whether the background generation is allowed SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } -// triedbConfig derives the configures for trie database. -func (c *CacheConfig) triedbConfig() *trie.Config { - config := &trie.Config{Preimages: c.Preimages} - if c.StateScheme == rawdb.HashScheme { - config.HashDB = &hashdb.Config{ - CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, - } - } - if c.StateScheme == rawdb.PathScheme { - config.PathDB = &pathdb.Config{ - StateHistory: c.StateHistory, - CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, - DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024, - } - } - return config -} - // defaultCacheConfig are the default caching values if none are specified by the // user (also used during testing). var defaultCacheConfig = &CacheConfig{ @@ -172,15 +150,6 @@ var defaultCacheConfig = &CacheConfig{ TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: true, - StateScheme: rawdb.HashScheme, -} - -// DefaultCacheConfigWithScheme returns a deep copied default cache config with -// a provided trie node scheme. -func DefaultCacheConfigWithScheme(scheme string) *CacheConfig { - config := *defaultCacheConfig - config.StateScheme = scheme - return &config } // BlockChain represents the canonical chain given a database with a genesis @@ -266,8 +235,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } // Open trie database with provided config - triedb := trie.NewDatabase(db, cacheConfig.triedbConfig()) - + triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ + Cache: cacheConfig.TrieCleanLimit, + Preimages: cacheConfig.Preimages, + }) // Setup the genesis block, commit the provided genesis specification // to database if the genesis block is not present yet, or load the // stored one from database. @@ -641,25 +612,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha pivot := rawdb.ReadLastPivotNumber(bc.db) frozen, _ := bc.db.Ancients() - // resetState resets the persistent state to genesis if it's not available. - resetState := func() { - // Short circuit if the genesis state is already present. - if bc.HasState(bc.genesisBlock.Root()) { - return - } - // Reset the state database to empty for committing genesis state. - // Note, it should only happen in path-based scheme and Reset function - // is also only call-able in this mode. - if bc.triedb.Scheme() == rawdb.PathScheme { - if err := bc.triedb.Reset(types.EmptyRootHash); err != nil { - log.Crit("Failed to clean state", "err", err) // Shouldn't happen - } - } - // Write genesis state into database. - if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil { - log.Crit("Failed to commit genesis state", "err", err) - } - } updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) { // Rewind the blockchain, ensuring we don't end up with a stateless head // block. Note, depth equality is permitted to allow using SetHead as a @@ -669,7 +621,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha if newHeadBlock == nil { log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash()) newHeadBlock = bc.genesisBlock - resetState() } else { // Block exists, keep rewinding until we find one with state, // keeping rewinding until we exceed the optional threshold @@ -681,7 +632,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha if root != (common.Hash{}) && !beyondRoot && newHeadBlock.Root() == root { beyondRoot, rootNumber = true, newHeadBlock.NumberU64() } - if !bc.HasState(newHeadBlock.Root()) && !bc.stateRecoverable(newHeadBlock.Root()) { + if !bc.HasState(newHeadBlock.Root()) { log.Trace("Block state missing, rewinding further", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) if pivot == nil || newHeadBlock.NumberU64() > *pivot { parent := bc.GetBlock(newHeadBlock.ParentHash(), newHeadBlock.NumberU64()-1) @@ -698,12 +649,16 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha } if beyondRoot || newHeadBlock.NumberU64() == 0 { if newHeadBlock.NumberU64() == 0 { - resetState() - } else if !bc.HasState(newHeadBlock.Root()) { - // Rewind to a block with recoverable state. If the state is - // missing, run the state recovery here. - if err := bc.triedb.Recover(newHeadBlock.Root()); err != nil { - log.Crit("Failed to rollback state", "err", err) // Shouldn't happen + // Recommit the genesis state into disk in case the rewinding destination + // is genesis block and the relevant state is gone. In the future this + // rewinding destination can be the earliest block stored in the chain + // if the historical chain pruning is enabled. In that case the logic + // needs to be improved here. + if !bc.HasState(bc.genesisBlock.Root()) { + if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil { + log.Crit("Failed to commit genesis state", "err", err) + } + log.Debug("Recommitted genesis state to disk") } } log.Debug("Rewound to block with state", "number", newHeadBlock.NumberU64(), "hash", newHeadBlock.Hash()) @@ -817,13 +772,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { if block == nil { return fmt.Errorf("non existent block [%x..]", hash[:4]) } - // Reset the trie database with the fresh snap synced state. root := block.Root() - if bc.triedb.Scheme() == rawdb.PathScheme { - if err := bc.triedb.Reset(root); err != nil { - return err - } - } if !bc.HasState(root) { return fmt.Errorf("non existent state [%x..]", root[:4]) } @@ -988,47 +937,41 @@ func (bc *BlockChain) Stop() { log.Error("Failed to journal state snapshot", "err", err) } } - if bc.triedb.Scheme() == rawdb.PathScheme { - // Ensure that the in-memory trie nodes are journaled to disk properly. - if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil { - log.Info("Failed to journal in-memory trie nodes", "err", err) - } - } else { - // Ensure the state of a recent block is also stored to disk before exiting. - // We're writing three different states to catch different restart scenarios: - // - HEAD: So we don't need to reprocess any blocks in the general case - // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle - // - HEAD-127: So we have a hard limit on the number of blocks reexecuted - if !bc.cacheConfig.TrieDirtyDisabled { - triedb := bc.triedb - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { - if number := bc.CurrentBlock().Number.Uint64(); number > offset { - recent := bc.GetBlockByNumber(number - offset) + // Ensure the state of a recent block is also stored to disk before exiting. + // We're writing three different states to catch different restart scenarios: + // - HEAD: So we don't need to reprocess any blocks in the general case + // - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle + // - HEAD-127: So we have a hard limit on the number of blocks reexecuted + if !bc.cacheConfig.TrieDirtyDisabled { + triedb := bc.triedb - log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) - if err := triedb.Commit(recent.Root(), true); err != nil { - log.Error("Failed to commit recent state trie", "err", err) - } - } - } - if snapBase != (common.Hash{}) { - log.Info("Writing snapshot state to disk", "root", snapBase) - if err := triedb.Commit(snapBase, true); err != nil { + for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + if number := bc.CurrentBlock().Number.Uint64(); number > offset { + recent := bc.GetBlockByNumber(number - offset) + + log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root()) + if err := triedb.Commit(recent.Root(), true); err != nil { log.Error("Failed to commit recent state trie", "err", err) } } - for !bc.triegc.Empty() { - triedb.Dereference(bc.triegc.PopItem()) - } - if size, _ := triedb.Size(); size != 0 { - log.Error("Dangling trie nodes after full cleanup") + } + if snapBase != (common.Hash{}) { + log.Info("Writing snapshot state to disk", "root", snapBase) + if err := triedb.Commit(snapBase, true); err != nil { + log.Error("Failed to commit recent state trie", "err", err) } } + for !bc.triegc.Empty() { + triedb.Dereference(bc.triegc.PopItem()) + } + if size, _ := triedb.Size(); size != 0 { + log.Error("Dangling trie nodes after full cleanup") + } } - // Close the trie database, release all the held resources as the last step. - if err := bc.triedb.Close(); err != nil { - log.Error("Failed to close trie database", "err", err) + // Flush the collected preimages to disk + if err := bc.stateCache.TrieDB().Close(); err != nil { + log.Error("Failed to close trie db", "err", err) } log.Info("Blockchain stopped") } @@ -1398,11 +1341,6 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. if err != nil { return err } - // If node is running in path mode, skip explicit gc operation - // which is unnecessary in this mode. - if bc.triedb.Scheme() == rawdb.PathScheme { - return nil - } // If we're running an archive node, always flush if bc.cacheConfig.TrieDirtyDisabled { return bc.triedb.Commit(root, false) @@ -1411,8 +1349,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) - // Flush limits are not considered for the first TriesInMemory blocks. current := block.NumberU64() + // Flush limits are not considered for the first TriesInMemory blocks. if current <= TriesInMemory { return nil } @@ -1998,12 +1936,6 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i ) parent := it.previous() for parent != nil && !bc.HasState(parent.Root) { - if bc.stateRecoverable(parent.Root) { - if err := bc.triedb.Recover(parent.Root); err != nil { - return 0, err - } - break - } hashes = append(hashes, parent.Hash()) numbers = append(numbers, parent.Number.Uint64()) @@ -2060,12 +1992,6 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error) parent = block ) for parent != nil && !bc.HasState(parent.Root()) { - if bc.stateRecoverable(parent.Root()) { - if err := bc.triedb.Recover(parent.Root()); err != nil { - return common.Hash{}, err - } - break - } hashes = append(hashes, parent.Hash()) numbers = append(numbers, parent.NumberU64()) parent = bc.GetBlock(parent.ParentHash(), parent.NumberU64()-1) @@ -2467,7 +2393,6 @@ func (bc *BlockChain) maintainTxIndex() { return } defer sub.Unsubscribe() - log.Info("Initialized transaction indexer", "limit", bc.TxLookupLimit()) for { select { diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 466a86c144..f9d0e3531f 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -293,16 +293,10 @@ func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool { return bc.HasState(block.Root()) } -// stateRecoverable checks if the specified state is recoverable. -// Note, this function assumes the state is not present, because -// state is not treated as recoverable if it's available, thus -// false will be returned in this case. -func (bc *BlockChain) stateRecoverable(root common.Hash) bool { - if bc.triedb.Scheme() == rawdb.HashScheme { - return false - } - result, _ := bc.triedb.Recoverable(root) - return result +// TrieNode retrieves a blob of data associated with a trie node +// either from ephemeral in-memory cache, or from persistent storage. +func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) { + return bc.stateCache.TrieDB().Node(hash) } // ContractCodeWithPrefix retrieves a blob of data associated with a contract diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 7080e23f8f..6a4a9c9d22 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -22,7 +22,6 @@ package core import ( "math/big" - "path" "testing" "time" @@ -1750,23 +1749,16 @@ func testLongReorgedSnapSyncingDeepRepair(t *testing.T, snapshots bool) { } func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - testRepairWithScheme(t, tt, snapshots, scheme) - } -} - -func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { // It's hard to follow the test case, visualize the input //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // fmt.Println(tt.dump(true)) // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -1785,7 +1777,6 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot by default - StateScheme: scheme, } ) defer engine.Close() @@ -1815,9 +1806,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - if err := chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false); err != nil { - t.Fatalf("Failed to flush trie state: %v", err) - } + chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) @@ -1839,21 +1828,21 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s rawdb.WriteLastPivotNumber(db, *tt.pivotBlock) } // Pull the plug on the database, simulating a hard crash - chain.triedb.Close() db.Close() chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) + if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } defer db.Close() - newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) + newChain, err := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1896,22 +1885,17 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s // In this case the snapshot layer of B3 is not created because of existent // state. func TestIssue23496(t *testing.T) { - testIssue23496(t, rawdb.HashScheme) - testIssue23496(t, rawdb.PathScheme) -} - -func testIssue23496(t *testing.T, scheme string) { // It's hard to follow the test case, visualize the input //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) + if err != nil { t.Fatalf("Failed to create persistent database: %v", err) } @@ -1924,8 +1908,15 @@ func testIssue23496(t *testing.T, scheme string) { BaseFee: big.NewInt(params.InitialBaseFee), } engine = ethash.NewFullFaker() + config = &CacheConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 256, + SnapshotWait: true, + } ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1938,7 +1929,7 @@ func testIssue23496(t *testing.T, scheme string) { if _, err := chain.InsertChain(blocks[:1]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.triedb.Commit(blocks[0].Root(), false) + chain.stateCache.TrieDB().Commit(blocks[0].Root(), false) // Insert block B2 and commit the snapshot into disk if _, err := chain.InsertChain(blocks[1:2]); err != nil { @@ -1952,7 +1943,7 @@ func testIssue23496(t *testing.T, scheme string) { if _, err := chain.InsertChain(blocks[2:3]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } - chain.triedb.Commit(blocks[2].Root(), false) + chain.stateCache.TrieDB().Commit(blocks[2].Root(), false) // Insert the remaining blocks if _, err := chain.InsertChain(blocks[3:]); err != nil { @@ -1960,21 +1951,20 @@ func testIssue23496(t *testing.T, scheme string) { } // Pull the plug on the database, simulating a hard crash - chain.triedb.Close() db.Close() chain.stopWithoutSaving() // Start a new blockchain back up and see where the repair leads us db, err = rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } defer db.Close() - chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err = NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1986,12 +1976,8 @@ func testIssue23496(t *testing.T, scheme string) { if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) { t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4)) } - expHead := uint64(1) - if scheme == rawdb.PathScheme { - expHead = uint64(2) - } - if head := chain.CurrentBlock(); head.Number.Uint64() != expHead { - t.Errorf("Head block mismatch: have %d, want %d", head.Number, expHead) + if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(1) { + t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(1)) } // Reinsert B2-B4 diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index 7691936ce2..9dc350db84 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -22,7 +22,6 @@ package core import ( "fmt" "math/big" - "path" "strings" "testing" "time" @@ -30,13 +29,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // rewindTest is a test case for chain rollback upon user request. @@ -1954,23 +1949,16 @@ func testLongReorgedSnapSyncingDeepSetHead(t *testing.T, snapshots bool) { } func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - testSetHeadWithScheme(t, tt, snapshots, scheme) - } -} - -func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme string) { // It's hard to follow the test case, visualize the input // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) // fmt.Println(tt.dump(false)) // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -1989,7 +1977,6 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, // Disable snapshot - StateScheme: scheme, } ) if snapshots { @@ -2020,7 +2007,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - chain.triedb.Commit(canonblocks[tt.commitBlock-1].Root(), false) + chain.stateCache.TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), false) if snapshots { if err := chain.snaps.Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) @@ -2030,17 +2017,13 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil { t.Fatalf("Failed to import canonical chain tail: %v", err) } - // Reopen the trie database without persisting in-memory dirty nodes. - chain.triedb.Close() - dbconfig := &trie.Config{} - if scheme == rawdb.PathScheme { - dbconfig.PathDB = pathdb.Defaults - } else { - dbconfig.HashDB = hashdb.Defaults + // Manually dereference anything not committed to not have to work with 128+ tries + for _, block := range sideblocks { + chain.stateCache.TrieDB().Dereference(block.Root()) + } + for _, block := range canonblocks { + chain.stateCache.TrieDB().Dereference(block.Root()) } - chain.triedb = trie.NewDatabase(chain.db, dbconfig) - chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb) - // Force run a freeze cycle type freezer interface { Freeze(threshold uint64) error diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index cdbd9d24fe..3bd876a58e 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -24,7 +24,6 @@ import ( "fmt" "math/big" "os" - "path" "strings" "testing" "time" @@ -40,7 +39,6 @@ import ( // snapshotTestBasic wraps the common testing fields in the snapshot tests. type snapshotTestBasic struct { - scheme string // Disk scheme used for storing trie nodes chainBlocks int // Number of blocks to generate for the canonical chain snapshotBlock uint64 // Block number of the relevant snapshot disk layer commitBlock uint64 // Block number for which to commit the state to disk @@ -53,7 +51,6 @@ type snapshotTestBasic struct { // share fields, set in runtime datadir string - ancient string db ethdb.Database genDb ethdb.Database engine consensus.Engine @@ -63,11 +60,10 @@ type snapshotTestBasic struct { func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) { // Create a temporary persistent database datadir := t.TempDir() - ancient := path.Join(datadir, "ancient") db, err := rawdb.Open(rawdb.OpenOptions{ Directory: datadir, - AncientsDirectory: ancient, + AncientsDirectory: datadir, }) if err != nil { t.Fatalf("Failed to create persistent database: %v", err) @@ -79,8 +75,13 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo Config: params.AllEthashProtocolChanges, } engine = ethash.NewFullFaker() + + // Snapshot is enabled, the first snapshot is created from the Genesis. + // The snapshot memory allowance is 256MB, it means no snapshot flush + // will happen during the block insertion. + cacheConfig = defaultCacheConfig ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -101,7 +102,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo startPoint = point if basic.commitBlock > 0 && basic.commitBlock == point { - chain.TrieDB().Commit(blocks[point-1].Root(), false) + chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), false) } if basic.snapshotBlock > 0 && basic.snapshotBlock == point { // Flushing the entire snap tree into the disk, the @@ -120,7 +121,6 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo // Set runtime fields basic.datadir = datadir - basic.ancient = ancient basic.db = db basic.genDb = genDb basic.engine = engine @@ -210,7 +210,6 @@ func (basic *snapshotTestBasic) teardown() { basic.db.Close() basic.genDb.Close() os.RemoveAll(basic.datadir) - os.RemoveAll(basic.ancient) } // snapshotTest is a test case type for normal snapshot recovery. @@ -227,7 +226,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally chain.Stop() - newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -236,7 +235,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { snaptest.verify(t, newchain, blocks) } -// crashSnapshotTest is a test case type for irregular snapshot recovery. +// crashSnapshotTest is a test case type for innormal snapshot recovery. // It can be used for testing that restart Geth after the crash. type crashSnapshotTest struct { snapshotTestBasic @@ -252,13 +251,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { db := chain.db db.Close() chain.stopWithoutSaving() - chain.triedb.Close() // Start a new blockchain back up and see where the repair leads us newdb, err := rawdb.Open(rawdb.OpenOptions{ Directory: snaptest.datadir, - AncientsDirectory: snaptest.ancient, + AncientsDirectory: snaptest.datadir, }) + if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } @@ -268,13 +267,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { // the crash, we do restart twice here: one after the crash and one // after the normal stop. It's used to ensure the broken snapshot // can be detected all the time. - newchain, err := NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } newchain.Stop() - newchain, err = NewBlockChain(newdb, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -301,7 +300,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { // Insert blocks without enabling snapshot if gapping is required. chain.Stop() - gappedBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) + gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) // Insert a few more blocks without enabling snapshot var cacheConfig = &CacheConfig{ @@ -309,7 +308,6 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, - StateScheme: snaptest.scheme, } newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { @@ -319,7 +317,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain with enabling the snapshot - newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -347,7 +345,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) chain.Stop() - newchain, err := NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -381,24 +379,22 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, - StateScheme: snaptest.scheme, } newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } - newBlocks, _ := GenerateChain(snaptest.gspec.Config, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) + newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) newchain.InsertChain(newBlocks) newchain.Stop() - // Restart the chain, the wiper should start working + // Restart the chain, the wiper should starts working config = &CacheConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild - StateScheme: snaptest.scheme, } tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { @@ -406,15 +402,14 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { } // Simulate the blockchain crash. - tmp.triedb.Close() tmp.stopWithoutSaving() - newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } + defer newchain.Stop() snaptest.verify(t, newchain, blocks) - newchain.Stop() } // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot @@ -438,23 +433,20 @@ func TestRestartWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : C8 // Expected snapshot disk : G - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &snapshotTest{ - snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 8, - expSnapshotBottom: 0, // Initial disk layer built from genesis - }, - } - test.test(t) - test.teardown() + test := &snapshotTest{ + snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 8, + expSnapshotBottom: 0, // Initial disk layer built from genesis + }, } + test.test(t) + test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case the @@ -480,23 +472,20 @@ func TestNoCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : G // Expected snapshot disk : C4 - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &crashSnapshotTest{ - snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 0, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 0, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, - } - test.test(t) - test.teardown() + test := &crashSnapshotTest{ + snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 0, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 0, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, } + test.test(t) + test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case the @@ -522,23 +511,20 @@ func TestLowCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : C2 // Expected snapshot disk : C4 - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &crashSnapshotTest{ - snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 2, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: 2, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, - } - test.test(t) - test.teardown() + test := &crashSnapshotTest{ + snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 2, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 2, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, } + test.test(t) + test.teardown() } // Tests a Geth was crashed and restarts with a broken snapshot. In this case @@ -564,27 +550,20 @@ func TestHighCommitCrashWithNewSnapshot(t *testing.T) { // Expected head fast block: C8 // Expected head block : G // Expected snapshot disk : C4 - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - expHead := uint64(0) - if scheme == rawdb.PathScheme { - expHead = uint64(4) - } - test := &crashSnapshotTest{ - snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 6, - expCanonicalBlocks: 8, - expHeadHeader: 8, - expHeadFastBlock: 8, - expHeadBlock: expHead, - expSnapshotBottom: 4, // Last committed disk layer, wait recovery - }, - } - test.test(t) - test.teardown() + test := &crashSnapshotTest{ + snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 6, + expCanonicalBlocks: 8, + expHeadHeader: 8, + expHeadFastBlock: 8, + expHeadBlock: 0, + expSnapshotBottom: 4, // Last committed disk layer, wait recovery + }, } + test.test(t) + test.teardown() } // Tests a Geth was running with snapshot enabled. Then restarts without @@ -608,24 +587,21 @@ func TestGappedNewSnapshot(t *testing.T) { // Expected head fast block: C10 // Expected head block : C10 // Expected snapshot disk : C10 - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &gappedSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 10, - expHeadHeader: 10, - expHeadFastBlock: 10, - expHeadBlock: 10, - expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD - }, - gapped: 2, - } - test.test(t) - test.teardown() + test := &gappedSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 10, + expHeadHeader: 10, + expHeadFastBlock: 10, + expHeadBlock: 10, + expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD + }, + gapped: 2, } + test.test(t) + test.teardown() } // Tests the Geth was running with snapshot enabled and resetHead is applied. @@ -649,24 +625,21 @@ func TestSetHeadWithNewSnapshot(t *testing.T) { // Expected head fast block: C4 // Expected head block : C4 // Expected snapshot disk : G - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &setHeadSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 0, - commitBlock: 0, - expCanonicalBlocks: 4, - expHeadHeader: 4, - expHeadFastBlock: 4, - expHeadBlock: 4, - expSnapshotBottom: 0, // The initial disk layer is built from the genesis - }, - setHead: 4, - } - test.test(t) - test.teardown() + test := &setHeadSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 0, + commitBlock: 0, + expCanonicalBlocks: 4, + expHeadHeader: 4, + expHeadFastBlock: 4, + expHeadBlock: 4, + expSnapshotBottom: 0, // The initial disk layer is built from the genesis + }, + setHead: 4, } + test.test(t) + test.teardown() } // Tests the Geth was running with a complete snapshot and then imports a few @@ -690,22 +663,19 @@ func TestRecoverSnapshotFromWipingCrash(t *testing.T) { // Expected head fast block: C10 // Expected head block : C8 // Expected snapshot disk : C10 - for _, scheme := range []string{rawdb.HashScheme, rawdb.PathScheme} { - test := &wipeCrashSnapshotTest{ - snapshotTestBasic: snapshotTestBasic{ - scheme: scheme, - chainBlocks: 8, - snapshotBlock: 4, - commitBlock: 0, - expCanonicalBlocks: 10, - expHeadHeader: 10, - expHeadFastBlock: 10, - expHeadBlock: 10, - expSnapshotBottom: 10, - }, - newBlocks: 2, - } - test.test(t) - test.teardown() + test := &wipeCrashSnapshotTest{ + snapshotTestBasic: snapshotTestBasic{ + chainBlocks: 8, + snapshotBlock: 4, + commitBlock: 0, + expCanonicalBlocks: 10, + expHeadHeader: 10, + expHeadFastBlock: 10, + expHeadBlock: 10, + expSnapshotBottom: 10, + }, + newBlocks: 2, } + test.test(t) + test.teardown() } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index a365cb5ed5..1b4b569575 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -52,7 +52,7 @@ var ( // chain. Depending on the full flag, if creates either a full block chain or a // header only chain. The database and genesis specification for block generation // are also returned in case more test blocks are needed later. -func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (ethdb.Database, *Genesis, *BlockChain, error) { +func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *Genesis, *BlockChain, error) { var ( genesis = &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), @@ -60,7 +60,7 @@ func newCanonical(engine consensus.Engine, n int, full bool, scheme string) (eth } ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) // Create and inject the requested chain if n == 0 { @@ -83,9 +83,9 @@ func newGwei(n int64) *big.Int { } // Test fork of length N starting from block i -func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int), scheme string) { +func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { // Copy old chain up to #i into a new db - genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full, scheme) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -198,13 +198,9 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error } return nil } -func TestLastBlock(t *testing.T) { - testLastBlock(t, rawdb.HashScheme) - testLastBlock(t, rawdb.PathScheme) -} -func testLastBlock(t *testing.T, scheme string) { - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, scheme) +func TestLastBlock(t *testing.T) { + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -221,9 +217,9 @@ func testLastBlock(t *testing.T, scheme string) { // Test inserts the blocks/headers after the fork choice rule is changed. // The chain is reorged to whatever specified. -func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full bool, scheme string) { +func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full bool) { // Copy old chain up to #i into a new db - genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full, scheme) + genDb, _, blockchain2, err := newCanonical(ethash.NewFaker(), i, full) if err != nil { t.Fatal("could not make new canonical in testFork", err) } @@ -270,20 +266,14 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b // Tests that given a starting canonical chain of a given size, it can be extended // with various length chains. -func TestExtendCanonicalHeaders(t *testing.T) { - testExtendCanonical(t, false, rawdb.HashScheme) - testExtendCanonical(t, false, rawdb.PathScheme) -} -func TestExtendCanonicalBlocks(t *testing.T) { - testExtendCanonical(t, true, rawdb.HashScheme) - testExtendCanonical(t, true, rawdb.PathScheme) -} +func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) } +func TestExtendCanonicalBlocks(t *testing.T) { testExtendCanonical(t, true) } -func testExtendCanonical(t *testing.T, full bool, scheme string) { +func testExtendCanonical(t *testing.T, full bool) { length := 5 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -296,53 +286,41 @@ func testExtendCanonical(t *testing.T, full bool, scheme string) { } } // Start fork from current height - testFork(t, processor, length, 1, full, better, scheme) - testFork(t, processor, length, 2, full, better, scheme) - testFork(t, processor, length, 5, full, better, scheme) - testFork(t, processor, length, 10, full, better, scheme) + testFork(t, processor, length, 1, full, better) + testFork(t, processor, length, 2, full, better) + testFork(t, processor, length, 5, full, better) + testFork(t, processor, length, 10, full, better) } // Tests that given a starting canonical chain of a given size, it can be extended // with various length chains. -func TestExtendCanonicalHeadersAfterMerge(t *testing.T) { - testExtendCanonicalAfterMerge(t, false, rawdb.HashScheme) - testExtendCanonicalAfterMerge(t, false, rawdb.PathScheme) -} -func TestExtendCanonicalBlocksAfterMerge(t *testing.T) { - testExtendCanonicalAfterMerge(t, true, rawdb.HashScheme) - testExtendCanonicalAfterMerge(t, true, rawdb.PathScheme) -} +func TestExtendCanonicalHeadersAfterMerge(t *testing.T) { testExtendCanonicalAfterMerge(t, false) } +func TestExtendCanonicalBlocksAfterMerge(t *testing.T) { testExtendCanonicalAfterMerge(t, true) } -func testExtendCanonicalAfterMerge(t *testing.T, full bool, scheme string) { +func testExtendCanonicalAfterMerge(t *testing.T, full bool) { length := 5 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, length, 1, full, scheme) - testInsertAfterMerge(t, processor, length, 10, full, scheme) + testInsertAfterMerge(t, processor, length, 1, full) + testInsertAfterMerge(t, processor, length, 10, full) } // Tests that given a starting canonical chain of a given size, creating shorter // forks do not take canonical ownership. -func TestShorterForkHeaders(t *testing.T) { - testShorterFork(t, false, rawdb.HashScheme) - testShorterFork(t, false, rawdb.PathScheme) -} -func TestShorterForkBlocks(t *testing.T) { - testShorterFork(t, true, rawdb.HashScheme) - testShorterFork(t, true, rawdb.PathScheme) -} +func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) } +func TestShorterForkBlocks(t *testing.T) { testShorterFork(t, true) } -func testShorterFork(t *testing.T, full bool, scheme string) { +func testShorterFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -355,117 +333,93 @@ func testShorterFork(t *testing.T, full bool, scheme string) { } } // Sum of numbers must be less than `length` for this to be a shorter fork - testFork(t, processor, 0, 3, full, worse, scheme) - testFork(t, processor, 0, 7, full, worse, scheme) - testFork(t, processor, 1, 1, full, worse, scheme) - testFork(t, processor, 1, 7, full, worse, scheme) - testFork(t, processor, 5, 3, full, worse, scheme) - testFork(t, processor, 5, 4, full, worse, scheme) + testFork(t, processor, 0, 3, full, worse) + testFork(t, processor, 0, 7, full, worse) + testFork(t, processor, 1, 1, full, worse) + testFork(t, processor, 1, 7, full, worse) + testFork(t, processor, 5, 3, full, worse) + testFork(t, processor, 5, 4, full, worse) } // Tests that given a starting canonical chain of a given size, creating shorter // forks do not take canonical ownership. -func TestShorterForkHeadersAfterMerge(t *testing.T) { - testShorterForkAfterMerge(t, false, rawdb.HashScheme) - testShorterForkAfterMerge(t, false, rawdb.PathScheme) -} -func TestShorterForkBlocksAfterMerge(t *testing.T) { - testShorterForkAfterMerge(t, true, rawdb.HashScheme) - testShorterForkAfterMerge(t, true, rawdb.PathScheme) -} +func TestShorterForkHeadersAfterMerge(t *testing.T) { testShorterForkAfterMerge(t, false) } +func TestShorterForkBlocksAfterMerge(t *testing.T) { testShorterForkAfterMerge(t, true) } -func testShorterForkAfterMerge(t *testing.T, full bool, scheme string) { +func testShorterForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 3, full, scheme) - testInsertAfterMerge(t, processor, 0, 7, full, scheme) - testInsertAfterMerge(t, processor, 1, 1, full, scheme) - testInsertAfterMerge(t, processor, 1, 7, full, scheme) - testInsertAfterMerge(t, processor, 5, 3, full, scheme) - testInsertAfterMerge(t, processor, 5, 4, full, scheme) + testInsertAfterMerge(t, processor, 0, 3, full) + testInsertAfterMerge(t, processor, 0, 7, full) + testInsertAfterMerge(t, processor, 1, 1, full) + testInsertAfterMerge(t, processor, 1, 7, full) + testInsertAfterMerge(t, processor, 5, 3, full) + testInsertAfterMerge(t, processor, 5, 4, full) } // Tests that given a starting canonical chain of a given size, creating longer // forks do take canonical ownership. -func TestLongerForkHeaders(t *testing.T) { - testLongerFork(t, false, rawdb.HashScheme) - testLongerFork(t, false, rawdb.PathScheme) -} -func TestLongerForkBlocks(t *testing.T) { - testLongerFork(t, true, rawdb.HashScheme) - testLongerFork(t, true, rawdb.PathScheme) -} +func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) } +func TestLongerForkBlocks(t *testing.T) { testLongerFork(t, true) } -func testLongerFork(t *testing.T, full bool, scheme string) { +func testLongerFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 11, full, scheme) - testInsertAfterMerge(t, processor, 0, 15, full, scheme) - testInsertAfterMerge(t, processor, 1, 10, full, scheme) - testInsertAfterMerge(t, processor, 1, 12, full, scheme) - testInsertAfterMerge(t, processor, 5, 6, full, scheme) - testInsertAfterMerge(t, processor, 5, 8, full, scheme) + testInsertAfterMerge(t, processor, 0, 11, full) + testInsertAfterMerge(t, processor, 0, 15, full) + testInsertAfterMerge(t, processor, 1, 10, full) + testInsertAfterMerge(t, processor, 1, 12, full) + testInsertAfterMerge(t, processor, 5, 6, full) + testInsertAfterMerge(t, processor, 5, 8, full) } // Tests that given a starting canonical chain of a given size, creating longer // forks do take canonical ownership. -func TestLongerForkHeadersAfterMerge(t *testing.T) { - testLongerForkAfterMerge(t, false, rawdb.HashScheme) - testLongerForkAfterMerge(t, false, rawdb.PathScheme) -} -func TestLongerForkBlocksAfterMerge(t *testing.T) { - testLongerForkAfterMerge(t, true, rawdb.HashScheme) - testLongerForkAfterMerge(t, true, rawdb.PathScheme) -} +func TestLongerForkHeadersAfterMerge(t *testing.T) { testLongerForkAfterMerge(t, false) } +func TestLongerForkBlocksAfterMerge(t *testing.T) { testLongerForkAfterMerge(t, true) } -func testLongerForkAfterMerge(t *testing.T, full bool, scheme string) { +func testLongerForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 11, full, scheme) - testInsertAfterMerge(t, processor, 0, 15, full, scheme) - testInsertAfterMerge(t, processor, 1, 10, full, scheme) - testInsertAfterMerge(t, processor, 1, 12, full, scheme) - testInsertAfterMerge(t, processor, 5, 6, full, scheme) - testInsertAfterMerge(t, processor, 5, 8, full, scheme) + testInsertAfterMerge(t, processor, 0, 11, full) + testInsertAfterMerge(t, processor, 0, 15, full) + testInsertAfterMerge(t, processor, 1, 10, full) + testInsertAfterMerge(t, processor, 1, 12, full) + testInsertAfterMerge(t, processor, 5, 6, full) + testInsertAfterMerge(t, processor, 5, 8, full) } // Tests that given a starting canonical chain of a given size, creating equal // forks do take canonical ownership. -func TestEqualForkHeaders(t *testing.T) { - testEqualFork(t, false, rawdb.HashScheme) - testEqualFork(t, false, rawdb.PathScheme) -} -func TestEqualForkBlocks(t *testing.T) { - testEqualFork(t, true, rawdb.HashScheme) - testEqualFork(t, true, rawdb.PathScheme) -} +func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) } +func TestEqualForkBlocks(t *testing.T) { testEqualFork(t, true) } -func testEqualFork(t *testing.T, full bool, scheme string) { +func testEqualFork(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -478,56 +432,44 @@ func testEqualFork(t *testing.T, full bool, scheme string) { } } // Sum of numbers must be equal to `length` for this to be an equal fork - testFork(t, processor, 0, 10, full, equal, scheme) - testFork(t, processor, 1, 9, full, equal, scheme) - testFork(t, processor, 2, 8, full, equal, scheme) - testFork(t, processor, 5, 5, full, equal, scheme) - testFork(t, processor, 6, 4, full, equal, scheme) - testFork(t, processor, 9, 1, full, equal, scheme) + testFork(t, processor, 0, 10, full, equal) + testFork(t, processor, 1, 9, full, equal) + testFork(t, processor, 2, 8, full, equal) + testFork(t, processor, 5, 5, full, equal) + testFork(t, processor, 6, 4, full, equal) + testFork(t, processor, 9, 1, full, equal) } // Tests that given a starting canonical chain of a given size, creating equal // forks do take canonical ownership. -func TestEqualForkHeadersAfterMerge(t *testing.T) { - testEqualForkAfterMerge(t, false, rawdb.HashScheme) - testEqualForkAfterMerge(t, false, rawdb.PathScheme) -} -func TestEqualForkBlocksAfterMerge(t *testing.T) { - testEqualForkAfterMerge(t, true, rawdb.HashScheme) - testEqualForkAfterMerge(t, true, rawdb.PathScheme) -} +func TestEqualForkHeadersAfterMerge(t *testing.T) { testEqualForkAfterMerge(t, false) } +func TestEqualForkBlocksAfterMerge(t *testing.T) { testEqualForkAfterMerge(t, true) } -func testEqualForkAfterMerge(t *testing.T, full bool, scheme string) { +func testEqualForkAfterMerge(t *testing.T, full bool) { length := 10 // Make first chain starting from genesis - _, _, processor, err := newCanonical(ethash.NewFaker(), length, full, scheme) + _, _, processor, err := newCanonical(ethash.NewFaker(), length, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } defer processor.Stop() - testInsertAfterMerge(t, processor, 0, 10, full, scheme) - testInsertAfterMerge(t, processor, 1, 9, full, scheme) - testInsertAfterMerge(t, processor, 2, 8, full, scheme) - testInsertAfterMerge(t, processor, 5, 5, full, scheme) - testInsertAfterMerge(t, processor, 6, 4, full, scheme) - testInsertAfterMerge(t, processor, 9, 1, full, scheme) + testInsertAfterMerge(t, processor, 0, 10, full) + testInsertAfterMerge(t, processor, 1, 9, full) + testInsertAfterMerge(t, processor, 2, 8, full) + testInsertAfterMerge(t, processor, 5, 5, full) + testInsertAfterMerge(t, processor, 6, 4, full) + testInsertAfterMerge(t, processor, 9, 1, full) } // Tests that chains missing links do not get accepted by the processor. -func TestBrokenHeaderChain(t *testing.T) { - testBrokenChain(t, false, rawdb.HashScheme) - testBrokenChain(t, false, rawdb.PathScheme) -} -func TestBrokenBlockChain(t *testing.T) { - testBrokenChain(t, true, rawdb.HashScheme) - testBrokenChain(t, true, rawdb.PathScheme) -} +func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) } +func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) } -func testBrokenChain(t *testing.T, full bool, scheme string) { +func testBrokenChain(t *testing.T, full bool) { // Make chain starting from genesis - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 10, full, scheme) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 10, full) if err != nil { t.Fatalf("failed to make new canonical chain: %v", err) } @@ -549,31 +491,19 @@ func testBrokenChain(t *testing.T, full bool, scheme string) { // Tests that reorganising a long difficult chain after a short easy one // overwrites the canonical numbers and links in the database. -func TestReorgLongHeaders(t *testing.T) { - testReorgLong(t, false, rawdb.HashScheme) - testReorgLong(t, false, rawdb.PathScheme) -} -func TestReorgLongBlocks(t *testing.T) { - testReorgLong(t, true, rawdb.HashScheme) - testReorgLong(t, true, rawdb.PathScheme) -} +func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } +func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } -func testReorgLong(t *testing.T, full bool, scheme string) { - testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280+params.GenesisDifficulty.Int64(), full, scheme) +func testReorgLong(t *testing.T, full bool) { + testReorg(t, []int64{0, 0, -9}, []int64{0, 0, 0, -9}, 393280+params.GenesisDifficulty.Int64(), full) } // Tests that reorganising a short difficult chain after a long easy one // overwrites the canonical numbers and links in the database. -func TestReorgShortHeaders(t *testing.T) { - testReorgShort(t, false, rawdb.HashScheme) - testReorgShort(t, false, rawdb.PathScheme) -} -func TestReorgShortBlocks(t *testing.T) { - testReorgShort(t, true, rawdb.HashScheme) - testReorgShort(t, true, rawdb.PathScheme) -} +func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } +func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } -func testReorgShort(t *testing.T, full bool, scheme string) { +func testReorgShort(t *testing.T, full bool) { // Create a long easy chain vs. a short heavy one. Due to difficulty adjustment // we need a fairly long chain of blocks with different difficulties for a short // one to become heavier than a long one. The 96 is an empirical value. @@ -585,12 +515,12 @@ func testReorgShort(t *testing.T, full bool, scheme string) { for i := 0; i < len(diff); i++ { diff[i] = -9 } - testReorg(t, easy, diff, 12615120+params.GenesisDifficulty.Int64(), full, scheme) + testReorg(t, easy, diff, 12615120+params.GenesisDifficulty.Int64(), full) } -func testReorg(t *testing.T, first, second []int64, td int64, full bool, scheme string) { +func testReorg(t *testing.T, first, second []int64, td int64, full bool) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -658,18 +588,12 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool, scheme } // Tests that the insertion functions detect banned hashes. -func TestBadHeaderHashes(t *testing.T) { - testBadHashes(t, false, rawdb.HashScheme) - testBadHashes(t, false, rawdb.PathScheme) -} -func TestBadBlockHashes(t *testing.T) { - testBadHashes(t, true, rawdb.HashScheme) - testBadHashes(t, true, rawdb.PathScheme) -} +func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } +func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } -func testBadHashes(t *testing.T, full bool, scheme string) { +func testBadHashes(t *testing.T, full bool) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -698,18 +622,12 @@ func testBadHashes(t *testing.T, full bool, scheme string) { // Tests that bad hashes are detected on boot, and the chain rolled back to a // good state prior to the bad hash. -func TestReorgBadHeaderHashes(t *testing.T) { - testReorgBadHashes(t, false, rawdb.HashScheme) - testReorgBadHashes(t, false, rawdb.PathScheme) -} -func TestReorgBadBlockHashes(t *testing.T) { - testReorgBadHashes(t, true, rawdb.HashScheme) - testReorgBadHashes(t, true, rawdb.PathScheme) -} +func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) } +func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } -func testReorgBadHashes(t *testing.T, full bool, scheme string) { +func testReorgBadHashes(t *testing.T, full bool) { // Create a pristine chain and database - genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) + genDb, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -739,7 +657,7 @@ func testReorgBadHashes(t *testing.T, full bool, scheme string) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ncm, err := NewBlockChain(blockchain.db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -759,19 +677,13 @@ func testReorgBadHashes(t *testing.T, full bool, scheme string) { } // Tests chain insertions in the face of one entity containing an invalid nonce. -func TestHeadersInsertNonceError(t *testing.T) { - testInsertNonceError(t, false, rawdb.HashScheme) - testInsertNonceError(t, false, rawdb.PathScheme) -} -func TestBlocksInsertNonceError(t *testing.T) { - testInsertNonceError(t, true, rawdb.HashScheme) - testInsertNonceError(t, true, rawdb.PathScheme) -} +func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) } +func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } -func testInsertNonceError(t *testing.T, full bool, scheme string) { +func testInsertNonceError(t *testing.T, full bool) { doTest := func(i int) { // Create a pristine chain and database - genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full, scheme) + genDb, _, blockchain, err := newCanonical(ethash.NewFaker(), 0, full) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -826,11 +738,6 @@ func testInsertNonceError(t *testing.T, full bool, scheme string) { // Tests that fast importing a block chain produces the same chain data as the // classical full block processing. func TestFastVsFullChains(t *testing.T) { - testFastVsFullChains(t, rawdb.HashScheme) - testFastVsFullChains(t, rawdb.PathScheme) -} - -func testFastVsFullChains(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -863,7 +770,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { }) // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() - archive, _ := NewBlockChain(archiveDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -871,7 +778,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { } // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() - fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -890,8 +797,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -959,11 +865,6 @@ func testFastVsFullChains(t *testing.T, scheme string) { // Tests that various import methods move the chain head pointers to the correct // positions. func TestLightVsFastVsFullChainHeads(t *testing.T) { - testLightVsFastVsFullChainHeads(t, rawdb.HashScheme) - testLightVsFastVsFullChainHeads(t, rawdb.PathScheme) -} - -func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1009,7 +910,6 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { archiveCaching := *defaultCacheConfig archiveCaching.TrieDirtyDisabled = true - archiveCaching.StateScheme = scheme archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := archive.InsertChain(blocks); err != nil { @@ -1024,7 +924,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := makeDb() defer fastDb.Close() - fast, _ := NewBlockChain(fastDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -1044,7 +944,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb := makeDb() defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers); err != nil { @@ -1063,7 +963,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Import the chain as a light node and ensure all pointers are updated lightDb := makeDb() defer lightDb.Close() - light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + light, _ := NewBlockChain(lightDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -1076,11 +976,6 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { // Tests that chain reorganisations handle transaction removals and reinsertions. func TestChainTxReorgs(t *testing.T) { - testChainTxReorgs(t, rawdb.HashScheme) - testChainTxReorgs(t, rawdb.PathScheme) -} - -func testChainTxReorgs(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") @@ -1136,7 +1031,7 @@ func testChainTxReorgs(t *testing.T, scheme string) { }) // Import the chain. This runs all block validation rules. db := rawdb.NewMemoryDatabase() - blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1195,11 +1090,6 @@ func testChainTxReorgs(t *testing.T, scheme string) { } func TestLogReorgs(t *testing.T) { - testLogReorgs(t, rawdb.HashScheme) - testLogReorgs(t, rawdb.PathScheme) -} - -func testLogReorgs(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) @@ -1210,7 +1100,7 @@ func testLogReorgs(t *testing.T, scheme string) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1255,18 +1145,13 @@ var logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd // This test checks that log events and RemovedLogsEvent are sent // when the chain reorganizes. func TestLogRebirth(t *testing.T) { - testLogRebirth(t, rawdb.HashScheme) - testLogRebirth(t, rawdb.PathScheme) -} - -func testLogRebirth(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1337,17 +1222,12 @@ func testLogRebirth(t *testing.T, scheme string) { // This test is a variation of TestLogRebirth. It verifies that log events are emitted // when a side chain containing log events overtakes the canonical chain. func TestSideLogRebirth(t *testing.T) { - testSideLogRebirth(t, rawdb.HashScheme) - testSideLogRebirth(t, rawdb.PathScheme) -} - -func testSideLogRebirth(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) ) defer blockchain.Stop() @@ -1432,11 +1312,6 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re } func TestReorgSideEvent(t *testing.T) { - testReorgSideEvent(t, rawdb.HashScheme) - testReorgSideEvent(t, rawdb.PathScheme) -} - -func testReorgSideEvent(t *testing.T, scheme string) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) @@ -1446,7 +1321,7 @@ func testReorgSideEvent(t *testing.T, scheme string) { } signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() _, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {}) @@ -1517,12 +1392,7 @@ done: // Tests if the canonical block can be fetched from the database during chain insertion. func TestCanonicalBlockRetrieval(t *testing.T) { - testCanonicalBlockRetrieval(t, rawdb.HashScheme) - testCanonicalBlockRetrieval(t, rawdb.PathScheme) -} - -func testCanonicalBlockRetrieval(t *testing.T, scheme string) { - _, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, true, scheme) + _, gspec, blockchain, err := newCanonical(ethash.NewFaker(), 0, true) if err != nil { t.Fatalf("failed to create pristine chain: %v", err) } @@ -1566,12 +1436,8 @@ func testCanonicalBlockRetrieval(t *testing.T, scheme string) { } pend.Wait() } -func TestEIP155Transition(t *testing.T) { - testEIP155Transition(t, rawdb.HashScheme) - testEIP155Transition(t, rawdb.PathScheme) -} -func testEIP155Transition(t *testing.T, scheme string) { +func TestEIP155Transition(t *testing.T) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1630,7 +1496,7 @@ func testEIP155Transition(t *testing.T, scheme string) { } }) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(blocks); err != nil { @@ -1680,12 +1546,8 @@ func testEIP155Transition(t *testing.T, scheme string) { t.Errorf("have %v, want %v", have, want) } } -func TestEIP161AccountRemoval(t *testing.T) { - testEIP161AccountRemoval(t, rawdb.HashScheme) - testEIP161AccountRemoval(t, rawdb.PathScheme) -} -func testEIP161AccountRemoval(t *testing.T, scheme string) { +func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1723,7 +1585,7 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) { block.AddTx(tx) }) // account must exist pre eip 161 - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { @@ -1756,11 +1618,6 @@ func testEIP161AccountRemoval(t *testing.T, scheme string) { // // https://github.com/ethereum/go-ethereum/pull/15941 func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { - testBlockchainHeaderchainReorgConsistency(t, rawdb.HashScheme) - testBlockchainHeaderchainReorgConsistency(t, rawdb.PathScheme) -} - -func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -1781,7 +1638,7 @@ func testBlockchainHeaderchainReorgConsistency(t *testing.T, scheme string) { } // Import the canonical and fork chain side by side, verifying the current block // and current header consistency - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1841,8 +1698,8 @@ func TestTrieForkGC(t *testing.T) { } // Dereference all the recent tries and ensure no past trie is left in for i := 0; i < TriesInMemory; i++ { - chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) - chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) + chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) + chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } if nodes, _ := chain.TrieDB().Size(); nodes > 0 { t.Fatalf("stale tries still alive after garbase collection") @@ -1852,11 +1709,6 @@ func TestTrieForkGC(t *testing.T) { // Tests that doing large reorgs works even if the state associated with the // forking point is not available any more. func TestLargeReorgTrieGC(t *testing.T) { - testLargeReorgTrieGC(t, rawdb.HashScheme) - testLargeReorgTrieGC(t, rawdb.PathScheme) -} - -func testLargeReorgTrieGC(t *testing.T, scheme string) { // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() genesis := &Genesis{ @@ -1868,10 +1720,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one - db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) - defer db.Close() - - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1884,7 +1733,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { t.Fatalf("failed to insert original chain: %v", err) } // Ensure that the state associated with the forking point is pruned away - if chain.HasState(shared[len(shared)-1].Root()) { + if node, _ := chain.stateCache.TrieDB().Node(shared[len(shared)-1].Root()); node != nil { t.Fatalf("common-but-old ancestor still cache") } // Import the competitor chain without exceeding the canonical's TD and ensure @@ -1893,7 +1742,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { t.Fatalf("failed to insert competitor chain: %v", err) } for i, block := range competitor[:len(competitor)-2] { - if chain.HasState(block.Root()) { + if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: low TD chain became processed", i) } } @@ -1902,30 +1751,14 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - // In path-based trie database implementation, it will keep 128 diff + 1 disk - // layers, totally 129 latest states available. In hash-based it's 128. - states := TriesInMemory - if scheme == rawdb.PathScheme { - states = states + 1 - } - for i, block := range competitor[:len(competitor)-states] { - if chain.HasState(block.Root()) { - t.Fatalf("competitor %d: unexpected competing chain state", i) - } - } - for i, block := range competitor[len(competitor)-states:] { - if !chain.HasState(block.Root()) { + for i, block := range competitor[:len(competitor)-TriesInMemory] { + if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: competing chain state missing", i) } } } func TestBlockchainRecovery(t *testing.T) { - testBlockchainRecovery(t, rawdb.HashScheme) - testBlockchainRecovery(t, rawdb.PathScheme) -} - -func testBlockchainRecovery(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -1942,7 +1775,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) { t.Fatalf("failed to create temp freezer db: %v", err) } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1962,7 +1795,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancient.Stop() if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1977,13 +1810,8 @@ func testBlockchainRecovery(t *testing.T, scheme string) { // This test checks that InsertReceiptChain will roll back correctly when attempting to insert a side chain. func TestInsertReceiptChainRollback(t *testing.T) { - testInsertReceiptChainRollback(t, rawdb.HashScheme) - testInsertReceiptChainRollback(t, rawdb.PathScheme) -} - -func testInsertReceiptChainRollback(t *testing.T, scheme string) { // Generate forked chain. The returned BlockChain object is used to process the side chain blocks. - tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains(scheme) + tmpChain, sideblocks, canonblocks, gspec, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -2014,7 +1842,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) { } defer ancientDb.Close() - ancientChain, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -2059,11 +1887,6 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) { // - https://github.com/ethereum/go-ethereum/issues/18977 // - https://github.com/ethereum/go-ethereum/pull/18988 func TestLowDiffLongChain(t *testing.T) { - testLowDiffLongChain(t, rawdb.HashScheme) - testLowDiffLongChain(t, rawdb.PathScheme) -} - -func testLowDiffLongChain(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -2078,14 +1901,11 @@ func testLowDiffLongChain(t *testing.T, scheme string) { }) // Import the canonical chain - diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) - defer diskdb.Close() - - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } - defer chain.Stop() + defer chain.stopWithoutSaving() if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) @@ -2265,20 +2085,11 @@ func TestPrunedImportSideWithMerging(t *testing.T) { testSideImport(t, 1, -10, 1) } -func TestInsertKnownHeaders(t *testing.T) { - testInsertKnownChainData(t, "headers", rawdb.HashScheme) - testInsertKnownChainData(t, "headers", rawdb.PathScheme) -} -func TestInsertKnownReceiptChain(t *testing.T) { - testInsertKnownChainData(t, "receipts", rawdb.HashScheme) - testInsertKnownChainData(t, "receipts", rawdb.PathScheme) -} -func TestInsertKnownBlocks(t *testing.T) { - testInsertKnownChainData(t, "blocks", rawdb.HashScheme) - testInsertKnownChainData(t, "blocks", rawdb.PathScheme) -} +func TestInsertKnownHeaders(t *testing.T) { testInsertKnownChainData(t, "headers") } +func TestInsertKnownReceiptChain(t *testing.T) { testInsertKnownChainData(t, "receipts") } +func TestInsertKnownBlocks(t *testing.T) { testInsertKnownChainData(t, "blocks") } -func testInsertKnownChainData(t *testing.T, typ string, scheme string) { +func testInsertKnownChainData(t *testing.T, typ string) { engine := ethash.NewFaker() genesis := &Genesis{ Config: params.TestChainConfig, @@ -2301,7 +2112,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) { } defer chaindb.Close() - chain, err := NewBlockChain(chaindb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2574,7 +2385,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } // getLongAndShortChains returns two chains: A is longer, B is heavier. -func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types.Block, *Genesis, error) { +func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, *Genesis, error) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -2586,7 +2397,7 @@ func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types genDb, longChain, _ := GenerateChainWithGenesis(genesis, engine, 80, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2632,12 +2443,7 @@ func getLongAndShortChains(scheme string) (*BlockChain, []*types.Block, []*types // 3. Then there should be no canon mapping for the block at height X // 4. The forked block should still be retrievable by hash func TestReorgToShorterRemovesCanonMapping(t *testing.T) { - testReorgToShorterRemovesCanonMapping(t, rawdb.HashScheme) - testReorgToShorterRemovesCanonMapping(t, rawdb.PathScheme) -} - -func testReorgToShorterRemovesCanonMapping(t *testing.T, scheme string) { - chain, canonblocks, sideblocks, _, err := getLongAndShortChains(scheme) + chain, canonblocks, sideblocks, _, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -2675,12 +2481,7 @@ func testReorgToShorterRemovesCanonMapping(t *testing.T, scheme string) { // as TestReorgToShorterRemovesCanonMapping, but applied on headerchain // imports -- that is, for fast sync func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { - testReorgToShorterRemovesCanonMappingHeaderChain(t, rawdb.HashScheme) - testReorgToShorterRemovesCanonMappingHeaderChain(t, rawdb.PathScheme) -} - -func testReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T, scheme string) { - chain, canonblocks, sideblocks, _, err := getLongAndShortChains(scheme) + chain, canonblocks, sideblocks, _, err := getLongAndShortChains() if err != nil { t.Fatal(err) } @@ -2823,11 +2624,6 @@ func TestTransactionIndices(t *testing.T) { } func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { - testSkipStaleTxIndicesInSnapSync(t, rawdb.HashScheme) - testSkipStaleTxIndicesInSnapSync(t, rawdb.PathScheme) -} - -func testSkipStaleTxIndicesInSnapSync(t *testing.T, scheme string) { // Configure and generate a sample block chain var ( key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -2886,7 +2682,7 @@ func testSkipStaleTxIndicesInSnapSync(t *testing.T, scheme string) { // Import all blocks into ancient db, only HEAD-32 indices are kept. l := uint64(32) - chain, err := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, &l) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3020,11 +2816,6 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { // 2. Downloader starts to sync again // 3. The blocks fetched are all known and canonical blocks func TestSideImportPrunedBlocks(t *testing.T) { - testSideImportPrunedBlocks(t, rawdb.HashScheme) - testSideImportPrunedBlocks(t, rawdb.PathScheme) -} - -func testSideImportPrunedBlocks(t *testing.T, scheme string) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() genesis := &Genesis{ @@ -3034,7 +2825,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { // Generate and import the canonical chain _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3043,20 +2834,15 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { if n, err := chain.InsertChain(blocks); err != nil { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - // In path-based trie database implementation, it will keep 128 diff + 1 disk - // layers, totally 129 latest states available. In hash-based it's 128. - states := TriesInMemory - if scheme == rawdb.PathScheme { - states = TriesInMemory + 1 - } - lastPrunedIndex := len(blocks) - states - 1 + + lastPrunedIndex := len(blocks) - TriesInMemory - 1 lastPrunedBlock := blocks[lastPrunedIndex] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) } - firstNonPrunedBlock := blocks[len(blocks)-states] + firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] // Verify firstNonPrunedBlock is not pruned if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) @@ -3078,11 +2864,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { // each transaction, so this works ok. The rework accumulated writes in memory // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { - testDeleteCreateRevert(t, rawdb.HashScheme) - testDeleteCreateRevert(t, rawdb.PathScheme) -} - -func testDeleteCreateRevert(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb") @@ -3134,7 +2915,7 @@ func testDeleteCreateRevert(t *testing.T, scheme string) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3153,11 +2934,6 @@ func testDeleteCreateRevert(t *testing.T, scheme string) { // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, // and then the new slots exist func TestDeleteRecreateSlots(t *testing.T) { - testDeleteRecreateSlots(t, rawdb.HashScheme) - testDeleteRecreateSlots(t, rawdb.PathScheme) -} - -func testDeleteRecreateSlots(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3247,7 +3023,7 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3281,11 +3057,6 @@ func testDeleteRecreateSlots(t *testing.T, scheme string) { // regular value-transfer // Expected outcome is that _all_ slots are cleared from A func TestDeleteRecreateAccount(t *testing.T) { - testDeleteRecreateAccount(t, rawdb.HashScheme) - testDeleteRecreateAccount(t, rawdb.PathScheme) -} - -func testDeleteRecreateAccount(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3329,7 +3100,7 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { b.AddTx(tx) }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), }, nil, nil) if err != nil { @@ -3359,11 +3130,6 @@ func testDeleteRecreateAccount(t *testing.T, scheme string) { // Expected outcome is that _all_ slots are cleared from A, due to the selfdestruct, // and then the new slots exist func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { - testDeleteRecreateSlotsAcrossManyBlocks(t, rawdb.HashScheme) - testDeleteRecreateSlotsAcrossManyBlocks(t, rawdb.PathScheme) -} - -func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3504,7 +3270,7 @@ func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) { current = exp }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3562,14 +3328,7 @@ func testDeleteRecreateSlotsAcrossManyBlocks(t *testing.T, scheme string) { // to the destructset in case something is created "onto" an existing item. // We need to either roll back the snapDestructs, or not place it into snapDestructs // in the first place. -// - func TestInitThenFailCreateContract(t *testing.T) { - testInitThenFailCreateContract(t, rawdb.HashScheme) - testInitThenFailCreateContract(t, rawdb.PathScheme) -} - -func testInitThenFailCreateContract(t *testing.T, scheme string) { var ( engine = ethash.NewFaker() @@ -3642,7 +3401,7 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), }, nil, nil) @@ -3680,11 +3439,6 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) { // checking that the gas usage of a hot SLOAD and a cold SLOAD are calculated // correctly. func TestEIP2718Transition(t *testing.T) { - testEIP2718Transition(t, rawdb.HashScheme) - testEIP2718Transition(t, rawdb.PathScheme) -} - -func testEIP2718Transition(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() @@ -3732,7 +3486,7 @@ func testEIP2718Transition(t *testing.T, scheme string) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3762,11 +3516,6 @@ func testEIP2718Transition(t *testing.T, scheme string) { // gasFeeCap - gasTipCap < baseFee. // 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { - testEIP1559Transition(t, rawdb.HashScheme) - testEIP1559Transition(t, rawdb.PathScheme) -} - -func testEIP1559Transition(t *testing.T, scheme string) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") engine = ethash.NewFaker() @@ -3777,9 +3526,8 @@ func testEIP1559Transition(t *testing.T, scheme string) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) - config = *params.AllEthashProtocolChanges gspec = &Genesis{ - Config: &config, + Config: params.AllEthashProtocolChanges, Alloc: GenesisAlloc{ addr1: {Balance: funds}, addr2: {Balance: funds}, @@ -3826,7 +3574,7 @@ func testEIP1559Transition(t *testing.T, scheme string) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3908,11 +3656,6 @@ func testEIP1559Transition(t *testing.T, scheme string) { // Tests the scenario the chain is requested to another point with the missing state. // It expects the state is recovered and all relevant chain markers are set correctly. func TestSetCanonical(t *testing.T) { - testSetCanonical(t, rawdb.HashScheme) - testSetCanonical(t, rawdb.PathScheme) -} - -func testSetCanonical(t *testing.T, scheme string) { //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) var ( @@ -3935,10 +3678,7 @@ func testSetCanonical(t *testing.T, scheme string) { } gen.AddTx(tx) }) - diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) - defer diskdb.Close() - - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3995,11 +3735,6 @@ func testSetCanonical(t *testing.T, scheme string) { // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted // correctly in case reorg is called. func TestCanonicalHashMarker(t *testing.T) { - testCanonicalHashMarker(t, rawdb.HashScheme) - testCanonicalHashMarker(t, rawdb.PathScheme) -} - -func testCanonicalHashMarker(t *testing.T, scheme string) { var cases = []struct { forkA int forkB int @@ -4047,7 +3782,7 @@ func testCanonicalHashMarker(t *testing.T, scheme string) { _, forkB, _ := GenerateChainWithGenesis(gspec, engine, c.forkB, func(i int, gen *BlockGen) {}) // Initialize test chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4403,116 +4138,6 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { } } -func TestDeleteThenCreate(t *testing.T) { - var ( - engine = ethash.NewFaker() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - factoryAddr = crypto.CreateAddress(address, 0) - funds = big.NewInt(1000000000000000) - ) - /* - contract Factory { - function deploy(bytes memory code) public { - address addr; - assembly { - addr := create2(0, add(code, 0x20), mload(code), 0) - if iszero(extcodesize(addr)) { - revert(0, 0) - } - } - } - } - */ - factoryBIN := common.Hex2Bytes("608060405234801561001057600080fd5b50610241806100206000396000f3fe608060405234801561001057600080fd5b506004361061002a5760003560e01c80627743601461002f575b600080fd5b610049600480360381019061004491906100d8565b61004b565b005b6000808251602084016000f59050803b61006457600080fd5b5050565b600061007b61007684610146565b610121565b905082815260208101848484011115610097576100966101eb565b5b6100a2848285610177565b509392505050565b600082601f8301126100bf576100be6101e6565b5b81356100cf848260208601610068565b91505092915050565b6000602082840312156100ee576100ed6101f5565b5b600082013567ffffffffffffffff81111561010c5761010b6101f0565b5b610118848285016100aa565b91505092915050565b600061012b61013c565b90506101378282610186565b919050565b6000604051905090565b600067ffffffffffffffff821115610161576101606101b7565b5b61016a826101fa565b9050602081019050919050565b82818337600083830152505050565b61018f826101fa565b810181811067ffffffffffffffff821117156101ae576101ad6101b7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f830116905091905056fea2646970667358221220ea8b35ed310d03b6b3deef166941140b4d9e90ea2c92f6b41eb441daf49a59c364736f6c63430008070033") - - /* - contract C { - uint256 value; - constructor() { - value = 100; - } - function destruct() public payable { - selfdestruct(payable(msg.sender)); - } - receive() payable external {} - } - */ - contractABI := common.Hex2Bytes("6080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c63430008070033") - contractAddr := crypto.CreateAddress2(factoryAddr, [32]byte{}, crypto.Keccak256(contractABI)) - - gspec := &Genesis{ - Config: params.TestChainConfig, - Alloc: GenesisAlloc{ - address: {Balance: funds}, - }, - } - nonce := uint64(0) - signer := types.HomesteadSigner{} - _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2, func(i int, b *BlockGen) { - fee := big.NewInt(1) - if b.header.BaseFee != nil { - fee = b.header.BaseFee - } - b.SetCoinbase(common.Address{1}) - - // Block 1 - if i == 0 { - tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: nonce, - GasPrice: new(big.Int).Set(fee), - Gas: 500000, - Data: factoryBIN, - }) - nonce++ - b.AddTx(tx) - - data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") - tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: nonce, - GasPrice: new(big.Int).Set(fee), - Gas: 500000, - To: &factoryAddr, - Data: data, - }) - b.AddTx(tx) - nonce++ - } else { - // Block 2 - tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: nonce, - GasPrice: new(big.Int).Set(fee), - Gas: 500000, - To: &contractAddr, - Data: common.Hex2Bytes("2b68b9c6"), // destruct - }) - nonce++ - b.AddTx(tx) - - data := common.Hex2Bytes("00774360000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a76080604052348015600f57600080fd5b5060646000819055506081806100266000396000f3fe608060405260043610601f5760003560e01c80632b68b9c614602a576025565b36602557005b600080fd5b60306032565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220ab749f5ed1fcb87bda03a74d476af3f074bba24d57cb5a355e8162062ad9a4e664736f6c6343000807003300000000000000000000000000000000000000000000000000") - tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ - Nonce: nonce, - GasPrice: new(big.Int).Set(fee), - Gas: 500000, - To: &factoryAddr, // re-creation - Data: data, - }) - b.AddTx(tx) - nonce++ - } - }) - // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("failed to create tester chain: %v", err) - } - for _, block := range blocks { - if _, err := chain.InsertChain([]*types.Block{block}); err != nil { - t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err) - } - } -} - // TestTransientStorageReset ensures the transient storage is wiped correctly // between transactions. func TestTransientStorageReset(t *testing.T) { diff --git a/core/chain_makers.go b/core/chain_makers.go index 56eea0e3f2..4e8e80b92b 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -283,7 +283,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) chainreader := &fakeChainReader{config: config} - genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb *state.StateDB) (*types.Block, types.Receipts) { + genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine} b.header = makeHeader(chainreader, parent, statedb, b.engine) @@ -326,23 +326,19 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } - if err = triedb.Commit(root, false); err != nil { + if err := statedb.Database().TrieDB().Commit(root, false); err != nil { panic(fmt.Sprintf("trie write error: %v", err)) } return block, b.receipts } return nil, nil } - // Forcibly use hash-based state scheme for retaining all nodes in disk. - triedb := trie.NewDatabase(db, trie.HashDefaults) - defer triedb.Close() - for i := 0; i < n; i++ { - statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil) if err != nil { panic(err) } - block, receipt := genblock(i, parent, triedb, statedb) + block, receipt := genblock(i, parent, statedb) blocks[i] = block receipts[i] = receipt parent = block @@ -355,9 +351,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // then generate chain on top. func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (ethdb.Database, []*types.Block, []types.Receipts) { db := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(db, trie.HashDefaults) - defer triedb.Close() - _, err := genesis.Commit(db, triedb) + _, err := genesis.Commit(db, trie.NewDatabase(db)) if err != nil { panic(err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index db220cf24a..4f73555275 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" ) func TestGenerateWithdrawalChain(t *testing.T) { @@ -75,7 +74,8 @@ func TestGenerateWithdrawalChain(t *testing.T) { Storage: storage, Code: common.Hex2Bytes("600154600354"), } - genesis := gspec.MustCommit(gendb, trie.NewDatabase(gendb, trie.HashDefaults)) + + genesis := gspec.MustCommit(gendb) chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) { tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key) @@ -146,7 +146,6 @@ func ExampleGenerateChain() { addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) db = rawdb.NewMemoryDatabase() - genDb = rawdb.NewMemoryDatabase() ) // Ensure that key1 has some funds in the genesis block. @@ -154,13 +153,13 @@ func ExampleGenerateChain() { Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}}, } - genesis := gspec.MustCommit(genDb, trie.NewDatabase(genDb, trie.HashDefaults)) + genesis := gspec.MustCommit(db) // This call generates a chain of 5 blocks. The function runs for // each block and adds different features to gen based on the // block index. signer := types.HomesteadSigner{} - chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), genDb, 5, func(i int, gen *BlockGen) { + chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { switch i { case 0: // In block 1, addr1 sends addr2 some ether. @@ -189,7 +188,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index b9a899ef2f..f2e8dfe8f9 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -83,7 +83,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } bc.Stop() @@ -106,7 +106,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } bc.Stop() @@ -131,7 +131,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import contra-fork chain for expansion: %v", err) } - if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit contra-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) @@ -149,7 +149,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { if _, err := bc.InsertChain(blocks); err != nil { t.Fatalf("failed to import pro-fork chain for expansion: %v", err) } - if err := bc.triedb.Commit(bc.CurrentHeader().Root, false); err != nil { + if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil { t.Fatalf("failed to commit pro-fork head for expansion: %v", err) } blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {}) diff --git a/core/genesis.go b/core/genesis.go index 6a2eafbf83..33716d0b61 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -323,12 +323,10 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen applyOverrides(genesis.Config) return genesis.Config, block.Hash(), nil } - // The genesis block is present(perhaps in ancient database) while the - // state database is not initialized yet. It can happen that the node - // is initialized with an external ancient store. Commit genesis state - // in this case. + // We have the genesis block in database(perhaps in ancient database) + // but the corresponding state is missing. header := rawdb.ReadHeader(db, stored, 0) - if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) { + if header.Root != types.EmptyRootHash && !rawdb.HasLegacyTrieNode(db, header.Root) { if genesis == nil { genesis = DefaultGenesisBlock() } @@ -528,8 +526,10 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block // MustCommit writes the genesis block and state to db, panicking on error. // The block is committed as the canonical head block. -func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block { - block, err := g.Commit(db, triedb) +// Note the state changes will be committed in hash-based scheme, use Commit +// if path-scheme is preferred. +func (g *Genesis) MustCommit(db ethdb.Database) *types.Block { + block, err := g.Commit(db, trie.NewDatabase(db)) if err != nil { panic(err) } diff --git a/core/genesis_test.go b/core/genesis_test.go index 6a0f2df085..723d1e476b 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -30,24 +30,18 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) func TestInvalidCliqueConfig(t *testing.T) { block := DefaultGoerliGenesisBlock() block.ExtraData = []byte{} db := rawdb.NewMemoryDatabase() - if _, err := block.Commit(db, trie.NewDatabase(db, nil)); err == nil { + if _, err := block.Commit(db, trie.NewDatabase(db)); err == nil { t.Fatal("Expected error on invalid clique config") } } func TestSetupGenesis(t *testing.T) { - testSetupGenesis(t, rawdb.HashScheme) - testSetupGenesis(t, rawdb.PathScheme) -} - -func testSetupGenesis(t *testing.T, scheme string) { var ( customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") customg = Genesis{ @@ -59,7 +53,6 @@ func testSetupGenesis(t *testing.T, scheme string) { oldcustomg = customg ) oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} - tests := []struct { name string fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) @@ -70,7 +63,7 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "genesis without ChainConfig", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), new(Genesis)) + return SetupGenesisBlock(db, trie.NewDatabase(db), new(Genesis)) }, wantErr: errGenesisNoConfig, wantConfig: params.AllEthashProtocolChanges, @@ -78,7 +71,7 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "no block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -86,8 +79,8 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "mainnet block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - DefaultGenesisBlock().MustCommit(db, trie.NewDatabase(db, newDbConfig(scheme))) - return SetupGenesisBlock(db, trie.NewDatabase(db, newDbConfig(scheme)), nil) + DefaultGenesisBlock().MustCommit(db) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: params.MainnetGenesisHash, wantConfig: params.MainnetChainConfig, @@ -95,9 +88,8 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "custom block in DB, genesis == nil", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - tdb := trie.NewDatabase(db, newDbConfig(scheme)) - customg.Commit(db, tdb) - return SetupGenesisBlock(db, tdb, nil) + customg.MustCommit(db) + return SetupGenesisBlock(db, trie.NewDatabase(db), nil) }, wantHash: customghash, wantConfig: customg.Config, @@ -105,9 +97,8 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "custom block in DB, genesis == goerli", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - tdb := trie.NewDatabase(db, newDbConfig(scheme)) - customg.Commit(db, tdb) - return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) + customg.MustCommit(db) + return SetupGenesisBlock(db, trie.NewDatabase(db), DefaultGoerliGenesisBlock()) }, wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, wantHash: params.GoerliGenesisHash, @@ -116,9 +107,8 @@ func testSetupGenesis(t *testing.T, scheme string) { { name: "compatible config in DB", fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { - tdb := trie.NewDatabase(db, newDbConfig(scheme)) - oldcustomg.Commit(db, tdb) - return SetupGenesisBlock(db, tdb, &customg) + oldcustomg.MustCommit(db) + return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -128,17 +118,16 @@ func testSetupGenesis(t *testing.T, scheme string) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. - tdb := trie.NewDatabase(db, newDbConfig(scheme)) - oldcustomg.Commit(db, tdb) + genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) defer bc.Stop() - _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) + blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) bc.InsertChain(blocks) // This should return a compatibility error. - return SetupGenesisBlock(db, tdb, &customg) + return SetupGenesisBlock(db, trie.NewDatabase(db), &customg) }, wantHash: customghash, wantConfig: customg.Config, @@ -186,8 +175,7 @@ func TestGenesisHashes(t *testing.T) { {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, } { // Test via MustCommit - db := rawdb.NewMemoryDatabase() - if have := c.genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)).Hash(); have != c.want { + if have := c.genesis.MustCommit(rawdb.NewMemoryDatabase()).Hash(); have != c.want { t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) } // Test via ToBlock @@ -205,7 +193,7 @@ func TestGenesis_Commit(t *testing.T) { } db := rawdb.NewMemoryDatabase() - genesisBlock := genesis.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + genesisBlock := genesis.MustCommit(db) if genesis.Difficulty != nil { t.Fatalf("assumption wrong") @@ -254,10 +242,3 @@ func TestReadWriteGenesisAlloc(t *testing.T) { } } } - -func newDbConfig(scheme string) *trie.Config { - if scheme == rawdb.HashScheme { - return trie.HashDefaults - } - return &trie.Config{PathDB: pathdb.Defaults} -} diff --git a/core/headerchain_test.go b/core/headerchain_test.go index 2c0323e6f7..08d19f6950 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} ) - gspec.Commit(db, trie.NewDatabase(db, nil)) + gspec.Commit(db, trie.NewDatabase(db)) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) if err != nil { t.Fatal(err) diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index a7ceb72998..a34bfc1a56 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -435,12 +435,12 @@ func checkReceiptsRLP(have, want types.Receipts) error { func TestAncientStorage(t *testing.T) { // Freezer style fast import the chain. frdir := t.TempDir() + db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false) if err != nil { t.Fatalf("failed to create database with ancient backend") } defer db.Close() - // Create a test block block := types.NewBlockWithHeader(&types.Header{ Number: big.NewInt(0), diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index f5c2f8899a..12f1ecdf83 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -36,7 +36,7 @@ import ( // // Now this scheme is still kept for backward compatibility, and it will be used // for archive node and some other tries(e.g. light trie). -const HashScheme = "hash" +const HashScheme = "hashScheme" // PathScheme is the new path-based state scheme with which trie nodes are stored // in the disk with node path as the database key. This scheme will only store one @@ -44,7 +44,7 @@ const HashScheme = "hash" // is native. At the same time, this scheme will put adjacent trie nodes in the same // area of the disk with good data locality property. But this scheme needs to rely // on extra state diffs to survive deep reorg. -const PathScheme = "path" +const PathScheme = "pathScheme" // hasher is used to compute the sha256 hash of the provided data. type hasher struct{ sha crypto.KeccakState } @@ -263,25 +263,3 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has panic(fmt.Sprintf("Unknown scheme %v", scheme)) } } - -// ReadStateScheme reads the state scheme of persistent state, or none -// if the state is not present in database. -func ReadStateScheme(db ethdb.Reader) string { - // Check if state in path-based scheme is present - blob, _ := ReadAccountTrieNode(db, nil) - if len(blob) != 0 { - return PathScheme - } - // In a hash-based scheme, the genesis state is consistently stored - // on the disk. To assess the scheme of the persistent state, it - // suffices to inspect the scheme of the genesis state. - header := ReadHeader(db, ReadCanonicalHash(db, 0), 0) - if header == nil { - return "" // empty datadir - } - blob = ReadLegacyTrieNode(db, header.Root) - if len(blob) == 0 { - return "" // no state in disk - } - return HashScheme -} diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 6f409fff1d..c1cd7fda17 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -58,7 +58,7 @@ const ( stateHistoryStorageData = "storage.data" ) -var stateFreezerNoSnappy = map[string]bool{ +var stateHistoryFreezerNoSnappy = map[string]bool{ stateHistoryMeta: true, stateHistoryAccountIndex: false, stateHistoryStorageIndex: false, @@ -75,7 +75,7 @@ var ( // freezers the collections of all builtin freezers. var freezers = []string{chainFreezerName, stateFreezerName} -// NewStateFreezer initializes the freezer for state history. -func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) { - return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) +// NewStateHistoryFreezer initializes the freezer for state history. +func NewStateHistoryFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) { + return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateHistoryFreezerNoSnappy) } diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 96bd9ee408..363a911aee 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -50,58 +50,36 @@ func (info *freezerInfo) size() common.StorageSize { return total } -func inspect(name string, order map[string]bool, reader ethdb.AncientReader) (freezerInfo, error) { - info := freezerInfo{name: name} - for t := range order { - size, err := reader.AncientSize(t) - if err != nil { - return freezerInfo{}, err - } - info.sizes = append(info.sizes, tableSize{name: t, size: common.StorageSize(size)}) - } - // Retrieve the number of last stored item - ancients, err := reader.Ancients() - if err != nil { - return freezerInfo{}, err - } - info.head = ancients - 1 - - // Retrieve the number of first stored item - tail, err := reader.Tail() - if err != nil { - return freezerInfo{}, err - } - info.tail = tail - return info, nil -} - // inspectFreezers inspects all freezers registered in the system. func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { var infos []freezerInfo for _, freezer := range freezers { switch freezer { case chainFreezerName: - info, err := inspect(chainFreezerName, chainFreezerNoSnappy, db) + // Chain ancient store is a bit special. It's always opened along + // with the key-value store, inspect the chain store directly. + info := freezerInfo{name: freezer} + // Retrieve storage size of every contained table. + for table := range chainFreezerNoSnappy { + size, err := db.AncientSize(table) + if err != nil { + return nil, err + } + info.sizes = append(info.sizes, tableSize{name: table, size: common.StorageSize(size)}) + } + // Retrieve the number of last stored item + ancients, err := db.Ancients() if err != nil { return nil, err } - infos = append(infos, info) + info.head = ancients - 1 - case stateFreezerName: - datadir, err := db.AncientDatadir() - if err != nil { - return nil, err - } - f, err := NewStateFreezer(datadir, true) - if err != nil { - return nil, err - } - defer f.Close() - - info, err := inspect(stateFreezerName, stateFreezerNoSnappy, f) + // Retrieve the number of first stored item + tail, err := db.Tail() if err != nil { return nil, err } + info.tail = tail infos = append(infos, info) default: diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 981690f7bd..7bc9109061 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -463,10 +463,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { tds stat numHashPairings stat hashNumPairings stat - legacyTries stat - stateLookups stat - accountTries stat - storageTries stat + tries stat codes stat txLookups stat accountSnaps stat @@ -507,14 +504,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { numHashPairings.Add(size) case bytes.HasPrefix(key, headerNumberPrefix) && len(key) == (len(headerNumberPrefix)+common.HashLength): hashNumPairings.Add(size) - case IsLegacyTrieNode(key, it.Value()): - legacyTries.Add(size) - case bytes.HasPrefix(key, stateIDPrefix) && len(key) == len(stateIDPrefix)+common.HashLength: - stateLookups.Add(size) - case IsAccountTrieNode(key): - accountTries.Add(size) - case IsStorageTrieNode(key): - storageTries.Add(size) + case len(key) == common.HashLength: + tries.Add(size) case bytes.HasPrefix(key, CodePrefix) && len(key) == len(CodePrefix)+common.HashLength: codes.Add(size) case bytes.HasPrefix(key, txLookupPrefix) && len(key) == (len(txLookupPrefix)+common.HashLength): @@ -552,7 +543,6 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey, snapshotJournalKey, snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey, uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey, - persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, } { if bytes.Equal(key, meta) { metadata.Add(size) @@ -581,10 +571,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Key-Value store", "Transaction index", txLookups.Size(), txLookups.Count()}, {"Key-Value store", "Bloombit index", bloomBits.Size(), bloomBits.Count()}, {"Key-Value store", "Contract codes", codes.Size(), codes.Count()}, - {"Key-Value store", "Hash trie nodes", legacyTries.Size(), legacyTries.Count()}, - {"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()}, - {"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()}, - {"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()}, + {"Key-Value store", "Trie nodes", tries.Size(), tries.Count()}, {"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()}, {"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()}, {"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index b9b9aae0d2..940ce01549 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -273,10 +273,9 @@ func IsLegacyTrieNode(key []byte, val []byte) bool { return bytes.Equal(key, crypto.Keccak256(val)) } -// ResolveAccountTrieNodeKey reports whether a provided database entry is an -// account trie node in path-based state scheme, and returns the resolved -// node path if so. -func ResolveAccountTrieNodeKey(key []byte) (bool, []byte) { +// IsAccountTrieNode reports whether a provided database entry is an account +// trie node in path-based state scheme. +func IsAccountTrieNode(key []byte) (bool, []byte) { if !bytes.HasPrefix(key, trieNodeAccountPrefix) { return false, nil } @@ -289,17 +288,9 @@ func ResolveAccountTrieNodeKey(key []byte) (bool, []byte) { return true, key[len(trieNodeAccountPrefix):] } -// IsAccountTrieNode reports whether a provided database entry is an account +// IsStorageTrieNode reports whether a provided database entry is a storage // trie node in path-based state scheme. -func IsAccountTrieNode(key []byte) bool { - ok, _ := ResolveAccountTrieNodeKey(key) - return ok -} - -// ResolveStorageTrieNode reports whether a provided database entry is a storage -// trie node in path-based state scheme, and returns the resolved account hash -// and node path if so. -func ResolveStorageTrieNode(key []byte) (bool, common.Hash, []byte) { +func IsStorageTrieNode(key []byte) (bool, common.Hash, []byte) { if !bytes.HasPrefix(key, trieNodeStoragePrefix) { return false, common.Hash{}, nil } @@ -315,10 +306,3 @@ func ResolveStorageTrieNode(key []byte) (bool, common.Hash, []byte) { accountHash := common.BytesToHash(key[len(trieNodeStoragePrefix) : len(trieNodeStoragePrefix)+common.HashLength]) return true, accountHash, key[len(trieNodeStoragePrefix)+common.HashLength:] } - -// IsStorageTrieNode reports whether a provided database entry is a storage -// trie node in path-based state scheme. -func IsStorageTrieNode(key []byte) bool { - ok, _, _ := ResolveStorageTrieNode(key) - return ok -} diff --git a/core/state/database.go b/core/state/database.go index 9467c8f72e..a3b6322ae3 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -58,7 +58,7 @@ type Database interface { // DiskDB returns the underlying key-value disk database. DiskDB() ethdb.KeyValueStore - // TrieDB returns the underlying trie database for managing trie nodes. + // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database } @@ -147,7 +147,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { disk: db, codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: trie.NewDatabase(db, config), + triedb: trie.NewDatabaseWithConfig(db, config), } } diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index 73cc22490b..c8e1a181eb 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -26,14 +26,9 @@ import ( // Tests that the node iterator indeed walks over the entire database contents. func TestNodeIteratorCoverage(t *testing.T) { - testNodeIteratorCoverage(t, rawdb.HashScheme) - testNodeIteratorCoverage(t, rawdb.PathScheme) -} - -func testNodeIteratorCoverage(t *testing.T, scheme string) { // Create some arbitrary test state to iterate - db, sdb, ndb, root, _ := makeTestState(scheme) - ndb.Commit(root, false) + db, sdb, root, _ := makeTestState() + sdb.TrieDB().Commit(root, false) state, err := New(root, sdb, nil) if err != nil { @@ -53,7 +48,7 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) { ) it := db.NewIterator(nil, nil) for it.Next() { - ok, hash := isTrieNode(scheme, it.Key(), it.Value()) + ok, hash := isTrieNode(sdb.TrieDB().Scheme(), it.Key(), it.Value()) if !ok { continue } @@ -95,11 +90,11 @@ func isTrieNode(scheme string, key, val []byte) (bool, common.Hash) { return true, common.BytesToHash(key) } } else { - ok := rawdb.IsAccountTrieNode(key) + ok, _ := rawdb.IsAccountTrieNode(key) if ok { return true, crypto.Keccak256Hash(val) } - ok = rawdb.IsStorageTrieNode(key) + ok, _, _ = rawdb.IsStorageTrieNode(key) if ok { return true, crypto.Keccak256Hash(val) } diff --git a/core/state/pruner/pruner.go b/core/state/pruner/pruner.go index 5acf54f642..64c4a3a6eb 100644 --- a/core/state/pruner/pruner.go +++ b/core/state/pruner/pruner.go @@ -85,16 +85,13 @@ func NewPruner(db ethdb.Database, config Config) (*Pruner, error) { if headBlock == nil { return nil, errors.New("failed to load head block") } - // Offline pruning is only supported in legacy hash based scheme. - triedb := trie.NewDatabase(db, trie.HashDefaults) - snapconfig := snapshot.Config{ CacheSize: 256, Recovery: false, NoBuild: true, AsyncBuild: false, } - snaptree, err := snapshot.New(snapconfig, db, triedb, headBlock.Root()) + snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) if err != nil { return nil, err // The relevant snapshot(s) might not exist } @@ -364,9 +361,7 @@ func RecoverPruning(datadir string, db ethdb.Database) error { NoBuild: true, AsyncBuild: false, } - // Offline pruning is only supported in legacy hash based scheme. - triedb := trie.NewDatabase(db, trie.HashDefaults) - snaptree, err := snapshot.New(snapconfig, db, triedb, headBlock.Root()) + snaptree, err := snapshot.New(snapconfig, db, trie.NewDatabase(db), headBlock.Root()) if err != nil { return err // The relevant snapshot(s) might not exist } @@ -408,7 +403,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { if genesis == nil { return errors.New("missing genesis block") } - t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db, trie.HashDefaults)) + t, err := trie.NewStateTrie(trie.StateTrieID(genesis.Root()), trie.NewDatabase(db)) if err != nil { return err } @@ -432,7 +427,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error { } if acc.Root != types.EmptyRootHash { id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root) - storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db, trie.HashDefaults)) + storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db)) if err != nil { return err } diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 40264b092c..0a85f0006d 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -356,8 +356,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi var resolver trie.NodeResolver if len(result.keys) > 0 { mdb := rawdb.NewMemoryDatabase() - tdb := trie.NewDatabase(mdb, trie.HashDefaults) - defer tdb.Close() + tdb := trie.NewDatabase(mdb) snapTrie := trie.NewEmpty(tdb) for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index 07016b675c..c503676241 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -30,8 +30,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" ) @@ -47,15 +45,10 @@ func hashData(input []byte) common.Hash { // Tests that snapshot generation from an empty database. func TestGeneration(t *testing.T) { - testGeneration(t, rawdb.HashScheme) - testGeneration(t, rawdb.PathScheme) -} - -func testGeneration(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var helper = newHelper(scheme) + var helper = newHelper() stRoot := helper.makeStorageTrie(common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false) helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) @@ -86,15 +79,10 @@ func testGeneration(t *testing.T, scheme string) { // Tests that snapshot generation with existent flat state. func TestGenerateExistentState(t *testing.T) { - testGenerateExistentState(t, rawdb.HashScheme) - testGenerateExistentState(t, rawdb.PathScheme) -} - -func testGenerateExistentState(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var helper = newHelper(scheme) + var helper = newHelper() stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) @@ -160,15 +148,9 @@ type testHelper struct { nodes *trienode.MergedNodeSet } -func newHelper(scheme string) *testHelper { +func newHelper() *testHelper { diskdb := rawdb.NewMemoryDatabase() - config := &trie.Config{} - if scheme == rawdb.PathScheme { - config.PathDB = &pathdb.Config{} // disable caching - } else { - config.HashDB = &hashdb.Config{} // disable caching - } - triedb := trie.NewDatabase(diskdb, config) + triedb := trie.NewDatabase(diskdb) accTrie, _ := trie.NewStateTrie(trie.StateTrieID(types.EmptyRootHash), triedb) return &testHelper{ diskdb: diskdb, @@ -251,12 +233,7 @@ func (t *testHelper) CommitAndGenerate() (common.Hash, *diskLayer) { // - extra slots in the middle // - extra slots in the end func TestGenerateExistentStateWithWrongStorage(t *testing.T) { - testGenerateExistentStateWithWrongStorage(t, rawdb.HashScheme) - testGenerateExistentStateWithWrongStorage(t, rawdb.PathScheme) -} - -func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) { - helper := newHelper(scheme) + helper := newHelper() // Account one, empty root but non-empty database helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) @@ -348,12 +325,7 @@ func testGenerateExistentStateWithWrongStorage(t *testing.T, scheme string) { // - wrong accounts // - extra accounts func TestGenerateExistentStateWithWrongAccounts(t *testing.T) { - testGenerateExistentStateWithWrongAccounts(t, rawdb.HashScheme) - testGenerateExistentStateWithWrongAccounts(t, rawdb.PathScheme) -} - -func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) { - helper := newHelper(scheme) + helper := newHelper() helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.makeStorageTrie(hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) @@ -408,15 +380,10 @@ func testGenerateExistentStateWithWrongAccounts(t *testing.T, scheme string) { // Tests that snapshot generation errors out correctly in case of a missing trie // node in the account trie. func TestGenerateCorruptAccountTrie(t *testing.T) { - testGenerateCorruptAccountTrie(t, rawdb.HashScheme) - testGenerateCorruptAccountTrie(t, rawdb.PathScheme) -} - -func testGenerateCorruptAccountTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // without any storage slots to keep the test smaller. - helper := newHelper(scheme) + helper := newHelper() helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074 helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 @@ -424,11 +391,9 @@ func testGenerateCorruptAccountTrie(t *testing.T, scheme string) { root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978 - // Delete an account trie node and ensure the generator chokes - targetPath := []byte{0xc} - targetHash := common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7") - - rawdb.DeleteTrieNode(helper.diskdb, common.Hash{}, targetPath, targetHash, scheme) + // Delete an account trie leaf and ensure the generator chokes + helper.triedb.Commit(root, false) + helper.diskdb.Delete(common.HexToHash("0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7").Bytes()) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -449,19 +414,11 @@ func testGenerateCorruptAccountTrie(t *testing.T, scheme string) { // trie node for a storage trie. It's similar to internal corruption but it is // handled differently inside the generator. func TestGenerateMissingStorageTrie(t *testing.T) { - testGenerateMissingStorageTrie(t, rawdb.HashScheme) - testGenerateMissingStorageTrie(t, rawdb.PathScheme) -} - -func testGenerateMissingStorageTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - var ( - acc1 = hashData([]byte("acc-1")) - acc3 = hashData([]byte("acc-3")) - helper = newHelper(scheme) - ) + helper := newHelper() + stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.addTrieAccount("acc-2", &types.StateAccount{Balance: big.NewInt(2), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7 @@ -470,9 +427,8 @@ func testGenerateMissingStorageTrie(t *testing.T, scheme string) { root := helper.Commit() - // Delete storage trie root of account one and three. - rawdb.DeleteTrieNode(helper.diskdb, acc1, nil, stRoot, scheme) - rawdb.DeleteTrieNode(helper.diskdb, acc3, nil, stRoot, scheme) + // Delete a storage trie root and ensure the generator chokes + helper.diskdb.Delete(stRoot.Bytes()) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -492,15 +448,10 @@ func testGenerateMissingStorageTrie(t *testing.T, scheme string) { // Tests that snapshot generation errors out correctly in case of a missing trie // node in a storage trie. func TestGenerateCorruptStorageTrie(t *testing.T) { - testGenerateCorruptStorageTrie(t, rawdb.HashScheme) - testGenerateCorruptStorageTrie(t, rawdb.PathScheme) -} - -func testGenerateCorruptStorageTrie(t *testing.T, scheme string) { // We can't use statedb to make a test trie (circular dependency), so make // a fake one manually. We're going with a small account trie of 3 accounts, // two of which also has the same 3-slot storage trie attached. - helper := newHelper(scheme) + helper := newHelper() stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67 helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e @@ -510,11 +461,8 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) { root := helper.Commit() - // Delete a node in the storage trie. - targetPath := []byte{0x4} - targetHash := common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371") - rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-1")), targetPath, targetHash, scheme) - rawdb.DeleteTrieNode(helper.diskdb, hashData([]byte("acc-3")), targetPath, targetHash, scheme) + // Delete a storage trie leaf and ensure the generator chokes + helper.diskdb.Delete(common.HexToHash("0x18a0f4d79cff4459642dd7604f303886ad9d77c30cf3d7d7cedb3a693ab6d371").Bytes()) snap := generateSnapshot(helper.diskdb, helper.triedb, 16, root) select { @@ -533,12 +481,7 @@ func testGenerateCorruptStorageTrie(t *testing.T, scheme string) { // Tests that snapshot generation when an extra account with storage exists in the snap state. func TestGenerateWithExtraAccounts(t *testing.T) { - testGenerateWithExtraAccounts(t, rawdb.HashScheme) - testGenerateWithExtraAccounts(t, rawdb.PathScheme) -} - -func testGenerateWithExtraAccounts(t *testing.T, scheme string) { - helper := newHelper(scheme) + helper := newHelper() { // Account one in the trie stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), @@ -606,15 +549,10 @@ func enableLogging() { // Tests that snapshot generation when an extra account with storage exists in the snap state. func TestGenerateWithManyExtraAccounts(t *testing.T) { - testGenerateWithManyExtraAccounts(t, rawdb.HashScheme) - testGenerateWithManyExtraAccounts(t, rawdb.PathScheme) -} - -func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) { if false { enableLogging() } - helper := newHelper(scheme) + helper := newHelper() { // Account one in the trie stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), @@ -667,16 +605,11 @@ func testGenerateWithManyExtraAccounts(t *testing.T, scheme string) { // So in trie, we iterate 2 entries 0x03, 0x07. We create the 0x07 in the database and abort the procedure, because the trie is exhausted. // But in the database, we still have the stale storage slots 0x04, 0x05. They are not iterated yet, but the procedure is finished. func TestGenerateWithExtraBeforeAndAfter(t *testing.T) { - testGenerateWithExtraBeforeAndAfter(t, rawdb.HashScheme) - testGenerateWithExtraBeforeAndAfter(t, rawdb.PathScheme) -} - -func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) { accountCheckRange = 3 if false { enableLogging() } - helper := newHelper(scheme) + helper := newHelper() { acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) @@ -709,16 +642,11 @@ func testGenerateWithExtraBeforeAndAfter(t *testing.T, scheme string) { // TestGenerateWithMalformedSnapdata tests what happes if we have some junk // in the snapshot database, which cannot be parsed back to an account func TestGenerateWithMalformedSnapdata(t *testing.T) { - testGenerateWithMalformedSnapdata(t, rawdb.HashScheme) - testGenerateWithMalformedSnapdata(t, rawdb.PathScheme) -} - -func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) { accountCheckRange = 3 if false { enableLogging() } - helper := newHelper(scheme) + helper := newHelper() { acc := &types.StateAccount{Balance: big.NewInt(1), Root: types.EmptyRootHash, CodeHash: types.EmptyCodeHash.Bytes()} val, _ := rlp.EncodeToBytes(acc) @@ -751,15 +679,10 @@ func testGenerateWithMalformedSnapdata(t *testing.T, scheme string) { } func TestGenerateFromEmptySnap(t *testing.T) { - testGenerateFromEmptySnap(t, rawdb.HashScheme) - testGenerateFromEmptySnap(t, rawdb.PathScheme) -} - -func testGenerateFromEmptySnap(t *testing.T, scheme string) { //enableLogging() accountCheckRange = 10 storageCheckRange = 20 - helper := newHelper(scheme) + helper := newHelper() // Add 1K accounts to the trie for i := 0; i < 400; i++ { stRoot := helper.makeStorageTrie(hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) @@ -791,13 +714,8 @@ func testGenerateFromEmptySnap(t *testing.T, scheme string) { // This hits a case where the snap verification passes, but there are more elements in the trie // which we must also add. func TestGenerateWithIncompleteStorage(t *testing.T) { - testGenerateWithIncompleteStorage(t, rawdb.HashScheme) - testGenerateWithIncompleteStorage(t, rawdb.PathScheme) -} - -func testGenerateWithIncompleteStorage(t *testing.T, scheme string) { storageCheckRange = 4 - helper := newHelper(scheme) + helper := newHelper() stKeys := []string{"1", "2", "3", "4", "5", "6", "7", "8"} stVals := []string{"v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8"} // We add 8 accounts, each one is missing exactly one of the storage slots. This means @@ -895,12 +813,7 @@ func populateDangling(disk ethdb.KeyValueStore) { // // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) { - testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.HashScheme) - testGenerateCompleteSnapshotWithDanglingStorage(t, rawdb.PathScheme) -} - -func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string) { - var helper = newHelper(scheme) + var helper = newHelper() stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) @@ -935,12 +848,7 @@ func testGenerateCompleteSnapshotWithDanglingStorage(t *testing.T, scheme string // // This test will populate some dangling storages to see if they can be cleaned up. func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) { - testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.HashScheme) - testGenerateBrokenSnapshotWithDanglingStorage(t, rawdb.PathScheme) -} - -func testGenerateBrokenSnapshotWithDanglingStorage(t *testing.T, scheme string) { - var helper = newHelper(scheme) + var helper = newHelper() stRoot := helper.makeStorageTrie(hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) helper.addTrieAccount("acc-1", &types.StateAccount{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index aa95236621..17d60c9ba6 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -179,7 +179,7 @@ func (test *stateTest) run() bool { storageList = append(storageList, copy2DSet(states.Storages)) } disk = rawdb.NewMemoryDatabase() - tdb = trie.NewDatabase(disk, &trie.Config{OnCommit: onCommit}) + tdb = trie.NewDatabaseWithConfig(disk, &trie.Config{OnCommit: onCommit}) sdb = NewDatabaseWithNodeDB(disk, tdb) byzantium = rand.Intn(2) == 0 ) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index c08a0d959f..66dda238e1 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -36,19 +36,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // Tests that updating a state trie does not leak any database writes prior to // actually committing the state. func TestUpdateLeaks(t *testing.T) { // Create an empty state database - var ( - db = rawdb.NewMemoryDatabase() - tdb = trie.NewDatabase(db, nil) - ) - state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) + db := rawdb.NewMemoryDatabase() + state, _ := New(types.EmptyRootHash, NewDatabase(db), nil) // Update it with some accounts for i := byte(0); i < 255; i++ { @@ -64,7 +59,7 @@ func TestUpdateLeaks(t *testing.T) { } root := state.IntermediateRoot(false) - if err := tdb.Commit(root, false); err != nil { + if err := state.Database().TrieDB().Commit(root, false); err != nil { t.Errorf("can not commit trie %v to persistent database", root.Hex()) } @@ -82,10 +77,8 @@ func TestIntermediateLeaks(t *testing.T) { // Create two state databases, one transitioning to the final state, the other final from the beginning transDb := rawdb.NewMemoryDatabase() finalDb := rawdb.NewMemoryDatabase() - transNdb := trie.NewDatabase(transDb, nil) - finalNdb := trie.NewDatabase(finalDb, nil) - transState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(transDb, transNdb), nil) - finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil) + transState, _ := New(types.EmptyRootHash, NewDatabase(transDb), nil) + finalState, _ := New(types.EmptyRootHash, NewDatabase(finalDb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) @@ -117,7 +110,7 @@ func TestIntermediateLeaks(t *testing.T) { if err != nil { t.Fatalf("failed to commit transition state: %v", err) } - if err = transNdb.Commit(transRoot, false); err != nil { + if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } @@ -125,7 +118,7 @@ func TestIntermediateLeaks(t *testing.T) { if err != nil { t.Fatalf("failed to commit final state: %v", err) } - if err = finalNdb.Commit(finalRoot, false); err != nil { + if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil { t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) } @@ -754,28 +747,9 @@ func TestDeleteCreateRevert(t *testing.T) { // the Commit operation fails with an error // If we are missing trie nodes, we should not continue writing to the trie func TestMissingTrieNodes(t *testing.T) { - testMissingTrieNodes(t, rawdb.HashScheme) - testMissingTrieNodes(t, rawdb.PathScheme) -} - -func testMissingTrieNodes(t *testing.T, scheme string) { // Create an initial state with a few accounts - var ( - triedb *trie.Database - memDb = rawdb.NewMemoryDatabase() - ) - if scheme == rawdb.PathScheme { - triedb = trie.NewDatabase(memDb, &trie.Config{PathDB: &pathdb.Config{ - CleanCacheSize: 0, - DirtyCacheSize: 0, - }}) // disable caching - } else { - triedb = trie.NewDatabase(memDb, &trie.Config{HashDB: &hashdb.Config{ - CleanCacheSize: 0, - }}) // disable caching - } - db := NewDatabaseWithNodeDB(memDb, triedb) - + memDb := rawdb.NewMemoryDatabase() + db := NewDatabase(memDb) var root common.Hash state, _ := New(types.EmptyRootHash, db, nil) addr := common.BytesToAddress([]byte("so")) @@ -788,7 +762,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { root, _ = state.Commit(0, false) t.Logf("root: %x", root) // force-flush - triedb.Commit(root, false) + state.Database().TrieDB().Cap(0) } // Create a new state on the old root state, _ = New(root, db, nil) @@ -995,8 +969,7 @@ func TestFlushOrderDataLoss(t *testing.T) { // Create a state trie with many accounts and slots var ( memdb = rawdb.NewMemoryDatabase() - triedb = trie.NewDatabase(memdb, nil) - statedb = NewDatabaseWithNodeDB(memdb, triedb) + statedb = NewDatabase(memdb) state, _ = New(types.EmptyRootHash, statedb, nil) ) for a := byte(0); a < 10; a++ { @@ -1009,11 +982,11 @@ func TestFlushOrderDataLoss(t *testing.T) { if err != nil { t.Fatalf("failed to commit state trie: %v", err) } - triedb.Reference(root, common.Hash{}) - if err := triedb.Cap(1024); err != nil { + statedb.TrieDB().Reference(root, common.Hash{}) + if err := statedb.TrieDB().Cap(1024); err != nil { t.Fatalf("failed to cap trie dirty cache: %v", err) } - if err := triedb.Commit(root, false); err != nil { + if err := statedb.TrieDB().Commit(root, false); err != nil { t.Fatalf("failed to commit state trie: %v", err) } // Reopen the state trie from flushed disk and verify it @@ -1067,7 +1040,7 @@ func TestStateDBTransientStorage(t *testing.T) { func TestResetObject(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() - tdb = trie.NewDatabase(disk, nil) + tdb = trie.NewDatabase(disk) db = NewDatabaseWithNodeDB(disk, tdb) snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) state, _ = New(types.EmptyRootHash, db, snaps) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 6196e77817..b065ad8355 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -28,8 +28,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // testAccount is the data associated with an account used by the state tests. @@ -41,17 +39,10 @@ type testAccount struct { } // makeTestState create a sample test state to test node-wise reconstruction. -func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, common.Hash, []*testAccount) { +func makeTestState() (ethdb.Database, Database, common.Hash, []*testAccount) { // Create an empty state - config := &trie.Config{Preimages: true} - if scheme == rawdb.PathScheme { - config.PathDB = pathdb.Defaults - } else { - config.HashDB = hashdb.Defaults - } db := rawdb.NewMemoryDatabase() - nodeDb := trie.NewDatabase(db, config) - sdb := NewDatabaseWithNodeDB(db, nodeDb) + sdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) state, _ := New(types.EmptyRootHash, sdb, nil) // Fill it with some arbitrary data @@ -76,27 +67,24 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com obj.SetState(hash, hash) } } + state.updateStateObject(obj) accounts = append(accounts, acc) } root, _ := state.Commit(0, false) // Return the generated state - return db, sdb, nodeDb, root, accounts + return db, sdb, root, accounts } // checkStateAccounts cross references a reconstructed state with an expected // account array. -func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root common.Hash, accounts []*testAccount) { - var config trie.Config - if scheme == rawdb.PathScheme { - config.PathDB = pathdb.Defaults - } +func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) { // Check root availability and state contents - state, err := New(root, NewDatabaseWithConfig(db, &config), nil) + state, err := New(root, NewDatabase(db), nil) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } - if err := checkStateConsistency(db, scheme, root); err != nil { + if err := checkStateConsistency(db, root); err != nil { t.Fatalf("inconsistent state trie at %x: %v", root, err) } for i, acc := range accounts { @@ -113,12 +101,8 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com } // checkStateConsistency checks that all data of a state root is present. -func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) error { - config := &trie.Config{Preimages: true} - if scheme == rawdb.PathScheme { - config.PathDB = pathdb.Defaults - } - state, err := New(root, NewDatabaseWithConfig(db, config), nil) +func checkStateConsistency(db ethdb.Database, root common.Hash) error { + state, err := New(root, NewDatabaseWithConfig(db, &trie.Config{Preimages: true}), nil) if err != nil { return err } @@ -130,14 +114,8 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { - dbA := trie.NewDatabase(rawdb.NewMemoryDatabase(), nil) - dbB := trie.NewDatabase(rawdb.NewMemoryDatabase(), &trie.Config{PathDB: pathdb.Defaults}) - - sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbA.Scheme()) - if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { - t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) - } - sync = NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, dbB.Scheme()) + db := trie.NewDatabase(rawdb.NewMemoryDatabase()) + sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, db.Scheme()) if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes) } @@ -146,28 +124,22 @@ func TestEmptyStateSync(t *testing.T) { // Tests that given a root hash, a state can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go. func TestIterativeStateSyncIndividual(t *testing.T) { - testIterativeStateSync(t, 1, false, false, rawdb.HashScheme) - testIterativeStateSync(t, 1, false, false, rawdb.PathScheme) + testIterativeStateSync(t, 1, false, false) } func TestIterativeStateSyncBatched(t *testing.T) { - testIterativeStateSync(t, 100, false, false, rawdb.HashScheme) - testIterativeStateSync(t, 100, false, false, rawdb.PathScheme) + testIterativeStateSync(t, 100, false, false) } func TestIterativeStateSyncIndividualFromDisk(t *testing.T) { - testIterativeStateSync(t, 1, true, false, rawdb.HashScheme) - testIterativeStateSync(t, 1, true, false, rawdb.PathScheme) + testIterativeStateSync(t, 1, true, false) } func TestIterativeStateSyncBatchedFromDisk(t *testing.T) { - testIterativeStateSync(t, 100, true, false, rawdb.HashScheme) - testIterativeStateSync(t, 100, true, false, rawdb.PathScheme) + testIterativeStateSync(t, 100, true, false) } func TestIterativeStateSyncIndividualByPath(t *testing.T) { - testIterativeStateSync(t, 1, false, true, rawdb.HashScheme) - testIterativeStateSync(t, 1, false, true, rawdb.PathScheme) + testIterativeStateSync(t, 1, false, true) } func TestIterativeStateSyncBatchedByPath(t *testing.T) { - testIterativeStateSync(t, 100, false, true, rawdb.HashScheme) - testIterativeStateSync(t, 100, false, true, rawdb.PathScheme) + testIterativeStateSync(t, 100, false, true) } // stateElement represents the element in the state trie(bytecode or trie node). @@ -178,17 +150,17 @@ type stateElement struct { syncPath trie.SyncPath } -func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, scheme string) { +func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) { // Create a random state to copy - srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() if commit { - ndb.Commit(srcRoot, false) + srcDb.TrieDB().Commit(srcRoot, false) } - srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), ndb) + srcTrie, _ := trie.New(trie.StateTrieID(srcRoot), srcDb.TrieDB()) // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( nodeElements []stateElement @@ -203,11 +175,9 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s }) } for i := 0; i < len(codes); i++ { - codeElements = append(codeElements, stateElement{code: codes[i]}) - } - reader, err := ndb.Reader(srcRoot) - if err != nil { - t.Fatalf("state is not existent, %#x", srcRoot) + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) } for len(nodeElements)+len(codeElements) > 0 { var ( @@ -235,7 +205,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) } id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) - stTrie, err := trie.New(id, ndb) + stTrie, err := trie.New(id, srcDb.TrieDB()) if err != nil { t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) } @@ -246,8 +216,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} } } else { - owner, inner := trie.ResolvePath([]byte(node.path)) - data, err := reader.Node(owner, inner, node.hash) + data, err := srcDb.TrieDB().Node(node.hash) if err != nil { t.Fatalf("failed to retrieve node data for key %v", []byte(node.path)) } @@ -291,23 +260,18 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s copyPreimages(srcDisk, dstDb) // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned, and the others sent only later. func TestIterativeDelayedStateSync(t *testing.T) { - testIterativeDelayedStateSync(t, rawdb.HashScheme) - testIterativeDelayedStateSync(t, rawdb.PathScheme) -} - -func testIterativeDelayedStateSync(t *testing.T, scheme string) { // Create a random state to copy - srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( nodeElements []stateElement @@ -322,11 +286,9 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { }) } for i := 0; i < len(codes); i++ { - codeElements = append(codeElements, stateElement{code: codes[i]}) - } - reader, err := ndb.Reader(srcRoot) - if err != nil { - t.Fatalf("state is not existent, %#x", srcRoot) + codeElements = append(codeElements, stateElement{ + code: codes[i], + }) } for len(nodeElements)+len(codeElements) > 0 { // Sync only half of the scheduled nodes @@ -351,8 +313,7 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { if len(nodeElements) > 0 { nodeResults := make([]trie.NodeSyncResult, len(nodeElements)/2+1) for i, element := range nodeElements[:len(nodeResults)] { - owner, inner := trie.ResolvePath([]byte(element.path)) - data, err := reader.Node(owner, inner, element.hash) + data, err := srcDb.TrieDB().Node(element.hash) if err != nil { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } @@ -392,28 +353,22 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { copyPreimages(srcDisk, dstDb) // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } // Tests that given a root hash, a trie can sync iteratively on a single thread, // requesting retrieval tasks and returning all of them in one go, however in a // random order. -func TestIterativeRandomStateSyncIndividual(t *testing.T) { - testIterativeRandomStateSync(t, 1, rawdb.HashScheme) - testIterativeRandomStateSync(t, 1, rawdb.PathScheme) -} -func TestIterativeRandomStateSyncBatched(t *testing.T) { - testIterativeRandomStateSync(t, 100, rawdb.HashScheme) - testIterativeRandomStateSync(t, 100, rawdb.PathScheme) -} +func TestIterativeRandomStateSyncIndividual(t *testing.T) { testIterativeRandomStateSync(t, 1) } +func TestIterativeRandomStateSyncBatched(t *testing.T) { testIterativeRandomStateSync(t, 100) } -func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { +func testIterativeRandomStateSync(t *testing.T, count int) { // Create a random state to copy - srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -428,10 +383,6 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { for _, hash := range codes { codeQueue[hash] = struct{}{} } - reader, err := ndb.Reader(srcRoot) - if err != nil { - t.Fatalf("state is not existent, %#x", srcRoot) - } for len(nodeQueue)+len(codeQueue) > 0 { // Fetch all the queued nodes in a random order if len(codeQueue) > 0 { @@ -452,8 +403,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { if len(nodeQueue) > 0 { results := make([]trie.NodeSyncResult, 0, len(nodeQueue)) for path, element := range nodeQueue { - owner, inner := trie.ResolvePath([]byte(element.path)) - data, err := reader.Node(owner, inner, element.hash) + data, err := srcDb.TrieDB().Node(element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x %v %v", element.hash, []byte(element.path), element.path) } @@ -465,6 +415,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { } } } + // Feed the retrieved results back and queue new tasks batch := dstDb.NewBatch() if err := sched.Commit(batch); err != nil { t.Fatalf("failed to commit data: %v", err) @@ -490,23 +441,18 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { copyPreimages(srcDisk, dstDb) // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } // Tests that the trie scheduler can correctly reconstruct the state even if only // partial results are returned (Even those randomly), others sent only later. func TestIterativeRandomDelayedStateSync(t *testing.T) { - testIterativeRandomDelayedStateSync(t, rawdb.HashScheme) - testIterativeRandomDelayedStateSync(t, rawdb.PathScheme) -} - -func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { // Create a random state to copy - srcDisk, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) + srcDisk, srcDb, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) nodeQueue := make(map[string]stateElement) codeQueue := make(map[common.Hash]struct{}) @@ -521,10 +467,6 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { for _, hash := range codes { codeQueue[hash] = struct{}{} } - reader, err := ndb.Reader(srcRoot) - if err != nil { - t.Fatalf("state is not existent, %#x", srcRoot) - } for len(nodeQueue)+len(codeQueue) > 0 { // Sync only half of the scheduled nodes, even those in random order if len(codeQueue) > 0 { @@ -553,8 +495,7 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { for path, element := range nodeQueue { delete(nodeQueue, path) - owner, inner := trie.ResolvePath([]byte(element.path)) - data, err := reader.Node(owner, inner, element.hash) + data, err := srcDb.TrieDB().Node(element.hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", element.hash) } @@ -594,19 +535,14 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { copyPreimages(srcDisk, dstDb) // Cross check that the two states are in sync - checkStateAccounts(t, dstDb, ndb.Scheme(), srcRoot, srcAccounts) + checkStateAccounts(t, dstDb, srcRoot, srcAccounts) } // Tests that at any point in time during a sync, only complete sub-tries are in // the database. func TestIncompleteStateSync(t *testing.T) { - testIncompleteStateSync(t, rawdb.HashScheme) - testIncompleteStateSync(t, rawdb.PathScheme) -} - -func testIncompleteStateSync(t *testing.T, scheme string) { // Create a random state to copy - db, srcDb, ndb, srcRoot, srcAccounts := makeTestState(scheme) + db, srcDb, srcRoot, srcAccounts := makeTestState() // isCodeLookup to save some hashing var isCode = make(map[common.Hash]struct{}) @@ -619,14 +555,14 @@ func testIncompleteStateSync(t *testing.T, scheme string) { // Create a destination state and sync with the scheduler dstDb := rawdb.NewMemoryDatabase() - sched := NewStateSync(srcRoot, dstDb, nil, ndb.Scheme()) + sched := NewStateSync(srcRoot, dstDb, nil, srcDb.TrieDB().Scheme()) var ( addedCodes []common.Hash addedPaths []string addedHashes []common.Hash ) - reader, err := ndb.Reader(srcRoot) + reader, err := srcDb.TrieDB().Reader(srcRoot) if err != nil { t.Fatalf("state is not available %x", srcRoot) } @@ -713,11 +649,12 @@ func testIncompleteStateSync(t *testing.T, scheme string) { for _, node := range addedCodes { val := rawdb.ReadCode(dstDb, node) rawdb.DeleteCode(dstDb, node) - if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil { + if err := checkStateConsistency(dstDb, srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %x", node) } rawdb.WriteCode(dstDb, node, val) } + scheme := srcDb.TrieDB().Scheme() for i, path := range addedPaths { owner, inner := trie.ResolvePath([]byte(path)) hash := addedHashes[i] @@ -726,7 +663,7 @@ func testIncompleteStateSync(t *testing.T, scheme string) { t.Error("missing trie node") } rawdb.DeleteTrieNode(dstDb, owner, inner, hash, scheme) - if err := checkStateConsistency(dstDb, scheme, srcRoot); err == nil { + if err := checkStateConsistency(dstDb, srcRoot); err == nil { t.Errorf("trie inconsistency not caught, missing: %v", path) } rawdb.WriteTrieNode(dstDb, owner, inner, hash, val, scheme) diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index d2a98ed7bf..c5b9f690d8 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -39,7 +39,7 @@ func TestDeriveSha(t *testing.T) { t.Fatal(err) } for len(txs) < 1000 { - exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(txs, trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("%d txs: got %x exp %x", len(txs), got, exp) @@ -86,7 +86,7 @@ func BenchmarkDeriveSha200(b *testing.B) { b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp = types.DeriveSha(txs, trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) } }) @@ -107,7 +107,7 @@ func TestFuzzDeriveSha(t *testing.T) { rndSeed := mrand.Int() for i := 0; i < 10; i++ { seed := rndSeed + i - exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(newDummy(i), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { printList(newDummy(seed)) @@ -135,7 +135,7 @@ func TestDerivableList(t *testing.T) { }, } for i, tc := range tcs[1:] { - exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil))) + exp := types.DeriveSha(flatList(tc), trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase()))) got := types.DeriveSha(flatList(tc), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { t.Fatalf("case %d: got %x exp %x", i, got, exp) diff --git a/eth/api_backend.go b/eth/api_backend.go index 235925a7f2..f096e86d06 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -418,7 +418,7 @@ func (b *EthAPIBackend) StartMining() error { } func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) { - return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) + return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk) } func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) { diff --git a/eth/api_debug.go b/eth/api_debug.go index 6afa046787..9cfa9103fb 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -322,7 +322,7 @@ func (api *DebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]c if startBlock.Number().Uint64() >= endBlock.Number().Uint64() { return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64()) } - triedb := api.eth.BlockChain().TrieDB() + triedb := api.eth.BlockChain().StateCache().TrieDB() oldTrie, err := trie.NewStateTrie(trie.StateTrieID(startBlock.Root()), triedb) if err != nil { diff --git a/eth/backend.go b/eth/backend.go index 38c0fa9743..667200bced 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -133,11 +133,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if err != nil { return nil, err } - // Try to recover offline state pruning only in hash-based. - if config.StateScheme == rawdb.HashScheme { - if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil { - log.Error("Failed to recover state", "error", err) - } + if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil { + log.Error("Failed to recover state", "error", err) } // Transfer mining-related config to the ethash config. chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) @@ -164,6 +161,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { p2pServer: stack.Server(), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } + bcVersion := rawdb.ReadDatabaseVersion(chainDb) var dbVer = "" if bcVersion != nil { @@ -193,8 +191,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { TrieTimeLimit: config.TrieTimeout, SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: config.StateScheme, } ) // Override the chain config with provided settings. @@ -205,7 +201,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TransactionHistory) + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) if err != nil { return nil, err } @@ -442,7 +438,7 @@ func (s *Ethereum) StartMining() error { } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. - s.handler.enableSyncedFeatures() + s.handler.acceptTxs.Store(true) go s.miner.Start() } @@ -475,7 +471,7 @@ func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } func (s *Ethereum) Synced() bool { return s.handler.acceptTxs.Load() } -func (s *Ethereum) SetSynced() { s.handler.enableSyncedFeatures() } +func (s *Ethereum) SetSynced() { s.handler.acceptTxs.Store(true) } func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } func (s *Ethereum) Merger() *consensus.Merger { return s.merger } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 1bf03411d1..d791723b05 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" ) // Test chain parameters. @@ -44,7 +43,7 @@ var ( Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - testGenesis = testGspec.MustCommit(testDB, trie.NewDatabase(testDB, trie.HashDefaults)) + testGenesis = testGspec.MustCommit(testDB) ) // The common prefix of all test chains: diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 55441a2cb9..4bc8b8dc6c 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -27,7 +27,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth/downloader" @@ -62,9 +61,6 @@ var Defaults = Config{ SyncMode: downloader.SnapSync, NetworkId: 1, TxLookupLimit: 2350000, - TransactionHistory: 2350000, - StateHistory: params.FullImmutabilityThreshold, - StateScheme: rawdb.HashScheme, LightPeers: 100, DatabaseCache: 512, TrieCleanCache: 154, @@ -101,11 +97,7 @@ type Config struct { NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - // Deprecated, use 'TransactionHistory' instead. - TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. - TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. - StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved. - StateScheme string `toml:",omitempty"` // State scheme used to store ethereum state and merkle trie nodes on top + TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. // RequiredBlocks is a set of block number -> hash mappings which must be in the // canonical chain of all remote peers. Setting the option makes geth verify the diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 2abddc9e0d..324fbe380e 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -25,9 +25,6 @@ func (c Config) MarshalTOML() (interface{}, error) { NoPruning bool NoPrefetch bool TxLookupLimit uint64 `toml:",omitempty"` - TransactionHistory uint64 `toml:",omitempty"` - StateHistory uint64 `toml:",omitempty"` - StateScheme string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` LightServ int `toml:",omitempty"` LightIngress int `toml:",omitempty"` @@ -66,9 +63,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.NoPruning = c.NoPruning enc.NoPrefetch = c.NoPrefetch enc.TxLookupLimit = c.TxLookupLimit - enc.TransactionHistory = c.TransactionHistory - enc.StateHistory = c.StateHistory - enc.StateScheme = c.StateScheme enc.RequiredBlocks = c.RequiredBlocks enc.LightServ = c.LightServ enc.LightIngress = c.LightIngress @@ -111,9 +105,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { NoPruning *bool NoPrefetch *bool TxLookupLimit *uint64 `toml:",omitempty"` - TransactionHistory *uint64 `toml:",omitempty"` - StateHistory *uint64 `toml:",omitempty"` - StateScheme *string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` LightServ *int `toml:",omitempty"` LightIngress *int `toml:",omitempty"` @@ -171,15 +162,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.TxLookupLimit != nil { c.TxLookupLimit = *dec.TxLookupLimit } - if dec.TransactionHistory != nil { - c.TransactionHistory = *dec.TransactionHistory - } - if dec.StateHistory != nil { - c.StateHistory = *dec.StateHistory - } - if dec.StateScheme != nil { - c.StateScheme = *dec.StateScheme - } if dec.RequiredBlocks != nil { c.RequiredBlocks = dec.RequiredBlocks } diff --git a/eth/fetcher/block_fetcher_test.go b/eth/fetcher/block_fetcher_test.go index 7c490df3f7..6d8516fa6a 100644 --- a/eth/fetcher/block_fetcher_test.go +++ b/eth/fetcher/block_fetcher_test.go @@ -44,7 +44,7 @@ var ( Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - genesis = gspec.MustCommit(testdb, trie.NewDatabase(testdb, trie.HashDefaults)) + genesis = gspec.MustCommit(testdb) unknownBlock = types.NewBlock(&types.Header{Root: types.EmptyRootHash, GasLimit: params.GenesisGasLimit, BaseFee: big.NewInt(params.InitialBaseFee)}, nil, nil, nil, trie.NewStackTrie(nil)) ) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index a076fb7377..8eea0a2678 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -86,7 +86,7 @@ func BenchmarkFilters(b *testing.B) { // The test txs are not properly signed, can't simply create a chain // and then import blocks. TODO(rjl493456442) try to get rid of the // manual database writes. - gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + gspec.MustCommit(db) for i, block := range chain { rawdb.WriteBlock(db, block) @@ -180,7 +180,7 @@ func TestFilters(t *testing.T) { // Hack: GenerateChainWithGenesis creates a new db. // Commit the genesis manually and use GenerateChain. - _, err = gspec.Commit(db, trie.NewDatabase(db, nil)) + _, err = gspec.Commit(db, trie.NewDatabase(db)) if err != nil { t.Fatal(err) } diff --git a/eth/handler.go b/eth/handler.go index 84a2788932..2453c08afb 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/forkid" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" @@ -41,7 +40,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) const ( @@ -185,7 +183,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } // If we've successfully finished a sync cycle, accept transactions from // the network - h.enableSyncedFeatures() + h.acceptTxs.Store(true) } // Construct the downloader (long sync) h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, success) @@ -274,7 +272,7 @@ func newHandler(config *handlerConfig) (*handler, error) { } n, err := h.chain.InsertChain(blocks) if err == nil { - h.enableSyncedFeatures() // Mark initial sync done on any fetcher import + h.acceptTxs.Store(true) // Mark initial sync done on any fetcher import } return n, err } @@ -676,12 +674,3 @@ func (h *handler) txBroadcastLoop() { } } } - -// enableSyncedFeatures enables the post-sync functionalities when the initial -// sync is finished. -func (h *handler) enableSyncedFeatures() { - h.acceptTxs.Store(true) - if h.chain.TrieDB().Scheme() == rawdb.PathScheme { - h.chain.TrieDB().SetBufferSize(pathdb.DefaultBufferSize) - } -} diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index bf2874721a..3f1dc9fe76 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -112,7 +112,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, panic(err) } for _, block := range bs { - chain.TrieDB().Commit(block.Root(), false) + chain.StateCache().TrieDB().Commit(block.Root(), false) } txconfig := legacypool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index cdac0da21a..f9fbf72b7b 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -22,7 +22,6 @@ 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/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -247,10 +246,6 @@ func handleGetNodeData66(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetNodeDataQuery assembles the response to a node data query. It is // exposed to allow external packages to test protocol behavior. func ServiceGetNodeDataQuery(chain *core.BlockChain, query GetNodeDataPacket) [][]byte { - // Request nodes by hash is not supported in path-based scheme. - if chain.TrieDB().Scheme() == rawdb.PathScheme { - return nil - } // Gather state data until the fetch or network limits is reached var ( bytes int @@ -262,7 +257,7 @@ func ServiceGetNodeDataQuery(chain *core.BlockChain, query GetNodeDataPacket) [] break } // Retrieve the requested state entry - entry, err := chain.TrieDB().Node(hash) + entry, err := chain.TrieNode(hash) if len(entry) == 0 || err != nil { // Read the contract code with prefix only to save unnecessary lookups. entry, err = chain.ContractCodeWithPrefix(hash) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index b2fd03766e..1c6d80d354 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -284,7 +284,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac req.Bytes = softResponseLimit } // Retrieve the requested state and bail out if non existent - tr, err := trie.New(trie.StateTrieID(req.Root), chain.TrieDB()) + tr, err := trie.New(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -414,7 +414,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP if origin != (common.Hash{}) || (abort && len(storage) > 0) { // Request started at a non-zero hash or was capped prematurely, add // the endpoint Merkle proofs - accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), chain.TrieDB()) + accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -423,7 +423,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP return nil, nil } id := trie.StorageTrieID(req.Root, account, acc.Root) - stTrie, err := trie.NewStateTrie(id, chain.TrieDB()) + stTrie, err := trie.NewStateTrie(id, chain.StateCache().TrieDB()) if err != nil { return nil, nil } @@ -487,7 +487,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s req.Bytes = softResponseLimit } // Make sure we have the state associated with the request - triedb := chain.TrieDB() + triedb := chain.StateCache().TrieDB() accTrie, err := trie.NewStateTrie(trie.StateTrieID(req.Root), triedb) if err != nil { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 8b09cd8c84..79b1cad25b 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" "golang.org/x/exp/slices" @@ -562,11 +561,6 @@ func noProofStorageRequestHandler(t *testPeer, requestId uint64, root common.Has func TestSyncBloatedProof(t *testing.T) { t.Parallel() - testSyncBloatedProof(t, rawdb.HashScheme) - testSyncBloatedProof(t, rawdb.PathScheme) -} - -func testSyncBloatedProof(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -576,7 +570,7 @@ func testSyncBloatedProof(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) source := newTestPeer("source", t, term) source.accountTrie = sourceAccountTrie.Copy() source.accountValues = elems @@ -644,11 +638,6 @@ func setupSyncer(scheme string, peers ...*testPeer) *Syncer { func TestSync(t *testing.T) { t.Parallel() - testSync(t, rawdb.HashScheme) - testSync(t, rawdb.PathScheme) -} - -func testSync(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -658,7 +647,7 @@ func testSync(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -670,7 +659,7 @@ func testSync(t *testing.T, scheme string) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncTinyTriePanic tests a basic sync with one peer, and a tiny trie. This caused a @@ -678,11 +667,6 @@ func testSync(t *testing.T, scheme string) { func TestSyncTinyTriePanic(t *testing.T) { t.Parallel() - testSyncTinyTriePanic(t, rawdb.HashScheme) - testSyncTinyTriePanic(t, rawdb.PathScheme) -} - -func testSyncTinyTriePanic(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -692,7 +676,7 @@ func testSyncTinyTriePanic(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(1, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(1) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -706,18 +690,13 @@ func testSyncTinyTriePanic(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSync tests a basic sync with multiple peers func TestMultiSync(t *testing.T) { t.Parallel() - testMultiSync(t, rawdb.HashScheme) - testMultiSync(t, rawdb.PathScheme) -} - -func testMultiSync(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -727,7 +706,7 @@ func testMultiSync(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -741,18 +720,13 @@ func testMultiSync(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorage tests basic sync using accounts + storage + code func TestSyncWithStorage(t *testing.T) { t.Parallel() - testSyncWithStorage(t, rawdb.HashScheme) - testSyncWithStorage(t, rawdb.PathScheme) -} - -func testSyncWithStorage(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -762,7 +736,7 @@ func testSyncWithStorage(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 3, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(3, 3000, true, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -778,18 +752,13 @@ func testSyncWithStorage(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUseless contains one good peer, and many which doesn't return anything valuable at all func TestMultiSyncManyUseless(t *testing.T) { t.Parallel() - testMultiSyncManyUseless(t, rawdb.HashScheme) - testMultiSyncManyUseless(t, rawdb.PathScheme) -} - -func testMultiSyncManyUseless(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -799,7 +768,7 @@ func testMultiSyncManyUseless(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -832,18 +801,11 @@ func testMultiSyncManyUseless(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUseless contains one good peer, and many which doesn't return anything valuable at all func TestMultiSyncManyUselessWithLowTimeout(t *testing.T) { - t.Parallel() - - testMultiSyncManyUselessWithLowTimeout(t, rawdb.HashScheme) - testMultiSyncManyUselessWithLowTimeout(t, rawdb.PathScheme) -} - -func testMultiSyncManyUselessWithLowTimeout(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -853,7 +815,7 @@ func testMultiSyncManyUselessWithLowTimeout(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -891,18 +853,11 @@ func testMultiSyncManyUselessWithLowTimeout(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestMultiSyncManyUnresponsive contains one good peer, and many which doesn't respond at all func TestMultiSyncManyUnresponsive(t *testing.T) { - t.Parallel() - - testMultiSyncManyUnresponsive(t, rawdb.HashScheme) - testMultiSyncManyUnresponsive(t, rawdb.PathScheme) -} - -func testMultiSyncManyUnresponsive(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -912,7 +867,7 @@ func testMultiSyncManyUnresponsive(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, noAccount, noStorage, noTrieNode bool) *testPeer { source := newTestPeer(name, t, term) @@ -948,7 +903,7 @@ func testMultiSyncManyUnresponsive(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } func checkStall(t *testing.T, term func()) chan struct{} { @@ -970,11 +925,6 @@ func checkStall(t *testing.T, term func()) chan struct{} { func TestSyncBoundaryAccountTrie(t *testing.T) { t.Parallel() - testSyncBoundaryAccountTrie(t, rawdb.HashScheme) - testSyncBoundaryAccountTrie(t, rawdb.PathScheme) -} - -func testSyncBoundaryAccountTrie(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -984,7 +934,7 @@ func testSyncBoundaryAccountTrie(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeBoundaryAccountTrie(scheme, 3000) + nodeScheme, sourceAccountTrie, elems := makeBoundaryAccountTrie(3000) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1002,7 +952,7 @@ func testSyncBoundaryAccountTrie(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCappedPeer tests sync using accounts and no storage, where one peer is @@ -1010,11 +960,6 @@ func testSyncBoundaryAccountTrie(t *testing.T, scheme string) { func TestSyncNoStorageAndOneCappedPeer(t *testing.T) { t.Parallel() - testSyncNoStorageAndOneCappedPeer(t, rawdb.HashScheme) - testSyncNoStorageAndOneCappedPeer(t, rawdb.PathScheme) -} - -func testSyncNoStorageAndOneCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1024,7 +969,7 @@ func testSyncNoStorageAndOneCappedPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) @@ -1049,7 +994,7 @@ func testSyncNoStorageAndOneCappedPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCodeCorruptPeer has one peer which doesn't deliver @@ -1057,11 +1002,6 @@ func testSyncNoStorageAndOneCappedPeer(t *testing.T, scheme string) { func TestSyncNoStorageAndOneCodeCorruptPeer(t *testing.T) { t.Parallel() - testSyncNoStorageAndOneCodeCorruptPeer(t, rawdb.HashScheme) - testSyncNoStorageAndOneCodeCorruptPeer(t, rawdb.PathScheme) -} - -func testSyncNoStorageAndOneCodeCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1071,7 +1011,7 @@ func testSyncNoStorageAndOneCodeCorruptPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1094,17 +1034,12 @@ func testSyncNoStorageAndOneCodeCorruptPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } func TestSyncNoStorageAndOneAccountCorruptPeer(t *testing.T) { t.Parallel() - testSyncNoStorageAndOneAccountCorruptPeer(t, rawdb.HashScheme) - testSyncNoStorageAndOneAccountCorruptPeer(t, rawdb.PathScheme) -} - -func testSyncNoStorageAndOneAccountCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1114,7 +1049,7 @@ func testSyncNoStorageAndOneAccountCorruptPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, accFn accountHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1137,7 +1072,7 @@ func testSyncNoStorageAndOneAccountCorruptPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncNoStorageAndOneCodeCappedPeer has one peer which delivers code hashes @@ -1145,11 +1080,6 @@ func testSyncNoStorageAndOneAccountCorruptPeer(t *testing.T, scheme string) { func TestSyncNoStorageAndOneCodeCappedPeer(t *testing.T) { t.Parallel() - testSyncNoStorageAndOneCodeCappedPeer(t, rawdb.HashScheme) - testSyncNoStorageAndOneCodeCappedPeer(t, rawdb.PathScheme) -} - -func testSyncNoStorageAndOneCodeCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1159,7 +1089,7 @@ func testSyncNoStorageAndOneCodeCappedPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(3000) mkSource := func(name string, codeFn codeHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1193,7 +1123,7 @@ func testSyncNoStorageAndOneCodeCappedPeer(t *testing.T, scheme string) { if threshold := 100; counter > threshold { t.Logf("Error, expected < %d invocations, got %d", threshold, counter) } - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncBoundaryStorageTrie tests sync against a few normal peers, but the @@ -1201,11 +1131,6 @@ func testSyncNoStorageAndOneCodeCappedPeer(t *testing.T, scheme string) { func TestSyncBoundaryStorageTrie(t *testing.T) { t.Parallel() - testSyncBoundaryStorageTrie(t, rawdb.HashScheme) - testSyncBoundaryStorageTrie(t, rawdb.PathScheme) -} - -func testSyncBoundaryStorageTrie(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1215,7 +1140,7 @@ func testSyncBoundaryStorageTrie(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 10, 1000, false, true) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(10, 1000, false, true) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1235,7 +1160,7 @@ func testSyncBoundaryStorageTrie(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorageAndOneCappedPeer tests sync using accounts + storage, where one peer is @@ -1243,11 +1168,6 @@ func testSyncBoundaryStorageTrie(t *testing.T, scheme string) { func TestSyncWithStorageAndOneCappedPeer(t *testing.T) { t.Parallel() - testSyncWithStorageAndOneCappedPeer(t, rawdb.HashScheme) - testSyncWithStorageAndOneCappedPeer(t, rawdb.PathScheme) -} - -func testSyncWithStorageAndOneCappedPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1257,7 +1177,7 @@ func testSyncWithStorageAndOneCappedPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 300, 1000, false, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(300, 1000, false, false) mkSource := func(name string, slow bool) *testPeer { source := newTestPeer(name, t, term) @@ -1282,7 +1202,7 @@ func testSyncWithStorageAndOneCappedPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorageAndCorruptPeer tests sync using accounts + storage, where one peer is @@ -1290,11 +1210,6 @@ func testSyncWithStorageAndOneCappedPeer(t *testing.T, scheme string) { func TestSyncWithStorageAndCorruptPeer(t *testing.T) { t.Parallel() - testSyncWithStorageAndCorruptPeer(t, rawdb.HashScheme) - testSyncWithStorageAndCorruptPeer(t, rawdb.PathScheme) -} - -func testSyncWithStorageAndCorruptPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1304,7 +1219,7 @@ func testSyncWithStorageAndCorruptPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1328,17 +1243,12 @@ func testSyncWithStorageAndCorruptPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } func TestSyncWithStorageAndNonProvingPeer(t *testing.T) { t.Parallel() - testSyncWithStorageAndNonProvingPeer(t, rawdb.HashScheme) - testSyncWithStorageAndNonProvingPeer(t, rawdb.PathScheme) -} - -func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1348,7 +1258,7 @@ func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(scheme, 100, 3000, true, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorage(100, 3000, true, false) mkSource := func(name string, handler storageHandlerFunc) *testPeer { source := newTestPeer(name, t, term) @@ -1371,7 +1281,7 @@ func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { t.Fatalf("sync failed: %v", err) } close(done) - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } // TestSyncWithStorage tests basic sync using accounts + storage + code, against @@ -1380,12 +1290,6 @@ func testSyncWithStorageAndNonProvingPeer(t *testing.T, scheme string) { // did not mark the account for healing. func TestSyncWithStorageMisbehavingProve(t *testing.T) { t.Parallel() - - testSyncWithStorageMisbehavingProve(t, rawdb.HashScheme) - testSyncWithStorageMisbehavingProve(t, rawdb.PathScheme) -} - -func testSyncWithStorageMisbehavingProve(t *testing.T, scheme string) { var ( once sync.Once cancel = make(chan struct{}) @@ -1395,7 +1299,7 @@ func testSyncWithStorageMisbehavingProve(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(scheme, 10, 30, false) + nodeScheme, sourceAccountTrie, elems, storageTries, storageElems := makeAccountTrieWithStorageWithUniqueStorage(10, 30, false) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1410,7 +1314,7 @@ func testSyncWithStorageMisbehavingProve(t *testing.T, scheme string) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) } type kv struct { @@ -1460,9 +1364,9 @@ func getCodeByHash(hash common.Hash) []byte { } // makeAccountTrieNoStorage spits out a trie, along with the leafs -func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) { +func makeAccountTrieNoStorage(n int) (string, *trie.Trie, []*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) entries []*kv ) @@ -1492,12 +1396,12 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) // makeBoundaryAccountTrie constructs an account trie. Instead of filling // accounts normally, this function will fill a few accounts which have // boundary hash. -func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) { +func makeBoundaryAccountTrie(n int) (string, *trie.Trie, []*kv) { var ( entries []*kv boundaries []common.Hash - db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) ) // Initialize boundaries @@ -1553,9 +1457,9 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) { // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts // has a unique storage set. -func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots int, code bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { +func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) entries []*kv storageRoots = make(map[common.Hash]common.Hash) @@ -1608,9 +1512,9 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots } // makeAccountTrieWithStorage spits out a trie, along with the leafs -func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, boundary bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { +func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { var ( - db = trie.NewDatabase(rawdb.NewMemoryDatabase(), newDbConfig(scheme)) + db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) entries []*kv storageRoots = make(map[common.Hash]common.Hash) @@ -1752,9 +1656,9 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo return root, nodes, entries } -func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *testing.T) { +func verifyTrie(db ethdb.KeyValueStore, root common.Hash, t *testing.T) { t.Helper() - triedb := trie.NewDatabase(rawdb.NewDatabase(db), newDbConfig(scheme)) + triedb := trie.NewDatabase(rawdb.NewDatabase(db)) accTrie, err := trie.New(trie.StateTrieID(root), triedb) if err != nil { t.Fatal(err) @@ -1796,13 +1700,6 @@ func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *test // TestSyncAccountPerformance tests how efficient the snap algo is at minimizing // state healing func TestSyncAccountPerformance(t *testing.T) { - t.Parallel() - - testSyncAccountPerformance(t, rawdb.HashScheme) - testSyncAccountPerformance(t, rawdb.PathScheme) -} - -func testSyncAccountPerformance(t *testing.T, scheme string) { // Set the account concurrency to 1. This _should_ result in the // range root to become correct, and there should be no healing needed defer func(old int) { accountConcurrency = old }(accountConcurrency) @@ -1817,7 +1714,7 @@ func testSyncAccountPerformance(t *testing.T, scheme string) { }) } ) - nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100, scheme) + nodeScheme, sourceAccountTrie, elems := makeAccountTrieNoStorage(100) mkSource := func(name string) *testPeer { source := newTestPeer(name, t, term) @@ -1830,7 +1727,7 @@ func testSyncAccountPerformance(t *testing.T, scheme string) { if err := syncer.Sync(sourceAccountTrie.Hash(), cancel); err != nil { t.Fatalf("sync failed: %v", err) } - verifyTrie(scheme, syncer.db, sourceAccountTrie.Hash(), t) + verifyTrie(syncer.db, sourceAccountTrie.Hash(), t) // The trie root will always be requested, since it is added when the snap // sync cycle starts. When popping the queue, we do not look it up again. // Doing so would bring this number down to zero in this artificial testcase, @@ -1890,10 +1787,3 @@ func TestSlotEstimation(t *testing.T) { } } } - -func newDbConfig(scheme string) *trie.Config { - if scheme == rawdb.HashScheme { - return &trie.Config{} - } - return &trie.Config{PathDB: pathdb.Defaults} -} diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 7418a92372..a725585e71 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -24,7 +24,6 @@ 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/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -37,11 +36,31 @@ import ( // for releasing state. var noopReleaser = tracers.StateReleaseFunc(func() {}) -func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { +// StateAtBlock retrieves the state database associated with a certain block. +// If no state is locally available for the given block, a number of blocks +// are attempted to be reexecuted to generate the desired state. The optional +// base layer statedb can be provided which is regarded as the statedb of the +// parent block. +// +// An additional release function will be returned if the requested state is +// available. Release is expected to be invoked when the returned state is no longer needed. +// Its purpose is to prevent resource leaking. Though it can be noop in some cases. +// +// Parameters: +// - block: The block for which we want the state(state = block.Root) +// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state +// - base: If the caller is tracing multiple blocks, the caller can provide the parent +// state continuously from the callsite. +// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should +// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. +// Otherwise, the trash generated by caller may be persisted permanently. +// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is +// provided, it would be preferable to start from a fresh state, if we have it +// on disk. +func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { var ( current *types.Block database state.Database - triedb *trie.Database report = true origin = block.NumberU64() ) @@ -52,9 +71,9 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // on top to prevent garbage collection and return a release // function to deref it. if statedb, err = eth.blockchain.StateAt(block.Root()); err == nil { - eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{}) + statedb.Database().TrieDB().Reference(block.Root(), common.Hash{}) return statedb, func() { - eth.blockchain.TrieDB().Dereference(block.Root()) + statedb.Database().TrieDB().Dereference(block.Root()) }, nil } } @@ -65,16 +84,14 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u if preferDisk { // Create an ephemeral trie.Database for isolating the live one. Otherwise // the internal junks created by tracing will be persisted into the disk. - // TODO(rjl493456442), clean cache is disabled to prevent memory leak, - // please re-enable it for better performance. - database = state.NewDatabaseWithConfig(eth.chainDb, trie.HashDefaults) + database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) if statedb, err = state.New(block.Root(), database, nil); err == nil { log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number()) return statedb, noopReleaser, nil } } // The optional base statedb is given, mark the start point as parent block - statedb, database, triedb, report = base, base.Database(), base.Database().TrieDB(), false + statedb, database, report = base, base.Database(), false current = eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1) } else { // Otherwise, try to reexec blocks until we find a state or reach our limit @@ -82,10 +99,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // Create an ephemeral trie.Database for isolating the live one. Otherwise // the internal junks created by tracing will be persisted into the disk. - // TODO(rjl493456442), clean cache is disabled to prevent memory leak, - // please re-enable it for better performance. - triedb = trie.NewDatabase(eth.chainDb, trie.HashDefaults) - database = state.NewDatabaseWithNodeDB(eth.chainDb, triedb) + database = state.NewDatabaseWithConfig(eth.chainDb, &trie.Config{Cache: 16}) // If we didn't check the live database, do check state over ephemeral database, // otherwise we would rewind past a persisted block (specific corner case is @@ -161,58 +175,17 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u } // Hold the state reference and also drop the parent state // to prevent accumulating too many nodes in memory. - triedb.Reference(root, common.Hash{}) + database.TrieDB().Reference(root, common.Hash{}) if parent != (common.Hash{}) { - triedb.Dereference(parent) + database.TrieDB().Dereference(parent) } parent = root } if report { - nodes, imgs := triedb.Size() + nodes, imgs := database.TrieDB().Size() log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs) } - return statedb, func() { triedb.Dereference(block.Root()) }, nil -} - -func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) { - // Check if the requested state is available in the live chain. - statedb, err := eth.blockchain.StateAt(block.Root()) - if err == nil { - return statedb, noopReleaser, nil - } - // TODO historic state is not supported in path-based scheme. - // Fully archive node in pbss will be implemented by relying - // on state history, but needs more work on top. - return nil, nil, errors.New("historical state not available in path scheme yet") -} - -// stateAtBlock retrieves the state database associated with a certain block. -// If no state is locally available for the given block, a number of blocks -// are attempted to be reexecuted to generate the desired state. The optional -// base layer statedb can be provided which is regarded as the statedb of the -// parent block. -// -// An additional release function will be returned if the requested state is -// available. Release is expected to be invoked when the returned state is no -// longer needed. Its purpose is to prevent resource leaking. Though it can be -// noop in some cases. -// -// Parameters: -// - block: The block for which we want the state(state = block.Root) -// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state -// - base: If the caller is tracing multiple blocks, the caller can provide the parent -// state continuously from the callsite. -// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should -// be made from caller, e.g. perform Commit or other 'save-to-disk' changes. -// Otherwise, the trash generated by caller may be persisted permanently. -// - preferDisk: This arg can be used by the caller to signal that even though the 'base' is -// provided, it would be preferable to start from a fresh state, if we have it -// on disk. -func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) { - if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme { - return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk) - } - return eth.pathState(block) + return statedb, func() { database.TrieDB().Dereference(block.Root()) }, nil } // stateAtTransaction returns the execution environment of a certain transaction. @@ -228,7 +201,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // Lookup the statedb of parent block from the live database, // otherwise regenerate it on the flight. - statedb, release, err := eth.stateAtBlock(ctx, parent, reexec, nil, true, false) + statedb, release, err := eth.StateAtBlock(ctx, parent, reexec, nil, true, false) if err != nil { return nil, vm.BlockContext{}, nil, nil, err } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 6df49a90c1..26c4455e30 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -137,10 +137,8 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, } - triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - triedb.Close() - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) @@ -239,8 +237,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } - triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) - defer triedb.Close() + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) b.ReportAllocs() b.ResetTimer() @@ -366,7 +363,7 @@ func TestInternals(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), core.GenesisAlloc{ to: core.GenesisAccount{ Code: tc.code, @@ -374,9 +371,7 @@ func TestInternals(t *testing.T) { origin: core.GenesisAccount{ Balance: big.NewInt(500000000000000), }, - }, false, rawdb.HashScheme) - defer triedb.Close() - + }, false) evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer}) msg := &core.Message{ To: &to, diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 423167b13c..85e95401a2 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -100,8 +100,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string Difficulty: (*big.Int)(test.Context.Difficulty), GasLimit: uint64(test.Context.GasLimit), } - triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) - defer triedb.Close() + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) // Create the tracer, the EVM environment and run it tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index b4fa5b6272..991da10b3a 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -108,10 +108,8 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { GasLimit: uint64(test.Context.GasLimit), BaseFee: test.Genesis.BaseFee, } - triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, rawdb.HashScheme) + _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - defer triedb.Close() - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index b4989ec984..759e3a4dd3 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -79,9 +79,7 @@ func BenchmarkTransactionTrace(b *testing.B) { Code: []byte{}, Balance: big.NewInt(500000000000000), } - triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme) - defer triedb.Close() - + _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) // Create the tracer, the EVM environment and run it tracer := logger.NewStructLogger(&logger.Config{ Debug: false, diff --git a/internal/flags/categories.go b/internal/flags/categories.go index 487684d98b..ac71931879 100644 --- a/internal/flags/categories.go +++ b/internal/flags/categories.go @@ -22,7 +22,7 @@ const ( EthCategory = "ETHEREUM" LightCategory = "LIGHT CLIENT" DevCategory = "DEVELOPER CHAIN" - StateCategory = "STATE HISTORY MANAGEMENT" + EthashCategory = "ETHASH" TxPoolCategory = "TRANSACTION POOL (EVM)" BlobPoolCategory = "TRANSACTION POOL (BLOB)" PerfCategory = "PERFORMANCE TUNING" diff --git a/les/client.go b/les/client.go index be5e9fd564..132c857aa5 100644 --- a/les/client.go +++ b/les/client.go @@ -98,8 +98,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { if config.OverrideVerkle != nil { overrides.OverrideVerkle = config.OverrideVerkle } - triedb := trie.NewDatabase(chainDb, trie.HashDefaults) - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, triedb, config.Genesis, &overrides) + chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, trie.NewDatabase(chainDb), config.Genesis, &overrides) if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat { return nil, genesisErr } diff --git a/les/handler_test.go b/les/handler_test.go index 26a083f475..81a34a25e8 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -406,7 +406,7 @@ func testGetProofs(t *testing.T, protocol int) { accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}} for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ { header := bc.GetHeaderByNumber(i) - trie, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB()) + trie, _ := trie.New(trie.StateTrieID(header.Root), trie.NewDatabase(server.db)) for _, acc := range accounts { req := ProofReq{ @@ -457,7 +457,7 @@ func testGetStaleProof(t *testing.T, protocol int) { var expected []rlp.RawValue if wantOK { proofsV2 := light.NewNodeSet() - t, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB()) + t, _ := trie.New(trie.StateTrieID(header.Root), trie.NewDatabase(server.db)) t.Prove(account, proofsV2) expected = proofsV2.NodeList() } @@ -513,7 +513,7 @@ func testGetCHTProofs(t *testing.T, protocol int) { AuxData: [][]byte{rlp}, } root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash()) - trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.ChtTablePrefix)), trie.HashDefaults)) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.ChtTablePrefix)))) trie.Prove(key, &proofsV2.Proofs) // Assemble the requests for the different protocols requestsV2 := []HelperTrieReq{{ @@ -578,7 +578,7 @@ func testGetBloombitsProofs(t *testing.T, protocol int) { var proofs HelperTrieResps root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash()) - trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.BloomTrieTablePrefix)), trie.HashDefaults)) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.BloomTrieTablePrefix)))) trie.Prove(key, &proofs.Proofs) // Send the proof request and verify the response diff --git a/les/odr_test.go b/les/odr_test.go index 69824a92dd..853b4ab565 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -104,7 +104,7 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainCon for _, addr := range acc { if bc != nil { header := bc.GetHeaderByHash(bhash) - st, err = state.New(header.Root, bc.StateCache(), nil) + st, err = state.New(header.Root, state.NewDatabase(db), nil) } else { header := lc.GetHeaderByHash(bhash) st = light.NewState(ctx, header, lc.Odr()) diff --git a/les/server_handler.go b/les/server_handler.go index c31cc69cd5..ad18d3f4e4 100644 --- a/les/server_handler.go +++ b/les/server_handler.go @@ -390,8 +390,7 @@ func (h *serverHandler) GetHelperTrie(typ uint, index uint64) *trie.Trie { if root == (common.Hash{}) { return nil } - triedb := trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix), trie.HashDefaults) - trie, _ := trie.New(trie.TrieID(root), triedb) + trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(h.chainDb, prefix))) return trie } diff --git a/les/server_requests.go b/les/server_requests.go index d33bcd8f55..30ff2cd05f 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -303,8 +303,9 @@ func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) { p.bumpInvalid() continue } + triedb := bc.StateCache().TrieDB() address := common.BytesToAddress(request.AccountAddress) - account, err := getAccount(bc.TrieDB(), header.Root, address) + account, err := getAccount(triedb, header.Root, address) if err != nil { p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", address, "err", err) p.bumpInvalid() @@ -423,7 +424,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { default: // Account key specified, open a storage trie address := common.BytesToAddress(request.AccountAddress) - account, err := getAccount(bc.TrieDB(), root, address) + account, err := getAccount(statedb.TrieDB(), root, address) if err != nil { p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", address, "err", err) p.bumpInvalid() diff --git a/les/test_helper.go b/les/test_helper.go index 7cc3dceae0..b03bca14bf 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -49,7 +49,6 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" ) var ( @@ -189,7 +188,7 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index BaseFee: big.NewInt(params.InitialBaseFee), } ) - genesis := gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + genesis := gspec.MustCommit(db) chain, _ := light.NewLightChain(odr, gspec.Config, engine) client := &LightEthereum{ @@ -227,7 +226,7 @@ func newTestServerHandler(blocks int, indexers []*core.ChainIndexer, db ethdb.Da BaseFee: big.NewInt(params.InitialBaseFee), } ) - genesis := gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + genesis := gspec.MustCommit(db) // create a simulation backend and pre-commit several customized block to the database. simulation := backends.NewSimulatedBackendWithDatabase(db, gspec.Alloc, 100000000) diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 5694ca72c2..e3d756f801 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -29,7 +29,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" ) // So we can deterministically seed different blockchains @@ -56,7 +55,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [ func newCanonical(n int) (ethdb.Database, *LightChain, error) { db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} - genesis := gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + genesis := gspec.MustCommit(db) blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) // Create and inject the requested chain @@ -76,7 +75,7 @@ func newTestLightChain() *LightChain { Difficulty: big.NewInt(1), Config: params.TestChainConfig, } - gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults)) + gspec.MustCommit(db) lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker()) if err != nil { panic(err) diff --git a/light/odr_test.go b/light/odr_test.go index d8a7f10675..79f901bbdb 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" ) var ( @@ -283,7 +282,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { t.Fatal(err) } - gspec.MustCommit(ldb, trie.NewDatabase(ldb, trie.HashDefaults)) + gspec.MustCommit(ldb) odr := &testOdr{sdb: sdb, ldb: ldb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} lightchain, err := NewLightChain(odr, gspec.Config, ethash.NewFullFaker()) if err != nil { diff --git a/light/postprocess.go b/light/postprocess.go index 13d75f8617..567814e2bf 100644 --- a/light/postprocess.go +++ b/light/postprocess.go @@ -145,7 +145,7 @@ func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64, dis diskdb: db, odr: odr, trieTable: trieTable, - triedb: trie.NewDatabase(trieTable, trie.HashDefaults), + triedb: trie.NewDatabaseWithConfig(trieTable, &trie.Config{Cache: 1}), // Use a tiny cache only to keep memory down sectionSize: size, disablePruning: disablePruning, } @@ -348,7 +348,7 @@ func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uin diskdb: db, odr: odr, trieTable: trieTable, - triedb: trie.NewDatabase(trieTable, trie.HashDefaults), + triedb: trie.NewDatabaseWithConfig(trieTable, &trie.Config{Cache: 1}), // Use a tiny cache only to keep memory down parentSize: parentSize, size: size, disablePruning: disablePruning, diff --git a/light/trie.go b/light/trie.go index 1847f1e71b..4967cc74e5 100644 --- a/light/trie.go +++ b/light/trie.go @@ -215,8 +215,7 @@ func (t *odrTrie) do(key []byte, fn func() error) error { } else { id = trie.StateTrieID(t.id.StateRoot) } - triedb := trie.NewDatabase(t.db.backend.Database(), trie.HashDefaults) - t.trie, err = trie.New(id, triedb) + t.trie, err = trie.New(id, trie.NewDatabase(t.db.backend.Database())) } if err == nil { err = fn() @@ -248,8 +247,7 @@ func newNodeIterator(t *odrTrie, startkey []byte) trie.NodeIterator { } else { id = trie.StateTrieID(t.id.StateRoot) } - triedb := trie.NewDatabase(t.db.backend.Database(), trie.HashDefaults) - t, err := trie.New(id, triedb) + t, err := trie.New(id, trie.NewDatabase(t.db.backend.Database())) if err == nil { it.t.trie = t } diff --git a/light/trie_test.go b/light/trie_test.go index fe724e9eea..ad7d769c84 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -50,7 +50,7 @@ func TestNodeIterator(t *testing.T) { panic(err) } - gspec.MustCommit(lightdb, trie.NewDatabase(lightdb, trie.HashDefaults)) + gspec.MustCommit(lightdb) ctx := context.Background() odr := &testOdr{sdb: fulldb, ldb: lightdb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} head := blockchain.CurrentHeader() diff --git a/light/txpool_test.go b/light/txpool_test.go index 1eec7bc427..1181e3889e 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/trie" ) type testTxRelay struct { @@ -97,7 +96,7 @@ func TestTxPool(t *testing.T) { panic(err) } - gspec.MustCommit(ldb, trie.NewDatabase(ldb, trie.HashDefaults)) + gspec.MustCommit(ldb) odr := &testOdr{sdb: sdb, ldb: ldb, serverState: blockchain.StateCache(), indexerConfig: TestClientIndexerConfig} relay := &testTxRelay{ send: make(chan int, 1), diff --git a/miner/miner_test.go b/miner/miner_test.go index 489bc46a91..21db1ce4a9 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -288,9 +288,8 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { } // Create chainConfig chainDB := rawdb.NewMemoryDatabase() - triedb := trie.NewDatabase(chainDB, nil) genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) - chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) + chainConfig, _, err := core.SetupGenesisBlock(chainDB, trie.NewDatabase(chainDB), genesis) if err != nil { t.Fatalf("can't create new chain config: %v", err) } @@ -301,7 +300,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux, func(skipMiner bool)) { if err != nil { t.Fatalf("can't create new chain %v", err) } - statedb, _ := state.New(bc.Genesis().Root(), bc.StateCache(), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(chainDB), nil) blockchain := &testBlockChain{chainConfig, statedb, 10000000, new(event.Feed)} pool := legacypool.New(testTxPoolConfig, blockchain) diff --git a/tests/block_test.go b/tests/block_test.go index ad522ad653..2405da1cc7 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -18,8 +18,6 @@ package tests import ( "testing" - - "github.com/ethereum/go-ethereum/core/rawdb" ) func TestBlockchain(t *testing.T) { @@ -50,17 +48,11 @@ func TestBlockchain(t *testing.T) { bt.skipLoad(`.*randomStatetest94.json.*`) bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { - if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil)); err != nil { - t.Errorf("test in hash mode without snapshotter failed: %v", err) + if err := bt.checkFailure(t, test.Run(false, nil)); err != nil { + t.Errorf("test without snapshotter failed: %v", err) } - if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil)); err != nil { - t.Errorf("test in hash mode with snapshotter failed: %v", err) - } - if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil)); err != nil { - t.Errorf("test in path mode without snapshotter failed: %v", err) - } - if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil)); err != nil { - t.Errorf("test in path mode with snapshotter failed: %v", err) + if err := bt.checkFailure(t, test.Run(true, nil)); err != nil { + t.Errorf("test with snapshotter failed: %v", err) } }) // There is also a LegacyTests folder, containing blockchain tests generated diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 712174884b..d3e525a387 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -38,9 +38,6 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" ) // A BlockTest checks handling of entire blocks. @@ -103,30 +100,16 @@ type btHeaderMarshaling struct { BaseFeePerGas *math.HexOrDecimal256 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) error { +func (t *BlockTest) Run(snapshotter bool, tracer vm.EVMLogger) error { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} } - // import pre accounts & construct test genesis block & state root - var ( - db = rawdb.NewMemoryDatabase() - tconf = &trie.Config{} - ) - if scheme == rawdb.PathScheme { - tconf.PathDB = pathdb.Defaults - } else { - tconf.HashDB = hashdb.Defaults - } - // Commit genesis state - gspec := t.genesis(config) - triedb := trie.NewDatabase(db, tconf) - gblock, err := gspec.Commit(db, triedb) - if err != nil { - return err - } - triedb.Close() // close the db to prevent memory leak + // import pre accounts & construct test genesis block & state root + db := rawdb.NewMemoryDatabase() + gspec := t.genesis(config) + gblock := gspec.MustCommit(db) if gblock.Hash() != t.json.Genesis.Hash { return fmt.Errorf("genesis block hash doesn't match test: computed=%x, test=%x", gblock.Hash().Bytes()[:6], t.json.Genesis.Hash[:6]) } @@ -136,7 +119,7 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger) er // Wrap the original engine within the beacon-engine engine := beacon.New(ethash.NewFaker()) - cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme} + cache := &core.CacheConfig{TrieCleanLimit: 0} if snapshotter { cache.SnapshotLimit = 1 cache.SnapshotWait = true diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index c29bb2ef12..c62253a726 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -88,8 +88,8 @@ func makechain() (bc *core.BlockChain, addresses []common.Address, txHashes []co } func makeTries() (chtTrie *trie.Trie, bloomTrie *trie.Trie, chtKeys, bloomKeys [][]byte) { - chtTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), trie.HashDefaults)) - bloomTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), trie.HashDefaults)) + chtTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) + bloomTrie = trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < testChainLen; i++ { // The element in CHT is -> key := make([]byte, 8) diff --git a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go index 34f3959ff8..d5aee206da 100644 --- a/tests/fuzzers/rangeproof/rangeproof-fuzzer.go +++ b/tests/fuzzers/rangeproof/rangeproof-fuzzer.go @@ -56,7 +56,7 @@ func (f *fuzzer) readInt() uint64 { } func (f *fuzzer) randomTrie(n int) (*trie.Trie, map[string]*kv) { - trie := trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := trie.NewEmpty(trie.NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) size := f.readInt() // Fill it with some fluff diff --git a/tests/fuzzers/stacktrie/trie_fuzzer.go b/tests/fuzzers/stacktrie/trie_fuzzer.go index b8e13f96d1..1eb639f644 100644 --- a/tests/fuzzers/stacktrie/trie_fuzzer.go +++ b/tests/fuzzers/stacktrie/trie_fuzzer.go @@ -136,10 +136,10 @@ func (f *fuzzer) fuzz() int { // This spongeDb is used to check the sequence of disk-db-writes var ( spongeA = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - dbA = trie.NewDatabase(rawdb.NewDatabase(spongeA), nil) + dbA = trie.NewDatabase(rawdb.NewDatabase(spongeA)) trieA = trie.NewEmpty(dbA) spongeB = &spongeDb{sponge: sha3.NewLegacyKeccak256()} - dbB = trie.NewDatabase(rawdb.NewDatabase(spongeB), nil) + dbB = trie.NewDatabase(rawdb.NewDatabase(spongeB)) trieB = trie.NewStackTrie(func(owner common.Hash, path []byte, hash common.Hash, blob []byte) { rawdb.WriteTrieNode(spongeB, owner, path, hash, blob, dbB.Scheme()) }) diff --git a/tests/fuzzers/trie/trie-fuzzer.go b/tests/fuzzers/trie/trie-fuzzer.go index 687f5efb1c..fe9bf3d0fd 100644 --- a/tests/fuzzers/trie/trie-fuzzer.go +++ b/tests/fuzzers/trie/trie-fuzzer.go @@ -143,7 +143,7 @@ func Fuzz(input []byte) int { func runRandTest(rt randTest) error { var ( - triedb = trie.NewDatabase(rawdb.NewMemoryDatabase(), nil) + triedb = trie.NewDatabase(rawdb.NewMemoryDatabase()) tr = trie.NewEmpty(triedb) origin = types.EmptyRootHash values = make(map[string]string) // tracks content of the trie diff --git a/tests/state_test.go b/tests/state_test.go index 094dafcafd..782f1b0b4c 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -30,8 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -80,52 +78,21 @@ func TestState(t *testing.T) { subtest := subtest key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index) - t.Run(key+"/hash/trie", func(t *testing.T) { + t.Run(key+"/trie", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { - var result error - test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { - result = st.checkFailure(t, err) - }) - return result + _, _, err := test.Run(subtest, vmconfig, false) + return st.checkFailure(t, err) }) }) - t.Run(key+"/hash/snap", func(t *testing.T) { + t.Run(key+"/snap", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { - var result error - test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { - if snaps != nil && state != nil { - if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil { - result = err - return - } + snaps, statedb, err := test.Run(subtest, vmconfig, true) + if snaps != nil && statedb != nil { + if _, err := snaps.Journal(statedb.IntermediateRoot(false)); err != nil { + return err } - result = st.checkFailure(t, err) - }) - return result - }) - }) - t.Run(key+"/path/trie", func(t *testing.T) { - withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { - var result error - test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { - result = st.checkFailure(t, err) - }) - return result - }) - }) - t.Run(key+"/path/snap", func(t *testing.T) { - withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { - var result error - test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { - if snaps != nil && state != nil { - if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil { - result = err - return - } - } - result = st.checkFailure(t, err) - }) - return result + } + return st.checkFailure(t, err) }) }) } @@ -223,8 +190,7 @@ func runBenchmark(b *testing.B, t *StateTest) { vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() - triedb, _, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false, rawdb.HashScheme) - defer triedb.Close() + _, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, false) var baseFee *big.Int if rules.IsLondon { diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 113c796ca7..42f0c662ee 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -39,8 +39,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/hashdb" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "golang.org/x/crypto/sha3" ) @@ -189,50 +187,43 @@ func (t *StateTest) checkError(subtest StateSubtest, err error) error { } // Run executes a specific subtest and verifies the post-state and logs -func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string, postCheck func(err error, snaps *snapshot.Tree, state *state.StateDB)) (result error) { - triedb, snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter, scheme) - - // Invoke the callback at the end of function for further analysis. - defer func() { - postCheck(result, snaps, statedb) - - if triedb != nil { - triedb.Close() - } - }() - checkedErr := t.checkError(subtest, err) - if checkedErr != nil { - return checkedErr +func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, error) { + snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter) + if checkedErr := t.checkError(subtest, err); checkedErr != nil { + return snaps, statedb, checkedErr } // The error has been checked; if it was unexpected, it's already returned. if err != nil { // Here, an error exists but it was expected. // We do not check the post state or logs. - return nil + return snaps, statedb, nil } post := t.json.Post[subtest.Fork][subtest.Index] // N.B: We need to do this in a two-step process, because the first Commit takes care // of self-destructs, and we need to touch the coinbase _after_ it has potentially self-destructed. if root != common.Hash(post.Root) { - return fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) + return snaps, statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) } if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { - return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) + return snaps, statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) } - statedb, _ = state.New(root, statedb.Database(), snaps) - return nil + // Re-init the post-state instance for further operation + statedb, err = state.New(root, statedb.Database(), snaps) + if err != nil { + return nil, nil, err + } + return snaps, statedb, nil } // RunNoVerify runs a specific subtest and returns the statedb and post-state root -func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (*trie.Database, *snapshot.Tree, *state.StateDB, common.Hash, error) { +func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, common.Hash, error) { config, eips, err := GetChainConfig(subtest.Fork) if err != nil { - return nil, nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork} + return nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork} } vmconfig.ExtraEips = eips - block := t.genesis(config).ToBlock() - triedb, snaps, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme) + snaps, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter) var baseFee *big.Int if config.IsLondon(new(big.Int)) { @@ -246,8 +237,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh post := t.json.Post[subtest.Fork][subtest.Index] msg, err := t.json.Tx.toMessage(post, baseFee) if err != nil { - triedb.Close() - return nil, nil, nil, common.Hash{}, err + return nil, nil, common.Hash{}, err } // Try to recover tx with current signer @@ -255,13 +245,11 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh var ttx types.Transaction err := ttx.UnmarshalBinary(post.TxBytes) if err != nil { - triedb.Close() - return nil, nil, nil, common.Hash{}, err + return nil, nil, common.Hash{}, err } if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil { - triedb.Close() - return nil, nil, nil, common.Hash{}, err + return nil, nil, common.Hash{}, err } } @@ -280,7 +268,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.Difficulty = big.NewInt(0) } evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) - // Execute the message. snapshot := statedb.Snapshot() gaspool := new(core.GasPool) @@ -295,25 +282,17 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - there are only 'bad' transactions, which aren't executed. In those cases, // the coinbase gets no txfee, so isn't created, and thus needs to be touched statedb.AddBalance(block.Coinbase(), new(big.Int)) - - // Commit state mutations into database. + // Commit block root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number())) - return triedb, snaps, statedb, root, err + return snaps, statedb, root, err } func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] } -func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool, scheme string) (*trie.Database, *snapshot.Tree, *state.StateDB) { - tconf := &trie.Config{Preimages: true} - if scheme == rawdb.HashScheme { - tconf.HashDB = hashdb.Defaults - } else { - tconf.PathDB = pathdb.Defaults - } - triedb := trie.NewDatabase(db, tconf) - sdb := state.NewDatabaseWithNodeDB(db, triedb) +func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { + sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) statedb, _ := state.New(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) @@ -334,10 +313,10 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo NoBuild: false, AsyncBuild: false, } - snaps, _ = snapshot.New(snapconfig, db, triedb, root) + snaps, _ = snapshot.New(snapconfig, db, sdb.TrieDB(), root) } statedb, _ = state.New(root, sdb, snaps) - return triedb, snaps, statedb + return snaps, statedb } func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { diff --git a/trie/database.go b/trie/database.go index bac3e984ce..49a884fd7f 100644 --- a/trie/database.go +++ b/trie/database.go @@ -21,7 +21,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie/triedb/hashdb" "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/ethereum/go-ethereum/trie/trienode" @@ -30,21 +29,14 @@ import ( // Config defines all necessary options for database. type Config struct { - Preimages bool // Flag whether the preimage of node key is recorded - HashDB *hashdb.Config // Configs for hash-based scheme - PathDB *pathdb.Config // Configs for experimental path-based scheme + Cache int // Memory allowance (MB) to use for caching trie nodes in memory + Preimages bool // Flag whether the preimage of trie key is recorded + PathDB *pathdb.Config // Configs for experimental path-based scheme, not used yet. // Testing hooks OnCommit func(states *triestate.Set) // Hook invoked when commit is performed } -// HashDefaults represents a config for using hash-based scheme with -// default settings. -var HashDefaults = &Config{ - Preimages: false, - HashDB: hashdb.Defaults, -} - // backend defines the methods needed to access/update trie nodes in different // state scheme. type backend interface { @@ -99,30 +91,22 @@ func prepare(diskdb ethdb.Database, config *Config) *Database { } } -// NewDatabase initializes the trie database with default settings, note +// NewDatabase initializes the trie database with default settings, namely // the legacy hash-based scheme is used by default. -func NewDatabase(diskdb ethdb.Database, config *Config) *Database { - // Sanitize the config and use the default one if it's not specified. - if config == nil { - config = HashDefaults - } - var preimages *preimageStore - if config.Preimages { - preimages = newPreimageStore(diskdb) - } - db := &Database{ - config: config, - diskdb: diskdb, - preimages: preimages, - } - if config.HashDB != nil && config.PathDB != nil { - log.Crit("Both 'hash' and 'path' mode are configured") - } - if config.PathDB != nil { - db.backend = pathdb.New(diskdb, config.PathDB) - } else { - db.backend = hashdb.New(diskdb, config.HashDB, mptResolver{}) +func NewDatabase(diskdb ethdb.Database) *Database { + return NewDatabaseWithConfig(diskdb, nil) +} + +// NewDatabaseWithConfig initializes the trie database with provided configs. +// The path-based scheme is not activated yet, always initialized with legacy +// hash-based scheme by default. +func NewDatabaseWithConfig(diskdb ethdb.Database, config *Config) *Database { + var cleans int + if config != nil && config.Cache != 0 { + cleans = config.Cache * 1024 * 1024 } + db := prepare(diskdb, config) + db.backend = hashdb.New(diskdb, cleans, mptResolver{}) return db } @@ -256,60 +240,3 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) { } return hdb.Node(hash) } - -// Recover rollbacks the database to a specified historical point. The state is -// supported as the rollback destination only if it's canonical state and the -// corresponding trie histories are existent. It's only supported by path-based -// database and will return an error for others. -func (db *Database) Recover(target common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Recover(target, &trieLoader{db: db}) -} - -// Recoverable returns the indicator if the specified state is enabled to be -// recovered. It's only supported by path-based database and will return an -// error for others. -func (db *Database) Recoverable(root common.Hash) (bool, error) { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return false, errors.New("not supported") - } - return pdb.Recoverable(root), nil -} - -// Reset wipes all available journal from the persistent database and discard -// all caches and diff layers. Using the given root to create a new disk layer. -// It's only supported by path-based database and will return an error for others. -func (db *Database) Reset(root common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Reset(root) -} - -// Journal commits an entire diff hierarchy to disk into a single journal entry. -// This is meant to be used during shutdown to persist the snapshot without -// flattening everything down (bad for reorgs). It's only supported by path-based -// database and will return an error for others. -func (db *Database) Journal(root common.Hash) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.Journal(root) -} - -// SetBufferSize sets the node buffer size to the provided value(in bytes). -// It's only supported by path-based database and will return an error for -// others. -func (db *Database) SetBufferSize(size int) error { - pdb, ok := db.backend.(*pathdb.Database) - if !ok { - return errors.New("not supported") - } - return pdb.SetBufferSize(size) -} diff --git a/trie/database_test.go b/trie/database_test.go index d675a2191b..ed43a81e59 100644 --- a/trie/database_test.go +++ b/trie/database_test.go @@ -27,7 +27,7 @@ import ( func newTestDatabase(diskdb ethdb.Database, scheme string) *Database { db := prepare(diskdb, nil) if scheme == rawdb.HashScheme { - db.backend = hashdb.New(diskdb, &hashdb.Config{}, mptResolver{}) + db.backend = hashdb.New(diskdb, 0, mptResolver{}) } else { db.backend = pathdb.New(diskdb, &pathdb.Config{}) // disable clean/dirty cache } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 5dc1faed59..bf20c00c64 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + "encoding/binary" "fmt" "math/rand" "testing" @@ -26,11 +27,13 @@ import ( "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/ethdb" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/trie/trienode" ) func TestEmptyIterator(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) iter := trie.MustNodeIterator(nil) seen := make(map[string]struct{}) @@ -43,7 +46,7 @@ func TestEmptyIterator(t *testing.T) { } func TestIterator(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase(), nil) + db := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(db) vals := []struct{ k, v string }{ {"do", "verb"}, @@ -86,7 +89,7 @@ func (k *kv) less(other *kv) bool { } func TestIteratorLargeData(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) for i := byte(0); i < 255; i++ { @@ -205,7 +208,7 @@ var testdata2 = []kvs{ } func TestIteratorSeek(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { trie.MustUpdate([]byte(val.k), []byte(val.v)) } @@ -246,7 +249,7 @@ func checkIteratorOrder(want []kvs, it *Iterator) error { } func TestDifferenceIterator(t *testing.T) { - dba := NewDatabase(rawdb.NewMemoryDatabase(), nil) + dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) @@ -255,7 +258,7 @@ func TestDifferenceIterator(t *testing.T) { dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil) triea, _ = New(TrieID(rootA), dba) - dbb := NewDatabase(rawdb.NewMemoryDatabase(), nil) + dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) @@ -288,7 +291,7 @@ func TestDifferenceIterator(t *testing.T) { } func TestUnionIterator(t *testing.T) { - dba := NewDatabase(rawdb.NewMemoryDatabase(), nil) + dba := NewDatabase(rawdb.NewMemoryDatabase()) triea := NewEmpty(dba) for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) @@ -297,7 +300,7 @@ func TestUnionIterator(t *testing.T) { dba.Update(rootA, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodesA), nil) triea, _ = New(TrieID(rootA), dba) - dbb := NewDatabase(rawdb.NewMemoryDatabase(), nil) + dbb := NewDatabase(rawdb.NewMemoryDatabase()) trieb := NewEmpty(dbb) for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) @@ -341,7 +344,7 @@ func TestUnionIterator(t *testing.T) { } func TestIteratorNoDups(t *testing.T) { - tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + tr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range testdata1 { tr.MustUpdate([]byte(val.k), []byte(val.v)) } @@ -534,6 +537,96 @@ func TestIteratorNodeBlob(t *testing.T) { testIteratorNodeBlob(t, rawdb.PathScheme) } +type loggingDb struct { + getCount uint64 + backend ethdb.KeyValueStore +} + +func (l *loggingDb) Has(key []byte) (bool, error) { + return l.backend.Has(key) +} + +func (l *loggingDb) Get(key []byte) ([]byte, error) { + l.getCount++ + return l.backend.Get(key) +} + +func (l *loggingDb) Put(key []byte, value []byte) error { + return l.backend.Put(key, value) +} + +func (l *loggingDb) Delete(key []byte) error { + return l.backend.Delete(key) +} + +func (l *loggingDb) NewBatch() ethdb.Batch { + return l.backend.NewBatch() +} + +func (l *loggingDb) NewBatchWithSize(size int) ethdb.Batch { + return l.backend.NewBatchWithSize(size) +} + +func (l *loggingDb) NewIterator(prefix []byte, start []byte) ethdb.Iterator { + return l.backend.NewIterator(prefix, start) +} + +func (l *loggingDb) NewSnapshot() (ethdb.Snapshot, error) { + return l.backend.NewSnapshot() +} + +func (l *loggingDb) Stat(property string) (string, error) { + return l.backend.Stat(property) +} + +func (l *loggingDb) Compact(start []byte, limit []byte) error { + return l.backend.Compact(start, limit) +} + +func (l *loggingDb) Close() error { + return l.backend.Close() +} + +// makeLargeTestTrie create a sample test trie +func makeLargeTestTrie() (*Database, *StateTrie, *loggingDb) { + // Create an empty trie + logDb := &loggingDb{0, memorydb.New()} + triedb := NewDatabase(rawdb.NewDatabase(logDb)) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) + + // Fill it with some arbitrary data + for i := 0; i < 10000; i++ { + key := make([]byte, 32) + val := make([]byte, 32) + binary.BigEndian.PutUint64(key, uint64(i)) + binary.BigEndian.PutUint64(val, uint64(i)) + key = crypto.Keccak256(key) + val = crypto.Keccak256(val) + trie.MustUpdate(key, val) + } + root, nodes, _ := trie.Commit(false) + triedb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) + triedb.Commit(root, false) + + // Return the generated trie + trie, _ = NewStateTrie(TrieID(root), triedb) + return triedb, trie, logDb +} + +// Tests that the node iterator indeed walks over the entire database contents. +func TestNodeIteratorLargeTrie(t *testing.T) { + // Create some arbitrary test trie to iterate + db, trie, logDb := makeLargeTestTrie() + db.Cap(0) // flush everything + // Do a seek operation + trie.NodeIterator(common.FromHex("0x77667766776677766778855885885885")) + // master: 24 get operations + // this pr: 6 get operations + if have, want := logDb.getCount, uint64(6); have != want { + t.Fatalf("Too many lookups during seek, have %d want %d", have, want) + } +} + func testIteratorNodeBlob(t *testing.T, scheme string) { var ( db = rawdb.NewMemoryDatabase() @@ -607,7 +700,7 @@ func isTrieNode(scheme string, key, val []byte) (bool, []byte, common.Hash) { } hash = common.BytesToHash(key) } else { - ok, remain := rawdb.ResolveAccountTrieNodeKey(key) + ok, remain := rawdb.IsAccountTrieNode(key) if !ok { return false, nil, common.Hash{} } diff --git a/trie/proof_test.go b/trie/proof_test.go index c943194586..d8effd0d04 100644 --- a/trie/proof_test.go +++ b/trie/proof_test.go @@ -94,7 +94,7 @@ func TestProof(t *testing.T) { } func TestOneElementProof(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "k", "v") for i, prover := range makeProvers(trie) { proof := prover([]byte("k")) @@ -145,7 +145,7 @@ func TestBadProof(t *testing.T) { // Tests that missing keys can also be proven. The test explicitly uses a single // entry trie and checks for missing keys both before and after the single entry. func TestMissingKeyProof(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "k", "v") for i, key := range []string{"a", "j", "l", "z"} { @@ -395,7 +395,7 @@ func TestOneElementRangeProof(t *testing.T) { } // Test the mini trie with only a single element. - tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + tinyTrie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) entry := &kv{randBytes(32), randBytes(20), false} tinyTrie.MustUpdate(entry.k, entry.v) @@ -467,7 +467,7 @@ func TestAllElementsProof(t *testing.T) { // TestSingleSideRangeProof tests the range starts from zero. func TestSingleSideRangeProof(t *testing.T) { for i := 0; i < 64; i++ { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries []*kv for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -502,7 +502,7 @@ func TestSingleSideRangeProof(t *testing.T) { // TestReverseSingleSideRangeProof tests the range ends with 0xffff...fff. func TestReverseSingleSideRangeProof(t *testing.T) { for i := 0; i < 64; i++ { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries []*kv for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -609,7 +609,7 @@ func TestBadRangeProof(t *testing.T) { // TestGappedRangeProof focuses on the small trie with embedded nodes. // If the gapped node is embedded in the trie, it should be detected too. func TestGappedRangeProof(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries []*kv // Sorted entries for i := byte(0); i < 10; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} @@ -683,7 +683,7 @@ func TestSameSideProofs(t *testing.T) { } func TestHasRightElement(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) var entries []*kv for i := 0; i < 4096; i++ { value := &kv{randBytes(32), randBytes(20), false} @@ -1036,7 +1036,7 @@ func benchmarkVerifyRangeNoProof(b *testing.B, size int) { } func randomTrie(n int) (*Trie, map[string]*kv) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) for i := byte(0); i < 100; i++ { value := &kv{common.LeftPadBytes([]byte{i}, 32), []byte{i}, false} @@ -1055,7 +1055,7 @@ func randomTrie(n int) (*Trie, map[string]*kv) { } func nonRandomTrie(n int) (*Trie, map[string]*kv) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := make(map[string]*kv) max := uint64(0xffffffffffffffff) for i := uint64(0); i < uint64(n); i++ { @@ -1080,7 +1080,7 @@ func TestRangeProofKeysWithSharedPrefix(t *testing.T) { common.Hex2Bytes("02"), common.Hex2Bytes("03"), } - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i, key := range keys { trie.MustUpdate(key, vals[i]) } diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 2087866d38..a610ca2fd6 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -31,14 +31,14 @@ import ( ) func newEmptySecure() *StateTrie { - trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), NewDatabase(rawdb.NewMemoryDatabase())) return trie } // makeTestStateTrie creates a large enough secure trie for testing. func makeTestStateTrie() (*Database, *StateTrie, map[string][]byte) { // Create an empty trie - triedb := NewDatabase(rawdb.NewMemoryDatabase(), nil) + triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie, _ := NewStateTrie(TrieID(types.EmptyRootHash), triedb) // Fill it with some arbitrary data diff --git a/trie/stacktrie_test.go b/trie/stacktrie_test.go index 822dd31a93..ea3eef7882 100644 --- a/trie/stacktrie_test.go +++ b/trie/stacktrie_test.go @@ -188,7 +188,7 @@ func TestStackTrieInsertAndHash(t *testing.T) { func TestSizeBug(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -203,7 +203,7 @@ func TestSizeBug(t *testing.T) { func TestEmptyBug(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -229,7 +229,7 @@ func TestEmptyBug(t *testing.T) { func TestValLength56(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) //leaf := common.FromHex("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563") //value := common.FromHex("94cf40d0d2b44f2b66e07cace1372ca42b73cf21a3") @@ -254,7 +254,7 @@ func TestValLength56(t *testing.T) { // which causes a lot of node-within-node. This case was found via fuzzing. func TestUpdateSmallNodes(t *testing.T) { st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) kvs := []struct { K string V string @@ -282,7 +282,7 @@ func TestUpdateSmallNodes(t *testing.T) { func TestUpdateVariableKeys(t *testing.T) { t.SkipNow() st := NewStackTrie(nil) - nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) kvs := []struct { K string V string @@ -351,7 +351,7 @@ func TestStacktrieNotModifyValues(t *testing.T) { func TestStacktrieSerialization(t *testing.T) { var ( st = NewStackTrie(nil) - nt = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + nt = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) keyB = big.NewInt(1) keyDelta = big.NewInt(1) vals [][]byte diff --git a/trie/sync_test.go b/trie/sync_test.go index dd3506559d..b6fe8d84a6 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -109,8 +109,8 @@ type trieElement struct { // Tests that an empty trie is not scheduled for syncing. func TestEmptySync(t *testing.T) { - dbA := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) - dbB := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.HashScheme) + dbA := NewDatabase(rawdb.NewMemoryDatabase()) + dbB := NewDatabase(rawdb.NewMemoryDatabase()) dbC := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) dbD := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme) diff --git a/trie/tracer_test.go b/trie/tracer_test.go index acb8c2f6bf..86daec6d20 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -61,7 +61,7 @@ func TestTrieTracer(t *testing.T) { // Tests if the trie diffs are tracked correctly. Tracer should capture // all non-leaf dirty nodes, no matter the node is embedded or not. func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { - db := NewDatabase(rawdb.NewMemoryDatabase(), nil) + db := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(db) // Determine all new nodes are tracked @@ -104,7 +104,7 @@ func TestTrieTracerNoop(t *testing.T) { } func testTrieTracerNoop(t *testing.T, vals []struct{ k, v string }) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for _, val := range vals { trie.MustUpdate([]byte(val.k), []byte(val.v)) } @@ -128,7 +128,7 @@ func TestAccessList(t *testing.T) { func testAccessList(t *testing.T, vals []struct{ k, v string }) { var ( - db = NewDatabase(rawdb.NewMemoryDatabase(), nil) + db = NewDatabase(rawdb.NewMemoryDatabase()) trie = NewEmpty(db) orig = trie.Copy() ) @@ -211,7 +211,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { // Tests origin values won't be tracked in Iterator or Prover func TestAccessListLeak(t *testing.T) { var ( - db = NewDatabase(rawdb.NewMemoryDatabase(), nil) + db = NewDatabase(rawdb.NewMemoryDatabase()) trie = NewEmpty(db) ) // Create trie from scratch @@ -262,7 +262,7 @@ func TestAccessListLeak(t *testing.T) { // in its parent due to the smaller size of the original tree node. func TestTinyTree(t *testing.T) { var ( - db = NewDatabase(rawdb.NewMemoryDatabase(), nil) + db = NewDatabase(rawdb.NewMemoryDatabase()) trie = NewEmpty(db) ) for _, val := range tiny { diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 4215964559..1c63ff4544 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -20,7 +20,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie/triestate" ) // Reader wraps the Node method of a backing trie store. @@ -84,18 +83,3 @@ func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) { } return blob, nil } - -// trieLoader implements triestate.TrieLoader for constructing tries. -type trieLoader struct { - db *Database -} - -// OpenTrie opens the main account trie. -func (l *trieLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return New(TrieID(root), l.db) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *trieLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return New(StorageTrieID(stateRoot, addrHash, root), l.db) -} diff --git a/trie/trie_test.go b/trie/trie_test.go index 35ccc77201..3cb21c1956 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -45,7 +45,7 @@ func init() { } func TestEmptyTrie(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) res := trie.Hash() exp := types.EmptyRootHash if res != exp { @@ -54,7 +54,7 @@ func TestEmptyTrie(t *testing.T) { } func TestNull(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) key := make([]byte, 32) value := []byte("test") trie.MustUpdate(key, value) @@ -64,13 +64,8 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - testMissingRoot(t, rawdb.HashScheme) - testMissingRoot(t, rawdb.PathScheme) -} - -func testMissingRoot(t *testing.T, scheme string) { root := common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") - trie, err := New(TrieID(root), newTestDatabase(rawdb.NewMemoryDatabase(), scheme)) + trie, err := New(TrieID(root), NewDatabase(rawdb.NewMemoryDatabase())) if trie != nil { t.Error("New returned non-nil trie for invalid root") } @@ -166,7 +161,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) { } func TestInsert(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "doe", "reindeer") updateString(trie, "dog", "puppy") @@ -178,7 +173,7 @@ func TestInsert(t *testing.T) { t.Errorf("case 1: exp %x got %x", exp, root) } - trie = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie = NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") @@ -189,7 +184,7 @@ func TestInsert(t *testing.T) { } func TestGet(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase(), nil) + db := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(db) updateString(trie, "doe", "reindeer") updateString(trie, "dog", "puppy") @@ -214,7 +209,7 @@ func TestGet(t *testing.T) { } func TestDelete(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := []struct{ k, v string }{ {"do", "verb"}, {"ether", "wookiedoo"}, @@ -241,7 +236,7 @@ func TestDelete(t *testing.T) { } func TestEmptyValues(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) vals := []struct{ k, v string }{ {"do", "verb"}, @@ -265,7 +260,7 @@ func TestEmptyValues(t *testing.T) { } func TestReplication(t *testing.T) { - db := NewDatabase(rawdb.NewMemoryDatabase(), nil) + db := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(db) vals := []struct{ k, v string }{ {"do", "verb"}, @@ -326,7 +321,7 @@ func TestReplication(t *testing.T) { } func TestLargeValue(t *testing.T) { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.MustUpdate([]byte("key1"), []byte{99, 99, 99, 99}) trie.MustUpdate([]byte("key2"), bytes.Repeat([]byte{1}, 32)) trie.Hash() @@ -609,7 +604,7 @@ func BenchmarkUpdateLE(b *testing.B) { benchUpdate(b, binary.LittleEndian) } const benchElemCount = 20000 func benchGet(b *testing.B) { - triedb := NewDatabase(rawdb.NewMemoryDatabase(), nil) + triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(triedb) k := make([]byte, 32) for i := 0; i < benchElemCount; i++ { @@ -626,7 +621,7 @@ func benchGet(b *testing.B) { } func benchUpdate(b *testing.B, e binary.ByteOrder) *Trie { - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) k := make([]byte, 32) b.ReportAllocs() for i := 0; i < b.N; i++ { @@ -656,7 +651,7 @@ func BenchmarkHash(b *testing.B) { // entries, then adding N more. addresses, accounts := makeAccounts(2 * b.N) // Insert the accounts into the trie and hash it - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) i := 0 for ; i < len(addresses)/2; i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) @@ -687,7 +682,7 @@ func BenchmarkCommitAfterHash(b *testing.B) { func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { // Make the random benchmark deterministic addresses, accounts := makeAccounts(b.N) - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -701,7 +696,7 @@ func benchmarkCommitAfterHash(b *testing.B, collectLeaf bool) { func TestTinyTrie(t *testing.T) { // Create a realistic account trie to hash _, accounts := makeAccounts(5) - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) trie.MustUpdate(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000001337"), accounts[3]) if exp, root := common.HexToHash("8c6a85a4d9fda98feff88450299e574e5378e32391f75a055d470ac0653f1005"), trie.Hash(); exp != root { t.Errorf("1: got %x, exp %x", root, exp) @@ -714,7 +709,7 @@ func TestTinyTrie(t *testing.T) { if exp, root := common.HexToHash("0608c1d1dc3905fa22204c7a0e43644831c3b6d3def0f274be623a948197e64a"), trie.Hash(); exp != root { t.Errorf("3: got %x, exp %x", root, exp) } - checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + checktr := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) it := NewIterator(trie.MustNodeIterator(nil)) for it.Next() { checktr.MustUpdate(it.Key, it.Value) @@ -727,7 +722,7 @@ func TestTinyTrie(t *testing.T) { func TestCommitAfterHash(t *testing.T) { // Create a realistic account trie to hash addresses, accounts := makeAccounts(1000) - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -793,17 +788,11 @@ func (s *spongeDb) Stat(property string) (string, error) { panic("implement func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Close() error { return nil } func (s *spongeDb) Put(key []byte, value []byte) error { - var ( - keybrief = key - valbrief = value - ) - if len(keybrief) > 8 { - keybrief = keybrief[:8] - } + valbrief := value if len(valbrief) > 8 { valbrief = valbrief[:8] } - s.journal = append(s.journal, fmt.Sprintf("%v: PUT([%x...], [%d bytes] %x...)\n", s.id, keybrief, len(value), valbrief)) + s.journal = append(s.journal, fmt.Sprintf("%v: PUT([%x...], [%d bytes] %x...)\n", s.id, key[:8], len(value), valbrief)) s.sponge.Write(key) s.sponge.Write(value) return nil @@ -841,7 +830,7 @@ func TestCommitSequence(t *testing.T) { addresses, accounts := makeAccounts(tc.count) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := NewDatabase(rawdb.NewDatabase(s), nil) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Fill the trie with elements for i := 0; i < tc.count; i++ { @@ -872,7 +861,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { prng := rand.New(rand.NewSource(int64(i))) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256()} - db := NewDatabase(rawdb.NewDatabase(s), nil) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Fill the trie with elements for i := 0; i < tc.count; i++ { @@ -904,7 +893,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { prng := rand.New(rand.NewSource(int64(count))) // This spongeDb is used to check the sequence of disk-db-writes s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} - db := NewDatabase(rawdb.NewDatabase(s), nil) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} @@ -963,7 +952,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { // not fit into 32 bytes, rlp-encoded. However, it's still the correct thing to do. func TestCommitSequenceSmallRoot(t *testing.T) { s := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "a"} - db := NewDatabase(rawdb.NewDatabase(s), nil) + db := NewDatabase(rawdb.NewDatabase(s)) trie := NewEmpty(db) // Another sponge is used for the stacktrie commits stackTrieSponge := &spongeDb{sponge: sha3.NewLegacyKeccak256(), id: "b"} @@ -1040,7 +1029,7 @@ func BenchmarkHashFixedSize(b *testing.B) { func benchmarkHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -1091,7 +1080,7 @@ func BenchmarkCommitAfterHashFixedSize(b *testing.B) { func benchmarkCommitAfterHashFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase(), nil)) + trie := NewEmpty(NewDatabase(rawdb.NewMemoryDatabase())) for i := 0; i < len(addresses); i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } @@ -1143,7 +1132,7 @@ func BenchmarkDerefRootFixedSize(b *testing.B) { func benchmarkDerefRootFixedSize(b *testing.B, addresses [][20]byte, accounts [][]byte) { b.ReportAllocs() - triedb := NewDatabase(rawdb.NewMemoryDatabase(), nil) + triedb := NewDatabase(rawdb.NewMemoryDatabase()) trie := NewEmpty(triedb) for i := 0; i < len(addresses); i++ { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) diff --git a/trie/triedb/hashdb/database.go b/trie/triedb/hashdb/database.go index b3ae54dbe3..4441f2a382 100644 --- a/trie/triedb/hashdb/database.go +++ b/trie/triedb/hashdb/database.go @@ -65,20 +65,6 @@ type ChildResolver interface { ForEach(node []byte, onChild func(common.Hash)) } -// Config contains the settings for database. -type Config struct { - CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes -} - -// Defaults is the default setting for database if it's not specified. -// Notably, clean cache is disabled explicitly, -var Defaults = &Config{ - // Explicitly set clean cache size to 0 to avoid creating fastcache, - // otherwise database must be closed when it's no longer needed to - // prevent memory leak. - CleanCacheSize: 0, -} - // Database is an intermediate write layer between the trie data structures and // the disk database. The aim is to accumulate trie writes in-memory and only // periodically flush a couple tries to disk, garbage collecting the remainder. @@ -136,13 +122,12 @@ func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash commo } // New initializes the hash-based node database. -func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Database { - if config == nil { - config = Defaults - } +func New(diskdb ethdb.Database, size int, resolver ChildResolver) *Database { + // Initialize the clean cache if the specified cache allowance + // is non-zero. Note, the size is in bytes. var cleans *fastcache.Cache - if config.CleanCacheSize > 0 { - cleans = fastcache.New(config.CleanCacheSize) + if size > 0 { + cleans = fastcache.New(size) } return &Database{ diskdb: diskdb, @@ -636,13 +621,7 @@ func (db *Database) Size() common.StorageSize { } // Close closes the trie database and releases all held resources. -func (db *Database) Close() error { - if db.cleans != nil { - db.cleans.Reset() - db.cleans = nil - } - return nil -} +func (db *Database) Close() error { return nil } // Scheme returns the node scheme used in the database. func (db *Database) Scheme() string { diff --git a/trie/triedb/pathdb/database.go b/trie/triedb/pathdb/database.go index 0382740046..29f6b5e103 100644 --- a/trie/triedb/pathdb/database.go +++ b/trie/triedb/pathdb/database.go @@ -33,26 +33,8 @@ import ( "github.com/ethereum/go-ethereum/trie/triestate" ) -const ( - // maxDiffLayers is the maximum diff layers allowed in the layer tree. - maxDiffLayers = 128 - - // defaultCleanSize is the default memory allowance of clean cache. - defaultCleanSize = 16 * 1024 * 1024 - - // maxBufferSize is the maximum memory allowance of node buffer. - // Too large nodebuffer will cause the system to pause for a long - // time when write happens. Also, the largest batch that pebble can - // support is 4GB, node will panic if batch size exceeds this limit. - maxBufferSize = 256 * 1024 * 1024 - - // DefaultBufferSize is the default memory allowance of node buffer - // that aggregates the writes from above until it's flushed into the - // disk. It's meant to be used once the initial sync is finished. - // Do not increase the buffer size arbitrarily, otherwise the system - // pause time will increase when the database writes happen. - DefaultBufferSize = 64 * 1024 * 1024 -) +// maxDiffLayers is the maximum diff layers allowed in the layer tree. +const maxDiffLayers = 128 // layer is the interface implemented by all state layers which includes some // public methods and some additional methods for internal usage. @@ -86,33 +68,30 @@ type layer interface { // Config contains the settings for database. type Config struct { - StateHistory uint64 // Number of recent blocks to maintain state history for - CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes - DirtyCacheSize int // Maximum memory allowance (in bytes) for caching dirty nodes - ReadOnly bool // Flag whether the database is opened in read only mode. + StateLimit uint64 // Number of recent blocks to maintain state history for + CleanSize int // Maximum memory allowance (in bytes) for caching clean nodes + DirtySize int // Maximum memory allowance (in bytes) for caching dirty nodes + ReadOnly bool // Flag whether the database is opened in read only mode. } -// sanitize checks the provided user configurations and changes anything that's -// unreasonable or unworkable. -func (c *Config) sanitize() *Config { - conf := *c - if conf.DirtyCacheSize > maxBufferSize { - log.Warn("Sanitizing invalid node buffer size", "provided", common.StorageSize(conf.DirtyCacheSize), "updated", common.StorageSize(maxBufferSize)) - conf.DirtyCacheSize = maxBufferSize - } - return &conf -} +var ( + // defaultCleanSize is the default memory allowance of clean cache. + defaultCleanSize = 16 * 1024 * 1024 + + // defaultBufferSize is the default memory allowance of node buffer + // that aggregates the writes from above until it's flushed into the + // disk. Do not increase the buffer size arbitrarily, otherwise the + // system pause time will increase when the database writes happen. + defaultBufferSize = 128 * 1024 * 1024 +) // Defaults contains default settings for Ethereum mainnet. var Defaults = &Config{ - StateHistory: params.FullImmutabilityThreshold, - CleanCacheSize: defaultCleanSize, - DirtyCacheSize: DefaultBufferSize, + StateLimit: params.FullImmutabilityThreshold, + CleanSize: defaultCleanSize, + DirtySize: defaultBufferSize, } -// ReadOnly is the config in order to open database in read only mode. -var ReadOnly = &Config{ReadOnly: true} - // Database is a multiple-layered structure for maintaining in-memory trie nodes. // It consists of one persistent base layer backed by a key-value store, on top // of which arbitrarily many in-memory diff layers are stacked. The memory diffs @@ -144,11 +123,9 @@ func New(diskdb ethdb.Database, config *Config) *Database { if config == nil { config = Defaults } - config = config.sanitize() - db := &Database{ readOnly: config.ReadOnly, - bufferSize: config.DirtyCacheSize, + bufferSize: config.DirtySize, config: config, diskdb: diskdb, } @@ -163,7 +140,7 @@ func New(diskdb ethdb.Database, config *Config) *Database { // mechanism also ensures that at most one **non-readOnly** database // is opened at the same time to prevent accidental mutation. if ancient, err := diskdb.AncientDatadir(); err == nil && ancient != "" && !db.readOnly { - freezer, err := rawdb.NewStateFreezer(ancient, false) + freezer, err := rawdb.NewStateHistoryFreezer(ancient, false) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } @@ -367,14 +344,7 @@ func (db *Database) Close() error { db.lock.Lock() defer db.lock.Unlock() - // Set the database to read-only mode to prevent all - // following mutations. db.readOnly = true - - // Release the memory held by clean cache. - db.tree.bottom().resetCache() - - // Close the attached state history freezer. if db.freezer == nil { return nil } @@ -412,10 +382,6 @@ func (db *Database) SetBufferSize(size int) error { db.lock.Lock() defer db.lock.Unlock() - if size > maxBufferSize { - log.Info("Capped node buffer size", "provided", common.StorageSize(size), "adjusted", common.StorageSize(maxBufferSize)) - size = maxBufferSize - } db.bufferSize = size return db.tree.bottom().setBufferSize(db.bufferSize) } diff --git a/trie/triedb/pathdb/database_test.go b/trie/triedb/pathdb/database_test.go index 6d346d20ea..bcc37e59c8 100644 --- a/trie/triedb/pathdb/database_test.go +++ b/trie/triedb/pathdb/database_test.go @@ -46,8 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm h.Update(key.Bytes(), val) } } - root, nodes, _ := h.Commit(false) - return root, nodes + return h.Commit(false) } func generateAccount(storageRoot common.Hash) types.StateAccount { @@ -99,7 +98,7 @@ type tester struct { func newTester(t *testing.T) *tester { var ( disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) - db = New(disk, &Config{CleanCacheSize: 256 * 1024, DirtyCacheSize: 256 * 1024}) + db = New(disk, &Config{CleanSize: 256 * 1024, DirtySize: 256 * 1024}) obj = &tester{ db: db, preimages: make(map[common.Hash]common.Address), diff --git a/trie/triedb/pathdb/difflayer_test.go b/trie/triedb/pathdb/difflayer_test.go index 9b5907c3c5..77c4cd5722 100644 --- a/trie/triedb/pathdb/difflayer_test.go +++ b/trie/triedb/pathdb/difflayer_test.go @@ -29,7 +29,7 @@ import ( func emptyLayer() *diskLayer { return &diskLayer{ db: New(rawdb.NewMemoryDatabase(), nil), - buffer: newNodeBuffer(DefaultBufferSize, nil, 0), + buffer: newNodeBuffer(defaultBufferSize, nil, 0), } } diff --git a/trie/triedb/pathdb/disklayer.go b/trie/triedb/pathdb/disklayer.go index 87718290f9..b526b3b7dd 100644 --- a/trie/triedb/pathdb/disklayer.go +++ b/trie/triedb/pathdb/disklayer.go @@ -47,8 +47,8 @@ func newDiskLayer(root common.Hash, id uint64, db *Database, cleans *fastcache.C // Initialize a clean cache if the memory allowance is not zero // or reuse the provided cache if it is not nil (inherited from // the original disk layer). - if cleans == nil && db.config.CleanCacheSize != 0 { - cleans = fastcache.New(db.config.CleanCacheSize) + if cleans == nil && db.config.CleanSize != 0 { + cleans = fastcache.New(db.config.CleanSize) } return &diskLayer{ root: root, @@ -177,7 +177,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { // corresponding states(journal), the stored state history will // be truncated in the next restart. if dl.db.freezer != nil { - err := writeHistory(dl.db.diskdb, dl.db.freezer, bottom, dl.db.config.StateHistory) + err := writeHistory(dl.db.diskdb, dl.db.freezer, bottom, dl.db.config.StateLimit) if err != nil { return nil, err } @@ -276,20 +276,6 @@ func (dl *diskLayer) size() common.StorageSize { return common.StorageSize(dl.buffer.size) } -// resetCache releases the memory held by clean cache to prevent memory leak. -func (dl *diskLayer) resetCache() { - dl.lock.RLock() - defer dl.lock.RUnlock() - - // Stale disk layer loses the ownership of clean cache. - if dl.stale { - return - } - if dl.cleans != nil { - dl.cleans.Reset() - } -} - // hasher is used to compute the sha256 hash of the provided data. type hasher struct{ sha crypto.KeccakState } diff --git a/trie/triedb/pathdb/history_test.go b/trie/triedb/pathdb/history_test.go index 677103e2b0..6c250c2591 100644 --- a/trie/triedb/pathdb/history_test.go +++ b/trie/triedb/pathdb/history_test.go @@ -226,7 +226,7 @@ func TestTruncateTailHistories(t *testing.T) { // openFreezer initializes the freezer instance for storing state histories. func openFreezer(datadir string, readOnly bool) (*rawdb.ResettableFreezer, error) { - return rawdb.NewStateFreezer(datadir, readOnly) + return rawdb.NewStateHistoryFreezer(datadir, readOnly) } func compareSet[k comparable](a, b map[k][]byte) bool { diff --git a/trie/triedb/pathdb/testutils.go b/trie/triedb/pathdb/testutils.go index 2efac87198..cb3a240cc4 100644 --- a/trie/triedb/pathdb/testutils.go +++ b/trie/triedb/pathdb/testutils.go @@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error { // Commit computes the new hash of the states and returns the set with all // state changes. -func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { var ( nodes = make(map[common.Hash][]byte) set = trienode.NewNodeSet(h.owner) @@ -108,7 +108,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e if root == types.EmptyRootHash && h.root != types.EmptyRootHash { set.AddNode(nil, trienode.NewDeleted()) } - return root, set, nil + return root, set } // hash performs the hash computation upon the provided states. diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 4c47e9c397..cb3611baf9 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -43,7 +43,7 @@ type Trie interface { // Commit the trie and returns a set of dirty nodes generated along with // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) } // TrieLoader wraps functions to load tries. @@ -129,10 +129,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre return nil, fmt.Errorf("failed to revert state, err: %w", err) } } - root, result, err := tr.Commit(false) - if err != nil { - return nil, err - } + root, result := tr.Commit(false) if root != prevRoot { return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) } @@ -184,10 +181,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != prev.Root { return errors.New("failed to reset storage trie") } @@ -238,10 +232,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != types.EmptyRootHash { return errors.New("failed to clear storage trie") }