From b5007068d1226c9de3997eb2d394d57baf4d7efd Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Fri, 1 Sep 2023 10:51:23 +0800 Subject: [PATCH] core, cmd, accounts, eth, light, trie: seperate out CodeStore interface --- accounts/abi/bind/backends/simulated.go | 2 +- cmd/evm/internal/t8ntool/execution.go | 3 +- cmd/evm/runner.go | 3 +- cmd/geth/chaincmd.go | 2 +- core/blockchain.go | 9 +- core/blockchain_reader.go | 19 ++- core/blockchain_sethead_test.go | 2 - core/blockchain_test.go | 3 +- core/chain_makers.go | 4 +- core/genesis.go | 7 +- core/state/codedb.go | 114 +++++++++++++++ core/state/database.go | 156 ++++++++------------- core/state/iterator.go | 2 +- core/state/state_object.go | 4 +- core/state/state_test.go | 20 +-- core/state/statedb.go | 23 ++- core/state/statedb_fuzz_test.go | 2 +- core/state/statedb_test.go | 34 ++--- core/state/sync_test.go | 22 +-- core/state/trie_prefetcher_test.go | 2 +- core/txpool/blobpool/blobpool_test.go | 10 +- core/txpool/legacypool/legacypool2_test.go | 8 +- core/txpool/legacypool/legacypool_test.go | 41 +++--- core/vm/gas_table_test.go | 4 +- core/vm/instructions_test.go | 2 +- core/vm/interpreter_test.go | 2 +- core/vm/runtime/runtime.go | 4 +- core/vm/runtime/runtime_test.go | 10 +- eth/api_debug_test.go | 37 ++--- eth/state_accessor.go | 6 +- miner/miner_test.go | 2 +- tests/state_test_util.go | 2 +- 32 files changed, 328 insertions(+), 233 deletions(-) create mode 100644 core/state/codedb.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2faf274dbd..05eac14f6d 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -149,7 +149,7 @@ func (b *SimulatedBackend) rollback(parent *types.Block) { blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) b.pendingBlock = blocks[0] - b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache(), nil) + b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.blockchain.CodeDB(), b.blockchain.TrieDB()), nil) } // Fork creates a side-chain that can be used to simulate reorgs. diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a4ffd09e4f..6b6b10dd31 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -353,7 +353,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { - sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) + tdb := trie.NewDatabase(db, &trie.Config{Preimages: true}) + sdb := state.NewDatabase(state.NewCodeDB(db), tdb) statedb, _ := state.New(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index f3ffb3ed9f..2d437a7fdd 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -154,7 +154,8 @@ func runCmd(ctx *cli.Context) error { }) defer triedb.Close() genesis := genesisConfig.MustCommit(db, triedb) - sdb := state.NewDatabaseWithNodeDB(db, triedb) + + sdb := state.NewDatabase(state.NewCodeDB(db), triedb) statedb, _ = state.New(genesis.Root(), sdb, nil) chainConfig = genesisConfig.Config diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 3b4f516af7..c4a704aa01 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -466,7 +466,7 @@ func dump(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup defer triedb.Close() - state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil) + state, err := state.New(root, state.NewDatabase(state.NewCodeDB(db), triedb), nil) if err != nil { return err } diff --git a/core/blockchain.go b/core/blockchain.go index f458da8257..1a39368409 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -209,8 +209,8 @@ type BlockChain struct { gcproc time.Duration // Accumulates canonical block processing for trie dumping lastWrite uint64 // Last block when the state was flushed flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state + codedb *state.CodeDB // The database handler for maintaining contract codes. triedb *trie.Database // The database handler for maintaining trie nodes. - stateCache state.Database // State database to reuse between imports (contains state cache) // txLookupLimit is the maximum number of blocks from head whose tx indices // are reserved: @@ -289,6 +289,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis chainConfig: chainConfig, cacheConfig: cacheConfig, db: db, + codedb: state.NewCodeDB(db), triedb: triedb, triegc: prque.New[int64, common.Hash](nil), quit: make(chan struct{}), @@ -304,7 +305,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) bc.forker = NewForkChoice(bc, shouldPreserve) - bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -1778,11 +1778,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) if parent == nil { parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) + statedb, err := state.New(parent.Root, state.NewDatabase(bc.codedb, bc.triedb), bc.snaps) if err != nil { return it.index, err } - // Enable prefetching to pull in trie node paths while processing transactions statedb.StartPrefetcher("chain") activeState = statedb @@ -1792,7 +1791,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) var followupInterrupt atomic.Bool if !bc.cacheConfig.TrieCleanNoPrefetch { if followup, err := it.peek(); followup != nil && err == nil { - throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) + throwaway, _ := state.New(parent.Root, state.NewDatabase(bc.codedb, bc.triedb), bc.snaps) go func(start time.Time, followup *types.Block, throwaway *state.StateDB) { bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 466a86c144..5143edb0fa 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -278,7 +278,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int { // HasState checks if state trie is fully present in the database or not. func (bc *BlockChain) HasState(hash common.Hash) bool { - _, err := bc.stateCache.OpenTrie(hash) + _, err := bc.StateAt(hash) return err == nil } @@ -311,12 +311,9 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool { // If the code doesn't exist in the in-memory cache, check the storage with // new code scheme. func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) { - type codeReader interface { - ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) - } // TODO(rjl493456442) The associated account address is also required // in Verkle scheme. Fix it once snap-sync is supported for Verkle. - return bc.stateCache.(codeReader).ContractCodeWithPrefix(common.Address{}, hash) + return bc.codedb.ReadCodeWithPrefix(common.Address{}, hash) } // State returns a new mutable state based on the current HEAD block. @@ -326,7 +323,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) { // StateAt returns a new mutable state based on a particular point in time. func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { - return state.New(root, bc.stateCache, bc.snaps) + return state.New(root, state.NewDatabase(bc.codedb, bc.triedb), bc.snaps) } // Config retrieves the chain's fork configuration. @@ -350,11 +347,6 @@ func (bc *BlockChain) Processor() Processor { return bc.processor } -// StateCache returns the caching database underpinning the blockchain instance. -func (bc *BlockChain) StateCache() state.Database { - return bc.stateCache -} - // GasLimit returns the gas limit of the current HEAD block. func (bc *BlockChain) GasLimit() uint64 { return bc.CurrentBlock().GasLimit @@ -387,6 +379,11 @@ func (bc *BlockChain) TrieDB() *trie.Database { return bc.triedb } +// CodeDB retrieves the low level code database used for contract code storage. +func (bc *BlockChain) CodeDB() *state.CodeDB { + return bc.codedb +} + // SubscribeRemovedLogsEvent registers a subscription of RemovedLogsEvent. func (bc *BlockChain) SubscribeRemovedLogsEvent(ch chan<- RemovedLogsEvent) event.Subscription { return bc.scope.Track(bc.rmLogsFeed.Subscribe(ch)) diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index fa739f924f..cb335feaf1 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -30,7 +30,6 @@ 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" @@ -2040,7 +2039,6 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme dbconfig.HashDB = hashdb.Defaults } chain.triedb = trie.NewDatabase(chain.db, dbconfig) - chain.stateCache = state.NewDatabaseWithNodeDB(chain.db, chain.triedb) // Force run a freeze cycle type freezer interface { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index bc6f8112f0..c176241438 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -158,7 +158,8 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { } return err } - statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache, nil) + sdb := state.NewDatabase(blockchain.CodeDB(), blockchain.TrieDB()) + statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), sdb, nil) if err != nil { return err } diff --git a/core/chain_makers.go b/core/chain_makers.go index 31c111b73e..3cb9660a69 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -364,8 +364,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse triedb := trie.NewDatabase(db, trie.HashDefaults) defer triedb.Close() + codedb := state.NewCodeDB(db) + 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(codedb, triedb), nil) if err != nil { panic(err) } diff --git a/core/genesis.go b/core/genesis.go index 634be9a9e0..05c2fc1896 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -135,7 +135,8 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. - db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config) + memorydb := rawdb.NewMemoryDatabase() + db := state.NewDatabase(state.NewCodeDB(memorydb), trie.NewDatabase(memorydb, config)) statedb, err := state.New(types.EmptyRootHash, db, nil) if err != nil { return common.Hash{}, err @@ -150,14 +151,14 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { statedb.SetState(addr, key, value) } } - return statedb.Commit(0, false) + return statedb.IntermediateRoot(false), nil } // flush is very similar with hash, but the main difference is all the generated // states will be persisted into the given database. Also, the genesis state // specification will be flushed as well. func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error { - statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(state.NewCodeDB(db), triedb), nil) if err != nil { return err } diff --git a/core/state/codedb.go b/core/state/codedb.go new file mode 100644 index 0000000000..3296c65e72 --- /dev/null +++ b/core/state/codedb.go @@ -0,0 +1,114 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package state + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +const ( + // Number of codehash->size associations to keep. + codeSizeCacheSize = 100000 + + // Cache size granted for caching clean code. + codeCacheSize = 64 * 1024 * 1024 +) + +var errMismatchedLength = errors.New("provided lists have different lengths") + +// CodeDB is an implementation of the CodeStore interface, designed for providing +// efficient read and write functionalities for contract code. +type CodeDB struct { + db ethdb.KeyValueStore + size *lru.Cache[common.Hash, int] + cache *lru.SizeConstrainedCache[common.Hash, []byte] +} + +// NewCodeDB returns a codeDB instance with given database. +func NewCodeDB(db ethdb.KeyValueStore) *CodeDB { + return &CodeDB{ + db: db, + size: lru.NewCache[common.Hash, int](codeSizeCacheSize), + cache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + } +} + +// ReadCode implements CodeReader, retrieving a particular contract's code +// with given contract address and code hash. +func (db *CodeDB) ReadCode(address common.Address, codeHash common.Hash) ([]byte, error) { + code, _ := db.cache.Get(codeHash) + if len(code) > 0 { + return code, nil + } + code = rawdb.ReadCode(db.db, codeHash) + if len(code) > 0 { + db.cache.Add(codeHash, code) + db.size.Add(codeHash, len(code)) + return code, nil + } + return nil, errors.New("not found") +} + +// ReadCodeSize implements CodeReader, retrieving a particular contracts code's size +// with given contract address and code hash. +func (db *CodeDB) ReadCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + if cached, ok := db.size.Get(codeHash); ok { + return cached, nil + } + code, err := db.ReadCode(addr, codeHash) + if err != nil { + return 0, err + } + return len(code), nil +} + +// WriteCodes implements CodeWriter, writing the provided a list of contract codes +// into database. +func (db *CodeDB) WriteCodes(addresses []common.Address, hashes []common.Hash, codes [][]byte) error { + if len(addresses) != len(hashes) { + return errMismatchedLength + } + if len(addresses) != len(codes) { + return errMismatchedLength + } + batch := db.db.NewBatch() + for i := 0; i < len(addresses); i++ { + rawdb.WriteCode(batch, hashes[i], codes[i]) + } + return batch.Write() +} + +// ReadCodeWithPrefix retrieves a particular contract's code. If the code can't +// be found in the cache, then check the existence with **new** db scheme. +func (db *CodeDB) ReadCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { + code, _ := db.cache.Get(codeHash) + if len(code) > 0 { + return code, nil + } + code = rawdb.ReadCodeWithPrefix(db.db, codeHash) + if len(code) > 0 { + db.cache.Add(codeHash, code) + db.size.Add(codeHash, len(code)) + return code, nil + } + return nil, errors.New("not found") +} diff --git a/core/state/database.go b/core/state/database.go index b55f870d90..3d51e711ab 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -17,13 +17,10 @@ package state import ( - "errors" "fmt" "github.com/crate-crypto/go-ipa/banderwagon" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "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" @@ -32,13 +29,7 @@ import ( "github.com/ethereum/go-ethereum/trie/utils" ) -const ( - // Number of codehash->size associations to keep. - codeSizeCacheSize = 100000 - - // Cache size granted for caching clean code. - codeCacheSize = 64 * 1024 * 1024 - +var ( // commitmentSize is the size of commitment stored in cache. commitmentSize = banderwagon.UncompressedSize @@ -46,8 +37,35 @@ const ( commitmentCacheItems = 64 * 1024 * 1024 / (commitmentSize + common.AddressLength) ) -// Database wraps access to tries and contract code. +// CodeReader wraps the ReadCode and ReadCodeSize methods of a backing contract +// code store, providing an interface for retrieving contract code and its size. +type CodeReader interface { + // ReadCode retrieves a particular contract's code. + ReadCode(addr common.Address, codeHash common.Hash) ([]byte, error) + + // ReadCodeSize retrieves a particular contracts code's size. + ReadCodeSize(addr common.Address, codeHash common.Hash) (int, error) +} + +// CodeWriter wraps the WriteCodes method of a backing contract code store, +// providing an interface for writing contract codes back to database. +type CodeWriter interface { + // WriteCodes persists the provided a batch of contract codes. + WriteCodes(addresses []common.Address, codeHashes []common.Hash, codes [][]byte) error +} + +// CodeStore defines the essential methods for reading and writing contract codes, +// providing a comprehensive interface for code management. +type CodeStore interface { + CodeReader + CodeWriter +} + +// Database defines the essential methods for reading and writing ethereum states, +// providing a comprehensive interface for ethereum state management. type Database interface { + CodeStore + // OpenTrie opens the main account trie. OpenTrie(root common.Hash) (Trie, error) @@ -57,20 +75,12 @@ type Database interface { // CopyTrie returns an independent copy of the given trie. CopyTrie(Trie) Trie - // ContractCode retrieves a particular contract's code. - ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) - - // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) - - // DiskDB returns the underlying key-value disk database. - DiskDB() ethdb.KeyValueStore - // TrieDB returns the underlying trie database for managing trie nodes. TrieDB() *trie.Database } -// Trie is a Ethereum Merkle Patricia trie. +// Trie is a Ethereum state trie interface, defining the essential methods +// to read and write states via trie. type Trie interface { // GetKey returns the sha3 preimage of a hashed key that was previously used // to store a value. @@ -140,40 +150,27 @@ type Trie interface { Prove(key []byte, proofDb ethdb.KeyValueWriter) error } -// NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use, but does not retain any recent trie nodes in memory. To keep some -// historical state in memory, use the NewDatabaseWithConfig constructor. -func NewDatabase(db ethdb.Database) Database { - return NewDatabaseWithConfig(db, nil) -} - -// NewDatabaseWithConfig creates a backing store for state. The returned database -// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a -// large memory cache. -func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { +// NewDatabase creates a state database with the provided contract code store +// and trie node database. +func NewDatabase(codedb *CodeDB, triedb *trie.Database) Database { return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: trie.NewDatabase(db, config), + codedb: codedb, + triedb: triedb, } } -// NewDatabaseWithNodeDB creates a state database with an already initialized node database. -func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database { - return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb, - } +// NewDatabaseForTesting is similar to NewDatabase, but it sets up a local code +// store and trie database with default config by using the provided database, +// specifically intended for testing. +func NewDatabaseForTesting(db ethdb.Database) Database { + return NewDatabase(NewCodeDB(db), trie.NewDatabase(db, nil)) } +// cachingDB is the implementation of Database interface, designed for providing +// functionalities to read and write states. type cachingDB struct { - disk ethdb.KeyValueStore - codeSizeCache *lru.Cache[common.Hash, int] - codeCache *lru.SizeConstrainedCache[common.Hash, []byte] - triedb *trie.Database + codedb *CodeDB + triedb *trie.Database } // OpenTrie opens the main account trie at a specific root hash. @@ -181,11 +178,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { if db.triedb.IsVerkle() { return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(commitmentCacheItems)) } - tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) - if err != nil { - return nil, err - } - return tr, nil + return trie.NewStateTrie(trie.StateTrieID(root), db.triedb) } // OpenStorageTrie opens the storage trie of an account. @@ -196,11 +189,7 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre if db.triedb.IsVerkle() { return self, nil } - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) - if err != nil { - return nil, err - } - return tr, nil + return trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) } // CopyTrie returns an independent copy of the given trie. @@ -213,50 +202,21 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { } } -// ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { - code, _ := db.codeCache.Get(codeHash) - if len(code) > 0 { - return code, nil - } - code = rawdb.ReadCode(db.disk, codeHash) - if len(code) > 0 { - db.codeCache.Add(codeHash, code) - db.codeSizeCache.Add(codeHash, len(code)) - return code, nil - } - return nil, errors.New("not found") +// ReadCode implements CodeReader, retrieving a particular contract's code. +func (db *cachingDB) ReadCode(address common.Address, codeHash common.Hash) ([]byte, error) { + return db.codedb.ReadCode(address, codeHash) } -// ContractCodeWithPrefix retrieves a particular contract's code. If the -// code can't be found in the cache, then check the existence with **new** -// db scheme. -func (db *cachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) { - code, _ := db.codeCache.Get(codeHash) - if len(code) > 0 { - return code, nil - } - code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) - if len(code) > 0 { - db.codeCache.Add(codeHash, code) - db.codeSizeCache.Add(codeHash, len(code)) - return code, nil - } - return nil, errors.New("not found") +// ReadCodeSize implements CodeReader, retrieving a particular contracts +// code's size. +func (db *cachingDB) ReadCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + return db.codedb.ReadCodeSize(addr, codeHash) } -// ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { - if cached, ok := db.codeSizeCache.Get(codeHash); ok { - return cached, nil - } - code, err := db.ContractCode(addr, codeHash) - return len(code), err -} - -// DiskDB returns the underlying key-value disk database. -func (db *cachingDB) DiskDB() ethdb.KeyValueStore { - return db.disk +// WriteCodes implements CodeWriter, writing the provided a list of contract +// codes into database. +func (db *cachingDB) WriteCodes(addresses []common.Address, hashes []common.Hash, codes [][]byte) error { + return db.codedb.WriteCodes(addresses, hashes, codes) } // TrieDB retrieves any intermediate trie-node caching layer. diff --git a/core/state/iterator.go b/core/state/iterator.go index dc84ce689b..d5858861fc 100644 --- a/core/state/iterator.go +++ b/core/state/iterator.go @@ -136,7 +136,7 @@ func (it *nodeIterator) step() error { } if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { it.codeHash = common.BytesToHash(account.CodeHash) - it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash)) + it.code, err = it.state.db.ReadCode(address, common.BytesToHash(account.CodeHash)) if err != nil { return fmt.Errorf("code %x: %v", account.CodeHash, err) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 9383b98e44..ca26601039 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -476,7 +476,7 @@ func (s *stateObject) Code() []byte { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return nil } - code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash())) + code, err := s.db.db.ReadCode(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err)) } @@ -494,7 +494,7 @@ func (s *stateObject) CodeSize() int { if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) { return 0 } - size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash())) + size, err := s.db.db.ReadCodeSize(s.address, common.BytesToHash(s.CodeHash())) if err != nil { s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err)) } diff --git a/core/state/state_test.go b/core/state/state_test.go index 2f45ba44b4..46e10af59a 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -37,14 +37,16 @@ type stateEnv struct { func newStateEnv() *stateEnv { db := rawdb.NewMemoryDatabase() - sdb, _ := New(types.EmptyRootHash, NewDatabase(db), nil) + sdb, _ := New(types.EmptyRootHash, NewDatabaseForTesting(db), nil) return &stateEnv{db: db, state: sdb} } func TestDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) + tdb := trie.NewDatabase(db, &trie.Config{Preimages: true}) + defer tdb.Close() + + sdb, _ := New(types.EmptyRootHash, NewDatabase(NewCodeDB(db), tdb), nil) s := &stateEnv{db: db, state: sdb} // generate a few entries @@ -61,7 +63,7 @@ func TestDump(t *testing.T) { root, _ := s.state.Commit(0, false) // check that DumpToCollector contains the state objects that are in trie - s.state, _ = New(root, tdb, nil) + s.state, _ = New(root, NewDatabase(NewCodeDB(db), tdb), nil) got := string(s.state.Dump(nil)) want := `{ "root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2", @@ -100,8 +102,10 @@ func TestDump(t *testing.T) { func TestIterativeDump(t *testing.T) { db := rawdb.NewMemoryDatabase() - tdb := NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) - sdb, _ := New(types.EmptyRootHash, tdb, nil) + tdb := trie.NewDatabase(db, &trie.Config{Preimages: true}) + defer tdb.Close() + + sdb, _ := New(types.EmptyRootHash, NewDatabase(NewCodeDB(db), tdb), nil) s := &stateEnv{db: db, state: sdb} // generate a few entries @@ -118,7 +122,7 @@ func TestIterativeDump(t *testing.T) { s.state.updateStateObject(obj1) s.state.updateStateObject(obj2) root, _ := s.state.Commit(0, false) - s.state, _ = New(root, tdb, nil) + s.state, _ = New(root, NewDatabase(NewCodeDB(db), tdb), nil) b := &bytes.Buffer{} s.state.IterativeDump(nil, json.NewEncoder(b)) @@ -194,7 +198,7 @@ func TestSnapshotEmpty(t *testing.T) { } func TestSnapshot2(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) stateobjaddr0 := common.BytesToAddress([]byte("so0")) stateobjaddr1 := common.BytesToAddress([]byte("so1")) diff --git a/core/state/statedb.go b/core/state/statedb.go index 905944cbb5..4e18b85ae6 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1171,12 +1171,19 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er // Commit objects to the trie, measuring the elapsed time var ( + // Metrics accountTrieNodesUpdated int accountTrieNodesDeleted int storageTrieNodesUpdated int storageTrieNodesDeleted int - nodes = trienode.NewMergedNodeSet() - codeWriter = s.db.DiskDB().NewBatch() + + // Un-flushed contract codes + addresses []common.Address + codeHashes []common.Hash + codes [][]byte + + // Un-flushed trie nodes + nodes = trienode.NewMergedNodeSet() ) // Handle all state deletions first incomplete, err := s.handleDestruction(nodes) @@ -1191,8 +1198,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } // Write any contract code associated with the state object if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) obj.dirtyCode = false + + // Collect dirty contract codes for later write in a single batch. + addresses = append(addresses, addr) + codeHashes = append(codeHashes, common.BytesToHash(obj.CodeHash())) + codes = append(codes, obj.code) } // Write any storage changes in the state object to its storage trie set, err := obj.commit() @@ -1211,10 +1222,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er storageTrieNodesDeleted += deleted } } - if codeWriter.ValueSize() > 0 { - if err := codeWriter.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } + if err := s.db.WriteCodes(addresses, codeHashes, codes); err != nil { + return common.Hash{}, err } // Write the account trie changes, measuring the amount of wasted time var start time.Time diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index c4704257c7..4c3863d074 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -182,7 +182,7 @@ func (test *stateTest) run() bool { } disk = rawdb.NewMemoryDatabase() tdb = trie.NewDatabase(disk, &trie.Config{PathDB: pathdb.Defaults}) - sdb = NewDatabaseWithNodeDB(disk, tdb) + sdb = NewDatabase(NewCodeDB(disk), tdb) byzantium = rand.Intn(2) == 0 ) defer disk.Close() diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index df1cd5547d..a6186a3ad5 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -51,7 +51,7 @@ func TestUpdateLeaks(t *testing.T) { db = rawdb.NewMemoryDatabase() tdb = trie.NewDatabase(db, nil) ) - state, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(db, tdb), nil) + state, _ := New(types.EmptyRootHash, NewDatabase(NewCodeDB(db), tdb), nil) // Update it with some accounts for i := byte(0); i < 255; i++ { @@ -87,8 +87,8 @@ func TestIntermediateLeaks(t *testing.T) { 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(NewCodeDB(transDb), transNdb), nil) + finalState, _ := New(types.EmptyRootHash, NewDatabase(NewCodeDB(finalDb), finalNdb), nil) modify := func(state *StateDB, addr common.Address, i, tweak byte) { state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) @@ -163,7 +163,7 @@ func TestIntermediateLeaks(t *testing.T) { // https://github.com/ethereum/go-ethereum/pull/15549. func TestCopy(t *testing.T) { // Create a random state test to copy and modify "independently" - orig, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + orig, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) for i := byte(0); i < 255; i++ { obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) @@ -423,7 +423,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - state, _ = New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ = New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 checkstates = make([]*StateDB, len(test.snapshots)) @@ -550,7 +550,7 @@ func TestTouchDelete(t *testing.T) { // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 func TestCopyOfCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) addr := common.HexToAddress("aaaa") state.SetBalance(addr, big.NewInt(42)) @@ -567,7 +567,7 @@ func TestCopyOfCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCommitCopy(t *testing.T) { - tdb := NewDatabase(rawdb.NewMemoryDatabase()) + tdb := NewDatabaseForTesting(rawdb.NewMemoryDatabase()) state, _ := New(types.EmptyRootHash, tdb, nil) // Create an account and check if the retrieved balance is correct @@ -641,7 +641,7 @@ func TestCopyCommitCopy(t *testing.T) { // // See https://github.com/ethereum/go-ethereum/issues/20106. func TestCopyCopyCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -710,7 +710,7 @@ func TestCopyCopyCommitCopy(t *testing.T) { // TestCommitCopy tests the copy from a committed state is not functional. func TestCommitCopy(t *testing.T) { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") @@ -763,7 +763,7 @@ func TestCommitCopy(t *testing.T) { // first, but the journal wiped the entire state object on create-revert. func TestDeleteCreateRevert(t *testing.T) { // Create an initial state with a single contract - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, big.NewInt(1)) @@ -812,7 +812,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { CleanCacheSize: 0, }}) // disable caching } - db := NewDatabaseWithNodeDB(memDb, triedb) + db := NewDatabase(NewCodeDB(memDb), triedb) var root common.Hash state, _ := New(types.EmptyRootHash, db, nil) @@ -863,7 +863,7 @@ func TestStateDBAccessList(t *testing.T) { } memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) + db := NewDatabaseForTesting(memDb) state, _ := New(types.EmptyRootHash, db, nil) state.accessList = newAccessList() @@ -1034,7 +1034,7 @@ func TestFlushOrderDataLoss(t *testing.T) { var ( memdb = rawdb.NewMemoryDatabase() triedb = trie.NewDatabase(memdb, nil) - statedb = NewDatabaseWithNodeDB(memdb, triedb) + statedb = NewDatabase(NewCodeDB(memdb), triedb) state, _ = New(types.EmptyRootHash, statedb, nil) ) for a := byte(0); a < 10; a++ { @@ -1055,7 +1055,7 @@ func TestFlushOrderDataLoss(t *testing.T) { t.Fatalf("failed to commit state trie: %v", err) } // Reopen the state trie from flushed disk and verify it - state, err = New(root, NewDatabase(memdb), nil) + state, err = New(root, NewDatabaseForTesting(memdb), nil) if err != nil { t.Fatalf("failed to reopen state trie: %v", err) } @@ -1070,7 +1070,7 @@ func TestFlushOrderDataLoss(t *testing.T) { func TestStateDBTransientStorage(t *testing.T) { memDb := rawdb.NewMemoryDatabase() - db := NewDatabase(memDb) + db := NewDatabaseForTesting(memDb) state, _ := New(types.EmptyRootHash, db, nil) key := common.Hash{0x01} @@ -1106,7 +1106,7 @@ func TestResetObject(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() tdb = trie.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) + db = NewDatabase(NewCodeDB(disk), tdb) snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) state, _ = New(types.EmptyRootHash, db, snaps) addr = common.HexToAddress("0x1") @@ -1140,7 +1140,7 @@ func TestDeleteStorage(t *testing.T) { var ( disk = rawdb.NewMemoryDatabase() tdb = trie.NewDatabase(disk, nil) - db = NewDatabaseWithNodeDB(disk, tdb) + db = NewDatabase(NewCodeDB(disk), tdb) snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash) state, _ = New(types.EmptyRootHash, db, snaps) addr = common.HexToAddress("0x1") diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 6196e77817..2f8932ab53 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -51,7 +51,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com } db := rawdb.NewMemoryDatabase() nodeDb := trie.NewDatabase(db, config) - sdb := NewDatabaseWithNodeDB(db, nodeDb) + sdb := NewDatabase(NewCodeDB(db), nodeDb) state, _ := New(types.EmptyRootHash, sdb, nil) // Fill it with some arbitrary data @@ -92,7 +92,10 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, scheme string, root com config.PathDB = pathdb.Defaults } // Check root availability and state contents - state, err := New(root, NewDatabaseWithConfig(db, &config), nil) + tdb := trie.NewDatabase(db, &config) + defer tdb.Close() + + state, err := New(root, NewDatabase(NewCodeDB(db), tdb), nil) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } @@ -118,7 +121,10 @@ func checkStateConsistency(db ethdb.Database, scheme string, root common.Hash) e if scheme == rawdb.PathScheme { config.PathDB = pathdb.Defaults } - state, err := New(root, NewDatabaseWithConfig(db, config), nil) + tdb := trie.NewDatabase(db, config) + defer tdb.Close() + + state, err := New(root, NewDatabase(NewCodeDB(db), tdb), nil) if err != nil { return err } @@ -215,7 +221,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s codeResults = make([]trie.CodeSyncResult, len(codeElements)) ) for i, element := range codeElements { - data, err := srcDb.ContractCode(common.Address{}, element.code) + data, err := srcDb.ReadCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code) } @@ -335,7 +341,7 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) { if len(codeElements) > 0 { codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1) for i, element := range codeElements[:len(codeResults)] { - data, err := srcDb.ContractCode(common.Address{}, element.code) + data, err := srcDb.ReadCode(common.Address{}, element.code) if err != nil { t.Fatalf("failed to retrieve contract bytecode for %x", element.code) } @@ -437,7 +443,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Address{}, hash) + data, err := srcDb.ReadCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -532,7 +538,7 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) { for hash := range codeQueue { delete(codeQueue, hash) - data, err := srcDb.ContractCode(common.Address{}, hash) + data, err := srcDb.ReadCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } @@ -648,7 +654,7 @@ func testIncompleteStateSync(t *testing.T, scheme string) { if len(codeQueue) > 0 { results := make([]trie.CodeSyncResult, 0, len(codeQueue)) for hash := range codeQueue { - data, err := srcDb.ContractCode(common.Address{}, hash) + data, err := srcDb.ReadCode(common.Address{}, hash) if err != nil { t.Fatalf("failed to retrieve node data for %x", hash) } diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index b190567e92..b9a14aadc8 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -27,7 +27,7 @@ import ( ) func filledStateDB() *StateDB { - state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := New(types.EmptyRootHash, NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) // Create an account and check if the retrieved balance is correct addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index b709ad0e58..75da880e80 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -511,7 +511,7 @@ func TestOpenDrops(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewDatabase(memorydb.New())), nil) statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000)) statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000)) statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000)) @@ -636,7 +636,7 @@ func TestOpenIndex(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewDatabase(memorydb.New())), nil) statedb.AddBalance(addr, big.NewInt(1_000_000_000)) statedb.Commit(0, true) @@ -736,7 +736,7 @@ func TestOpenHeap(t *testing.T) { store.Close() // Create a blob pool out of the pre-seeded data - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewDatabase(memorydb.New())), nil) statedb.AddBalance(addr1, big.NewInt(1_000_000_000)) statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) @@ -816,7 +816,7 @@ func TestOpenCap(t *testing.T) { // with a high cap to ensure everything was persisted previously for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewDatabase(memorydb.New())), nil) statedb.AddBalance(addr1, big.NewInt(1_000_000_000)) statedb.AddBalance(addr2, big.NewInt(1_000_000_000)) statedb.AddBalance(addr3, big.NewInt(1_000_000_000)) @@ -1203,7 +1203,7 @@ func TestAdd(t *testing.T) { keys = make(map[string]*ecdsa.PrivateKey) addrs = make(map[string]common.Address) ) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewDatabase(memorydb.New())), nil) for acc, seed := range tt.seeds { // Generate a new random key/address for the seed account keys[acc], _ = crypto.GenerateKey() diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index a73c1bb8a7..c5182254f9 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -78,7 +78,7 @@ func TestTransactionFutureAttack(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 @@ -115,7 +115,7 @@ func TestTransactionFutureAttack(t *testing.T) { func TestTransactionFuture1559(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) @@ -148,7 +148,7 @@ func TestTransactionFuture1559(t *testing.T) { func TestTransactionZAttack(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) pool.Init(new(big.Int).SetUint64(testTxPoolConfig.PriceLimit), blockchain.CurrentBlock(), makeAddressReserver()) @@ -216,7 +216,7 @@ func TestTransactionZAttack(t *testing.T) { func BenchmarkFutureAttack(b *testing.B) { // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig config.GlobalQueue = 100 diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 0366a58d61..561a0a1d75 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -158,7 +158,7 @@ func setupPool() (*LegacyPool, *ecdsa.PrivateKey) { } func setupPoolWithConfig(config *params.ChainConfig) (*LegacyPool, *ecdsa.PrivateKey) { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(config, 10000000, statedb, new(event.Feed)) key, _ := crypto.GenerateKey() @@ -252,7 +252,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + c.statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether)) @@ -270,7 +270,7 @@ func TestStateChangeDuringReset(t *testing.T) { var ( key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) trigger = false ) @@ -469,7 +469,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) @@ -498,7 +498,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.AddBalance(addr, big.NewInt(100000000000000)) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) @@ -698,7 +698,7 @@ func TestPostponing(t *testing.T) { t.Parallel() // Create the pool to test the postponing with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -911,7 +911,7 @@ func testQueueGlobalLimiting(t *testing.T, nolocals bool) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1004,7 +1004,7 @@ func testQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Millisecond * 100 // Create the pool to test the non-expiration enforcement - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1190,7 +1190,7 @@ func TestPendingGlobalLimiting(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1292,7 +1292,7 @@ func TestCapClearsFromAll(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1327,7 +1327,7 @@ func TestPendingMinimumAllowance(t *testing.T) { t.Parallel() // Create the pool to test the limit enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1376,7 +1376,7 @@ func TestRepricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -1496,7 +1496,8 @@ func TestMinGasPriceEnforced(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + memorydb := rawdb.NewMemoryDatabase() + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(state.NewCodeDB(memorydb), trie.NewDatabase(memorydb, nil)), nil) blockchain := newTestBlockChain(eip1559Config, 10000000, statedb, new(event.Feed)) txPoolConfig := DefaultConfig @@ -1669,7 +1670,7 @@ func TestRepricingKeepsLocals(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(eip1559Config, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -1743,7 +1744,7 @@ func TestUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -1858,7 +1859,7 @@ func TestStableUnderpricing(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2091,7 +2092,7 @@ func TestDeduplication(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -2158,7 +2159,7 @@ func TestReplacement(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) @@ -2364,7 +2365,7 @@ func testJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) config := testTxPoolConfig @@ -2465,7 +2466,7 @@ func TestStatusCheck(t *testing.T) { t.Parallel() // Create the pool to test the status retrievals with - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) blockchain := newTestBlockChain(params.TestChainConfig, 1000000, statedb, new(event.Feed)) pool := New(testTxPoolConfig, blockchain) diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 4a5259a262..1410ee143d 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -84,7 +84,7 @@ func TestEIP2200(t *testing.T) { for i, tt := range eip2200Tests { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.input)) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) @@ -136,7 +136,7 @@ func TestCreateGas(t *testing.T) { var gasUsed = uint64(0) doCheck := func(testGas int) bool { address := common.BytesToAddress([]byte("contract")) - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.code)) statedb.Finalise(true) diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 807073336d..0aa66ba522 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -582,7 +582,7 @@ func BenchmarkOpMstore(bench *testing.B) { func TestOpTstore(t *testing.T) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) env = NewEVM(BlockContext{}, TxContext{}, statedb, params.TestChainConfig, Config{}) stack = newstack() mem = NewMemory() diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index 96e681fccd..86a5bdc629 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -43,7 +43,7 @@ func TestLoopInterrupt(t *testing.T) { } for i, tt := range loopInterruptTests { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.CreateAccount(address) statedb.SetCode(address, common.Hex2Bytes(tt)) statedb.Finalise(true) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index d10457e7fa..00e128acab 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -114,7 +114,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) } var ( address = common.BytesToAddress([]byte("contract")) @@ -148,7 +148,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) } var ( vmenv = NewEnv(cfg) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index e71760bb23..df09f4d8d4 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -103,7 +103,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + state, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, @@ -159,7 +159,7 @@ func BenchmarkCall(b *testing.B) { } func benchmarkEVM_Create(bench *testing.B, code string) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) sender = common.BytesToAddress([]byte("sender")) receiver = common.BytesToAddress([]byte("receiver")) ) @@ -327,7 +327,7 @@ func TestBlockhash(t *testing.T) { func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode string, b *testing.B) { cfg := new(Config) setDefaults(cfg) - cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil) @@ -818,7 +818,7 @@ func TestRuntimeJSTracer(t *testing.T) { main := common.HexToAddress("0xaa") for i, jsTracer := range jsTracers { for j, tc := range tests { - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) statedb.SetCode(main, tc.code) statedb.SetCode(common.HexToAddress("0xbb"), calleeCode) statedb.SetCode(common.HexToAddress("0xcc"), calleeCode) @@ -860,7 +860,7 @@ func TestJSTracerCreateTx(t *testing.T) { exit: function(res) { this.exits++ }}` code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()), nil) tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 184b90dd09..08bf6b91b6 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -36,7 +36,7 @@ import ( var dumper = spew.ConfigState{Indent: " "} -func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.Dump { +func accountRangeTest(t *testing.T, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.Dump { result := statedb.RawDump(&state.DumpConfig{ SkipCode: true, SkipStorage: true, @@ -63,11 +63,13 @@ func TestAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) - sdb, _ = state.New(types.EmptyRootHash, statedb, nil) - addrs = [AccountRangeMaxResults * 2]common.Address{} - m = map[common.Address]bool{} + disk = rawdb.NewMemoryDatabase() + tdb = trie.NewDatabase(disk, &trie.Config{Preimages: true}) + sdb, _ = state.New(types.EmptyRootHash, state.NewDatabase(state.NewCodeDB(disk), tdb), nil) + addrs = [AccountRangeMaxResults * 2]common.Address{} + m = map[common.Address]bool{} ) + defer tdb.Close() for i := range addrs { hash := common.HexToHash(fmt.Sprintf("%x", i)) @@ -81,16 +83,12 @@ func TestAccountRange(t *testing.T) { } } root, _ := sdb.Commit(0, true) - sdb, _ = state.New(root, statedb, nil) + sdb, _ = state.New(root, state.NewDatabase(state.NewCodeDB(disk), tdb), nil) - trie, err := statedb.OpenTrie(root) - if err != nil { - t.Fatal(err) - } - accountRangeTest(t, &trie, sdb, common.Hash{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2) + accountRangeTest(t, sdb, common.Hash{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2) // test pagination - firstResult := accountRangeTest(t, &trie, sdb, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) - secondResult := accountRangeTest(t, &trie, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) + firstResult := accountRangeTest(t, sdb, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) + secondResult := accountRangeTest(t, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) hList := make([]common.Hash, 0) for addr1, acc := range firstResult.Accounts { @@ -108,7 +106,7 @@ func TestAccountRange(t *testing.T) { // set and get an even split between the first and second sets. slices.SortFunc(hList, common.Hash.Cmp) middleH := hList[AccountRangeMaxResults/2] - middleResult := accountRangeTest(t, &trie, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults) + middleResult := accountRangeTest(t, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults) missing, infirst, insecond := 0, 0, 0 for h := range middleResult.Accounts { if _, ok := firstResult.Accounts[h]; ok { @@ -134,7 +132,7 @@ func TestEmptyAccountRange(t *testing.T) { t.Parallel() var ( - statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) + statedb = state.NewDatabaseForTesting(rawdb.NewMemoryDatabase()) st, _ = state.New(types.EmptyRootHash, statedb, nil) ) // Commit(although nothing to flush) and re-init the statedb @@ -160,8 +158,9 @@ func TestStorageRangeAt(t *testing.T) { // Create a state where account 0x010000... has a few storage entries. var ( - db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true}) - sdb, _ = state.New(types.EmptyRootHash, db, nil) + disk = rawdb.NewMemoryDatabase() + tdb = trie.NewDatabase(disk, &trie.Config{Preimages: true}) + sdb, _ = state.New(types.EmptyRootHash, state.NewDatabase(state.NewCodeDB(disk), tdb), nil) addr = common.Address{0x01} keys = []common.Hash{ // hashes of Keys of storage common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"), @@ -176,11 +175,13 @@ func TestStorageRangeAt(t *testing.T) { keys[3]: {Key: &common.Hash{0x03}, Value: common.Hash{0x04}}, } ) + defer tdb.Close() + for _, entry := range storage { sdb.SetState(addr, *entry.Key, entry.Value) } root, _ := sdb.Commit(0, false) - sdb, _ = state.New(root, db, nil) + sdb, _ = state.New(root, state.NewDatabase(state.NewCodeDB(disk), tdb), nil) // Check a few combinations of limit and start/end. tests := []struct { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 24694df66c..9c8646d17e 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -67,8 +67,8 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // 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) - if statedb, err = state.New(block.Root(), database, nil); err == nil { + tdb := trie.NewDatabase(eth.chainDb, trie.HashDefaults) + if statedb, err = state.New(block.Root(), state.NewDatabase(state.NewCodeDB(eth.chainDb), tdb), nil); err == nil { log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number()) return statedb, noopReleaser, nil } @@ -85,7 +85,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u // 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.NewDatabase(state.NewCodeDB(eth.chainDb), triedb) // 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 diff --git a/miner/miner_test.go b/miner/miner_test.go index 411d6026ce..12f57a69f9 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -313,7 +313,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(bc.Genesis().Root(), state.NewDatabase(bc.CodeDB(), bc.TrieDB()), nil) blockchain := &testBlockChain{bc.Genesis().Root(), chainConfig, statedb, 10000000, new(event.Feed)} pool := legacypool.New(testTxPoolConfig, blockchain) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 745a3c6b28..6c9da89271 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -317,7 +317,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter boo tconf.PathDB = pathdb.Defaults } triedb := trie.NewDatabase(db, tconf) - sdb := state.NewDatabaseWithNodeDB(db, triedb) + sdb := state.NewDatabase(state.NewCodeDB(db), triedb) statedb, _ := state.New(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { statedb.SetCode(addr, a.Code)