From 676200638360275f18a5025f6124ff78e1707521 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 19 Jun 2025 17:43:24 +0800 Subject: [PATCH 01/10] core: simplify effectiveTip calculation (#31771) Since we have the effective gas price in the message, we can compute tip by simply subtracting the basefee. No need to recompute the effective price. --------- Co-authored-by: Felix Lange --- core/state_transition.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 4f172682d0..3ec718c52c 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -534,10 +534,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { effectiveTip := msg.GasPrice if rules.IsLondon { - effectiveTip = new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee) - if effectiveTip.Cmp(msg.GasTipCap) > 0 { - effectiveTip = msg.GasTipCap - } + effectiveTip = new(big.Int).Sub(msg.GasPrice, st.evm.Context.BaseFee) } effectiveTipU256, _ := uint256.FromBig(effectiveTip) From ac50181b74c6046bfbd894a3ea4156c7943581e0 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 19 Jun 2025 18:21:15 +0800 Subject: [PATCH 02/10] core: consolidate BlockChain constructor options (#31925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this pull request, the original `CacheConfig` has been renamed to `BlockChainConfig`. Over time, more fields have been added to `CacheConfig` to support blockchain configuration. Such as `ChainHistoryMode`, which clearly extends beyond just caching concerns. Additionally, adding new parameters to the blockchain constructor has become increasingly complicated, since it’s initialized across multiple places in the codebase. A natural solution is to consolidate these arguments into a dedicated configuration struct. As a result, the existing `CacheConfig` has been redefined as `BlockChainConfig`. Some parameters, such as `VmConfig`, `TxLookupLimit`, and `ChainOverrides` have been moved into `BlockChainConfig`. Besides, a few fields in `BlockChainConfig` were renamed, specifically: - `TrieCleanNoPrefetch` -> `NoPrefetch` - `TrieDirtyDisabled` -> `ArchiveMode` Notably, this change won't affect the command line flags or the toml configuration file. It's just an internal refactoring and fully backward-compatible. --------- Co-authored-by: Felix Lange --- cmd/utils/flags.go | 41 +++-- cmd/utils/history_test.go | 5 +- consensus/clique/clique_test.go | 7 +- consensus/clique/snapshot_test.go | 3 +- core/bench_test.go | 9 +- core/block_validator_test.go | 6 +- core/blockchain.go | 164 ++++++++++-------- core/blockchain_reader.go | 2 +- core/blockchain_repair_test.go | 21 +-- core/blockchain_sethead_test.go | 14 +- core/blockchain_snapshot_test.go | 31 ++-- core/blockchain_test.go | 127 ++++++++------ core/chain_makers.go | 2 +- core/chain_makers_test.go | 5 +- core/dao_test.go | 13 +- core/genesis_test.go | 3 +- core/state_processor_test.go | 7 +- core/txpool/locals/tx_tracker_test.go | 3 +- core/verkle_witness_test.go | 8 +- eth/api_backend_test.go | 3 +- eth/api_debug_test.go | 17 +- eth/backend.go | 32 ++-- eth/downloader/downloader_test.go | 3 +- eth/downloader/testchain_test.go | 3 +- eth/filters/filter_test.go | 12 +- eth/gasprice/gasprice_test.go | 3 +- eth/handler_eth_test.go | 5 +- eth/handler_test.go | 3 +- eth/protocols/eth/handler_test.go | 3 +- eth/protocols/snap/handler_fuzzing_test.go | 17 +- eth/tracers/api_test.go | 28 +-- eth/tracers/internal/tracetest/supply_test.go | 4 +- internal/ethapi/api_test.go | 17 +- miner/miner_test.go | 3 +- miner/payload_building_test.go | 3 +- tests/block_test_util.go | 22 ++- 36 files changed, 342 insertions(+), 307 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index eadc6e8b2d..2412964a3a 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2191,36 +2191,38 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if err != nil { Fatalf("%v", err) } - cache := &core.CacheConfig{ - TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, - TrieCleanNoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), - TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, - TrieDirtyDisabled: ctx.String(GCModeFlag.Name) == "archive", - TrieTimeLimit: ethconfig.Defaults.TrieTimeout, - SnapshotLimit: ethconfig.Defaults.SnapshotCache, - Preimages: ctx.Bool(CachePreimagesFlag.Name), - StateScheme: scheme, - StateHistory: ctx.Uint64(StateHistoryFlag.Name), + options := &core.BlockChainConfig{ + TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, + NoPrefetch: ctx.Bool(CacheNoPrefetchFlag.Name), + TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, + ArchiveMode: ctx.String(GCModeFlag.Name) == "archive", + TrieTimeLimit: ethconfig.Defaults.TrieTimeout, + SnapshotLimit: ethconfig.Defaults.SnapshotCache, + Preimages: ctx.Bool(CachePreimagesFlag.Name), + StateScheme: scheme, + StateHistory: ctx.Uint64(StateHistoryFlag.Name), + // Disable transaction indexing/unindexing. + TxLookupLimit: -1, } - if cache.TrieDirtyDisabled && !cache.Preimages { - cache.Preimages = true + if options.ArchiveMode && !options.Preimages { + options.Preimages = true log.Info("Enabling recording of key preimages since archive mode is used") } if !ctx.Bool(SnapshotFlag.Name) { - cache.SnapshotLimit = 0 // Disabled + options.SnapshotLimit = 0 // Disabled } else if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheSnapshotFlag.Name) { - cache.SnapshotLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheSnapshotFlag.Name) / 100 + options.SnapshotLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheSnapshotFlag.Name) / 100 } // If we're in readonly, do not bother generating snapshot data. if readonly { - cache.SnapshotNoBuild = true + options.SnapshotNoBuild = true } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { - cache.TrieCleanLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 + options.TrieCleanLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 } if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { - cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 + options.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } vmcfg := vm.Config{ EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), @@ -2235,8 +2237,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh vmcfg.Tracer = t } } - // Disable transaction indexing/unindexing by default. - chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil) + options.VmConfig = vmcfg + + chain, err := core.NewBlockChain(chainDb, gspec, engine, options) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index be51803f8c..994756eda5 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -31,7 +31,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/era" "github.com/ethereum/go-ethereum/params" @@ -78,7 +77,7 @@ func TestHistoryImportAndExport(t *testing.T) { }) // Initialize BlockChain. - chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, err := core.NewBlockChain(db, genesis, ethash.NewFaker(), nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) } @@ -167,7 +166,7 @@ func TestHistoryImportAndExport(t *testing.T) { }) genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults)) - imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) + imported, err := core.NewBlockChain(db2, genesis, ethash.NewFaker(), nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index bacd207493..afcab1d1f7 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -24,7 +24,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) @@ -55,7 +54,7 @@ func TestReimportMirroredState(t *testing.T) { copy(genspec.ExtraData[extraVanity:], addr[:]) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genspec, nil, engine, vm.Config{}, nil) + chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), genspec, engine, nil) defer chain.Stop() _, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) { @@ -87,7 +86,7 @@ func TestReimportMirroredState(t *testing.T) { } // Insert the first two blocks and make sure the chain is valid db = rawdb.NewMemoryDatabase() - chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil) + chain, _ = core.NewBlockChain(db, genspec, engine, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[:2]); err != nil { @@ -100,7 +99,7 @@ func TestReimportMirroredState(t *testing.T) { // Simulate a crash by creating a new chain on top of the database, without // flushing the dirty states out. Insert the last block, triggering a sidechain // reimport. - chain, _ = core.NewBlockChain(db, nil, genspec, nil, engine, vm.Config{}, nil) + chain, _ = core.NewBlockChain(db, genspec, engine, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[2:]); err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index a83d6ca736..ac2355c730 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -28,7 +28,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) @@ -458,7 +457,7 @@ func (tt *cliqueTest) run(t *testing.T) { batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, nil) if err != nil { t.Fatalf("failed to create test chain: %v", err) } diff --git a/core/bench_test.go b/core/bench_test.go index 155fa6c3b5..2830022662 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/pebble" @@ -200,7 +199,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + chainman, _ := NewBlockChain(db, gspec, ethash.NewFaker(), nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -325,9 +324,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { genesis := &Genesis{Config: params.AllEthashProtocolChanges} makeChainForBench(db, genesis, full, count) db.Close() - cacheConfig := *defaultCacheConfig - cacheConfig.TrieDirtyDisabled = true - + options := DefaultConfig().WithArchive(true) b.ReportAllocs() b.ResetTimer() @@ -338,7 +335,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { } db = rawdb.NewDatabase(pdb) - chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, err := NewBlockChain(db, genesis, ethash.NewFaker(), options) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 5217979236..fcc99effd0 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" ) @@ -50,7 +49,8 @@ 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, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), options) defer chain.Stop() if err != nil { t.Fatal(err) @@ -166,7 +166,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { postHeaders[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) defer chain.Stop() if err != nil { t.Fatal(err) diff --git a/core/blockchain.go b/core/blockchain.go index 2794513025..25b37b5cce 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -149,72 +149,95 @@ const ( BlockChainVersion uint64 = 9 ) -// CacheConfig contains the configuration values for the trie database -// and state snapshot these are 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 - TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk - TrieDirtyDisabled bool // Whether to disable trie write caching and GC altogether (archive node) - 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 +// BlockChainConfig contains the configuration of the BlockChain object. +type BlockChainConfig struct { + // Trie database related options + TrieCleanLimit int // Memory allowance (MB) to use for caching trie nodes in memory + TrieDirtyLimit int // Memory limit (MB) at which to start flushing dirty trie nodes to disk + TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk + 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 + ArchiveMode bool // Whether to enable the archive mode + + // State snapshot related options + SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory 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 // This defines the cutoff block for history expiry. // Blocks before this number may be unavailable in the chain database. ChainHistoryMode history.HistoryMode + + // Misc options + NoPrefetch bool // Whether to disable heuristic state prefetching when processing blocks + Overrides *ChainOverrides // Optional chain config overrides + VmConfig vm.Config // Config options for the EVM Interpreter + + // TxLookupLimit specifies the maximum number of blocks from head for which + // transaction hashes will be indexed. + // + // If the value is zero, all transactions of the entire chain will be indexed. + // If the value is -1, indexing is disabled. + TxLookupLimit int64 +} + +// DefaultConfig returns the default config. +// Note the returned object is safe to modify! +func DefaultConfig() *BlockChainConfig { + return &BlockChainConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + StateScheme: rawdb.HashScheme, + SnapshotLimit: 256, + SnapshotWait: true, + ChainHistoryMode: history.KeepAll, + // Transaction indexing is disabled by default. + // This is appropriate for most unit tests. + TxLookupLimit: -1, + } +} + +// WithArchive enabled/disables archive mode on the config. +func (cfg BlockChainConfig) WithArchive(on bool) *BlockChainConfig { + cfg.ArchiveMode = on + return &cfg +} + +// WithStateScheme sets the state storage scheme on the config. +func (cfg BlockChainConfig) WithStateScheme(scheme string) *BlockChainConfig { + cfg.StateScheme = scheme + return &cfg } // triedbConfig derives the configures for trie database. -func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config { +func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config { config := &triedb.Config{ - Preimages: c.Preimages, + Preimages: cfg.Preimages, IsVerkle: isVerkle, } - if c.StateScheme == rawdb.HashScheme { + if cfg.StateScheme == rawdb.HashScheme { config.HashDB = &hashdb.Config{ - CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, + CleanCacheSize: cfg.TrieCleanLimit * 1024 * 1024, } } - if c.StateScheme == rawdb.PathScheme { + if cfg.StateScheme == rawdb.PathScheme { config.PathDB = &pathdb.Config{ - StateHistory: c.StateHistory, - TrieCleanSize: c.TrieCleanLimit * 1024 * 1024, - StateCleanSize: c.SnapshotLimit * 1024 * 1024, + StateHistory: cfg.StateHistory, + TrieCleanSize: cfg.TrieCleanLimit * 1024 * 1024, + StateCleanSize: cfg.SnapshotLimit * 1024 * 1024, // TODO(rjl493456442): The write buffer represents the memory limit used // for flushing both trie data and state data to disk. The config name // should be updated to eliminate the confusion. - WriteBufferSize: c.TrieDirtyLimit * 1024 * 1024, + WriteBufferSize: cfg.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{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - 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 -} - // txLookup is wrapper over transaction lookup along with the corresponding // transaction object. type txLookup struct { @@ -238,7 +261,7 @@ type txLookup struct { // canonical chain. type BlockChain struct { chainConfig *params.ChainConfig // Chain & network configuration - cacheConfig *CacheConfig // Cache configuration for pruning + cfg *BlockChainConfig // Blockchain configuration db ethdb.Database // Low level persistent database to store final content in snaps *snapshot.Tree // Snapshot tree for fast trie leaf access @@ -285,7 +308,6 @@ type BlockChain struct { validator Validator // Block and state validator interface prefetcher Prefetcher processor Processor // Block transaction processor interface - vmConfig vm.Config logger *tracing.Hooks lastForkReadyAlert time.Time // Last time there was a fork readiness print out @@ -294,22 +316,23 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator // and Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, overrides *ChainOverrides, engine consensus.Engine, vmConfig vm.Config, txLookupLimit *uint64) (*BlockChain, error) { - if cacheConfig == nil { - cacheConfig = defaultCacheConfig +func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, cfg *BlockChainConfig) (*BlockChain, error) { + if cfg == nil { + cfg = DefaultConfig() } + // Open trie database with provided config enableVerkle, err := EnableVerkleAtGenesis(db, genesis) if err != nil { return nil, err } - triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle)) + triedb := triedb.NewDatabase(db, cfg.triedbConfig(enableVerkle)) // Write the supplied genesis to the database if it has not been initialized // yet. The corresponding chain config will be returned, either from the // provided genesis or from the locally stored configuration if the genesis // has already been initialized. - chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) + chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, cfg.Overrides) if err != nil { return nil, err } @@ -323,7 +346,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis bc := &BlockChain{ chainConfig: chainConfig, - cacheConfig: cacheConfig, + cfg: cfg, db: db, triedb: triedb, triegc: prque.New[int64, common.Hash](nil), @@ -334,14 +357,13 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit), txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit), engine: engine, - vmConfig: vmConfig, - logger: vmConfig.Tracer, + logger: cfg.VmConfig.Tracer, } bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err } - bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) + bc.flushInterval.Store(int64(cfg.TrieTimeLimit)) bc.statedb = state.NewDatabase(bc.triedb, nil) bc.validator = NewBlockValidator(chainConfig, bc) bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) @@ -390,7 +412,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // Note it's unnecessary in path mode which always keep trie data and // state data consistent. var diskRoot common.Hash - if bc.cacheConfig.SnapshotLimit > 0 && bc.cacheConfig.StateScheme == rawdb.HashScheme { + if bc.cfg.SnapshotLimit > 0 && bc.cfg.StateScheme == rawdb.HashScheme { diskRoot = rawdb.ReadSnapshotRoot(bc.db) } if diskRoot != (common.Hash{}) { @@ -477,8 +499,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Start tx indexer if it's enabled. - if txLookupLimit != nil { - bc.txIndexer = newTxIndexer(*txLookupLimit, bc) + if bc.cfg.TxLookupLimit >= 0 { + bc.txIndexer = newTxIndexer(uint64(bc.cfg.TxLookupLimit), bc) } return bc, nil } @@ -486,11 +508,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis func (bc *BlockChain) setupSnapshot() { // Short circuit if the chain is established with path scheme, as the // state snapshot has been integrated into path database natively. - if bc.cacheConfig.StateScheme == rawdb.PathScheme { + if bc.cfg.StateScheme == rawdb.PathScheme { return } // Load any existing snapshot, regenerating it if loading failed - if bc.cacheConfig.SnapshotLimit > 0 { + if bc.cfg.SnapshotLimit > 0 { // If the chain was rewound past the snapshot persistent layer (causing // a recovery block number to be persisted to disk), check if we're still // in recovery mode and in that case, don't invalidate the snapshot on a @@ -502,10 +524,10 @@ func (bc *BlockChain) setupSnapshot() { recover = true } snapconfig := snapshot.Config{ - CacheSize: bc.cacheConfig.SnapshotLimit, + CacheSize: bc.cfg.SnapshotLimit, Recovery: recover, - NoBuild: bc.cacheConfig.SnapshotNoBuild, - AsyncBuild: !bc.cacheConfig.SnapshotWait, + NoBuild: bc.cfg.SnapshotNoBuild, + AsyncBuild: !bc.cfg.SnapshotWait, } bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) @@ -629,7 +651,7 @@ func (bc *BlockChain) loadLastState() error { func (bc *BlockChain) initializeHistoryPruning(latest uint64) error { freezerTail, _ := bc.db.Tail() - switch bc.cacheConfig.ChainHistoryMode { + switch bc.cfg.ChainHistoryMode { case history.KeepAll: if freezerTail == 0 { return nil @@ -650,7 +672,7 @@ func (bc *BlockChain) initializeHistoryPruning(latest uint64) error { // postmerge directly on an existing DB. We could just trigger the pruning // here, but it'd be a bit dangerous since they may not have intended this // action to happen. So just tell them how to do it. - log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cacheConfig.ChainHistoryMode.String())) + log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cfg.ChainHistoryMode.String())) log.Error(fmt.Sprintf("Run 'geth prune-history' to prune pre-merge history.")) return fmt.Errorf("history pruning requested via configuration") } @@ -666,7 +688,7 @@ func (bc *BlockChain) initializeHistoryPruning(latest uint64) error { return nil default: - return fmt.Errorf("invalid history mode: %d", bc.cacheConfig.ChainHistoryMode) + return fmt.Errorf("invalid history mode: %d", bc.cfg.ChainHistoryMode) } } @@ -1240,7 +1262,7 @@ func (bc *BlockChain) Stop() { // - 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 { + if !bc.cfg.ArchiveMode { triedb := bc.triedb for _, offset := range []uint64{0, 1, state.TriesInMemory - 1} { @@ -1546,7 +1568,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. return nil } // If we're running an archive node, always flush - if bc.cacheConfig.TrieDirtyDisabled { + if bc.cfg.ArchiveMode { return bc.triedb.Commit(root, false) } // Full but not archive node, do proper garbage collection @@ -1561,7 +1583,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( _, nodes, imgs = bc.triedb.Size() // all memory is contained within the nodes return for hashdb - limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 + limit = common.StorageSize(bc.cfg.TrieDirtyLimit) * 1024 * 1024 ) if nodes > limit || imgs > 4*1024*1024 { bc.triedb.Cap(limit - ethdb.IdealBatchSize) @@ -1911,7 +1933,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s ) defer interrupt.Store(true) // terminate the prefetch at the end - if bc.cacheConfig.TrieCleanNoPrefetch { + if bc.cfg.NoPrefetch { statedb, err = state.New(parentRoot, bc.statedb) if err != nil { return nil, err @@ -1936,7 +1958,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s } go func(start time.Time, throwaway *state.StateDB, block *types.Block) { // Disable tracing for prefetcher executions. - vmCfg := bc.vmConfig + vmCfg := bc.cfg.VmConfig vmCfg.Tracer = nil bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt) @@ -1955,7 +1977,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s // Generate witnesses either if we're self-testing, or if it's the // only block being inserted. A bit crude, but witnesses are huge, // so we refuse to make an entire chain of them. - if bc.vmConfig.StatelessSelfValidation || makeWitness { + if bc.cfg.VmConfig.StatelessSelfValidation || makeWitness { witness, err = stateless.NewWitness(block.Header(), bc) if err != nil { return nil, err @@ -1980,7 +2002,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s // Process block using the parent state as reference point pstart := time.Now() - res, err := bc.processor.Process(block, statedb, bc.vmConfig) + res, err := bc.processor.Process(block, statedb, bc.cfg.VmConfig) if err != nil { bc.reportBlock(block, res, err) return nil, err @@ -2000,7 +2022,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s // witness builder/runner, which would otherwise be impossible due to the // various invalid chain states/behaviors being contained in those tests. xvstart := time.Now() - if witness := statedb.Witness(); witness != nil && bc.vmConfig.StatelessSelfValidation { + if witness := statedb.Witness(); witness != nil && bc.cfg.VmConfig.StatelessSelfValidation { log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash()) // Remove critical computed fields from the block to force true recalculation @@ -2011,7 +2033,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s task := types.NewBlockWithHeader(context).WithBody(*block.Body()) // Run the stateless self-cross-validation - crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, bc.vmConfig, task, witness) + crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, bc.cfg.VmConfig, task, witness) if err != nil { return nil, fmt.Errorf("stateless self-validation failed: %v", err) } diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index c54948122d..6a0cfd6704 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -408,7 +408,7 @@ func (bc *BlockChain) Genesis() *types.Block { // GetVMConfig returns the block chain VM config. func (bc *BlockChain) GetVMConfig() *vm.Config { - return &bc.vmConfig + return &bc.cfg.VmConfig } // TxIndexProgress returns the transaction indexing progress. diff --git a/core/blockchain_repair_test.go b/core/blockchain_repair_test.go index 9661cee4c7..55794c6596 100644 --- a/core/blockchain_repair_test.go +++ b/core/blockchain_repair_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb/pebble" "github.com/ethereum/go-ethereum/params" ) @@ -1782,20 +1781,21 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s Config: params.AllEthashProtocolChanges, } engine = ethash.NewFullFaker() - config = &CacheConfig{ + option = &BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, // Disable snapshot by default + SnapshotLimit: 0, // disable snapshot by default + TxLookupLimit: -1, // disable tx indexing StateScheme: scheme, } ) defer engine.Close() if snapshots && scheme == rawdb.HashScheme { - config.SnapshotLimit = 256 - config.SnapshotWait = true + option.SnapshotLimit = 256 + option.SnapshotWait = true } - chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, gspec, engine, option) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1860,7 +1860,7 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s } defer db.Close() - newChain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) + newChain, err := NewBlockChain(db, gspec, engine, option) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -1931,9 +1931,10 @@ func testIssue23496(t *testing.T, scheme string) { Config: params.TestChainConfig, BaseFee: big.NewInt(params.InitialBaseFee), } - engine = ethash.NewFullFaker() + engine = ethash.NewFullFaker() + options = DefaultConfig().WithStateScheme(scheme) ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, gspec, engine, options) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -1985,7 +1986,7 @@ func testIssue23496(t *testing.T, scheme string) { } defer db.Close() - chain, err = NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) + chain, err = NewBlockChain(db, gspec, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index b094ed3b65..72ca15d7f6 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -32,7 +32,6 @@ import ( "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/ethdb/pebble" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -1985,20 +1984,21 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } - engine = ethash.NewFullFaker() - config = &CacheConfig{ + engine = ethash.NewFullFaker() + options = &BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, // Disable snapshot + SnapshotLimit: 0, // disable snapshot + TxLookupLimit: -1, // disable tx indexing StateScheme: scheme, } ) if snapshots { - config.SnapshotLimit = 256 - config.SnapshotWait = true + options.SnapshotLimit = 256 + options.SnapshotWait = true } - chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, gspec, engine, options) if err != nil { t.Fatalf("Failed to create chain: %v", err) } diff --git a/core/blockchain_snapshot_test.go b/core/blockchain_snapshot_test.go index e12a0c67c4..5550907b0d 100644 --- a/core/blockchain_snapshot_test.go +++ b/core/blockchain_snapshot_test.go @@ -33,7 +33,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb/pebble" "github.com/ethereum/go-ethereum/params" @@ -82,7 +81,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo } engine = ethash.NewFullFaker() ) - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(basic.scheme), gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, gspec, engine, DefaultConfig().WithStateScheme(basic.scheme)) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -233,7 +232,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) + newchain, err := NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, DefaultConfig().WithStateScheme(snaptest.scheme)) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -275,13 +274,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) + newchain, err := NewBlockChain(newdb, snaptest.gspec, snaptest.engine, DefaultConfig().WithStateScheme(snaptest.scheme)) 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) + newchain, err = NewBlockChain(newdb, snaptest.gspec, snaptest.engine, DefaultConfig().WithStateScheme(snaptest.scheme)) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -311,14 +310,15 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { gappedBlocks, _ := GenerateChain(snaptest.gspec.Config, 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{ + var options = &BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, StateScheme: snaptest.scheme, + TxLookupLimit: -1, } - newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) + newchain, err := NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, options) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -326,7 +326,8 @@ 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) + options = DefaultConfig().WithStateScheme(snaptest.scheme) + newchain, err = NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, options) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -354,7 +355,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) + newchain, err := NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, DefaultConfig().WithStateScheme(snaptest.scheme)) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -383,14 +384,15 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { // and state committed. chain.Stop() - config := &CacheConfig{ + config := &BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, StateScheme: snaptest.scheme, + TxLookupLimit: -1, } - newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) + newchain, err := NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, config) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -399,15 +401,16 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain, the wiper should start working - config = &CacheConfig{ + config = &BlockChainConfig{ TrieCleanLimit: 256, TrieDirtyLimit: 256, TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild StateScheme: snaptest.scheme, + TxLookupLimit: -1, } - tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) + tmp, err := NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, config) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -416,7 +419,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { tmp.triedb.Close() tmp.stopWithoutSaving() - newchain, err = NewBlockChain(snaptest.db, DefaultCacheConfigWithScheme(snaptest.scheme), snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil) + newchain, err = NewBlockChain(snaptest.db, snaptest.gspec, snaptest.engine, DefaultConfig().WithStateScheme(snaptest.scheme)) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 2401402f32..f47e922e18 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -66,7 +66,8 @@ 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) + options := DefaultConfig().WithStateScheme(scheme) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, options) // Create and inject the requested chain if n == 0 { @@ -723,7 +724,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) + archive, _ := NewBlockChain(archiveDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -731,7 +732,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) + fast, _ := NewBlockChain(fastDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer fast.Stop() if n, err := fast.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), 0); err != nil { @@ -744,7 +745,7 @@ func testFastVsFullChains(t *testing.T, scheme string) { } defer ancientDb.Close() - ancient, _ := NewBlockChain(ancientDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + ancient, _ := NewBlockChain(ancientDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer ancient.Stop() if n, err := ancient.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), uint64(len(blocks)/2)); err != nil { @@ -851,11 +852,8 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { archiveDb := makeDb() defer archiveDb.Close() - archiveCaching := *defaultCacheConfig - archiveCaching.TrieDirtyDisabled = true - archiveCaching.StateScheme = scheme - - archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + options := DefaultConfig().WithArchive(true).WithStateScheme(scheme) + archive, _ := NewBlockChain(archiveDb, gspec, ethash.NewFaker(), options) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -868,7 +866,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) + fast, _ := NewBlockChain(fastDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer fast.Stop() if n, err := fast.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), 0); err != nil { @@ -881,7 +879,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) + ancient, _ := NewBlockChain(ancientDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer ancient.Stop() if n, err := ancient.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), uint64(3*len(blocks)/4)); err != nil { @@ -902,7 +900,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) { for i, block := range blocks { headers[i] = block.Header() } - light, _ := NewBlockChain(lightDb, DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + light, _ := NewBlockChain(lightDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) if n, err := light.InsertHeaderChain(headers); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -975,7 +973,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) + blockchain, _ := NewBlockChain(db, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1049,7 +1047,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) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1105,7 +1103,7 @@ func testLogRebirth(t *testing.T, scheme string) { gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.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) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, DefaultConfig().WithStateScheme(scheme)) ) defer blockchain.Stop() @@ -1186,7 +1184,7 @@ func testSideLogRebirth(t *testing.T, scheme string) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + blockchain, _ = NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) ) defer blockchain.Stop() @@ -1385,7 +1383,7 @@ func testEIP155Transition(t *testing.T, scheme string) { } }) - blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer blockchain.Stop() if _, err := blockchain.InsertChain(blocks); err != nil { @@ -1478,7 +1476,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) + blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer blockchain.Stop() if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { @@ -1536,7 +1534,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) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1580,7 +1578,7 @@ func TestTrieForkGC(t *testing.T) { forks[i] = fork[0] } // Import the canonical and fork chain side by side, forcing the trie cache to cache both - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, genesis, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1626,7 +1624,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) { db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{}) defer db.Close() - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1694,7 +1692,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) + ancient, _ := NewBlockChain(ancientDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) if n, err := ancient.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), uint64(3*len(blocks)/4)); err != nil { t.Fatalf("failed to insert receipt %d: %v", n, err) @@ -1707,7 +1705,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) + ancient, _ = NewBlockChain(ancientDb, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(scheme)) defer ancient.Stop() if num := ancient.CurrentBlock().Number.Uint64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1750,7 +1748,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) { diskdb, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{}) defer diskdb.Close() - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(diskdb, genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1811,7 +1809,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon mergeBlock = gomath.MaxInt32 ) // Generate and import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1965,7 +1963,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) + chain, err := NewBlockChain(chaindb, genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2128,7 +2126,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i } defer chaindb.Close() - chain, err := NewBlockChain(chaindb, nil, genesis, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(chaindb, genesis, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2234,7 +2232,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) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { return nil, nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2410,7 +2408,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in b.ResetTimer() for i := 0; i < b.N; i++ { // Import the shared chain and the original canonical one - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2502,7 +2500,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) { } defer db.Close() - chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(db, genesis, engine, DefaultConfig().WithStateScheme(scheme)) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2601,7 +2599,8 @@ 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) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2714,9 +2713,11 @@ 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{ + options := DefaultConfig().WithStateScheme(scheme) + options.VmConfig = vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil) + } + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2796,9 +2797,11 @@ 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{ + options := DefaultConfig().WithStateScheme(scheme) + options.VmConfig = vm.Config{ Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil) + } + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2971,10 +2974,12 @@ 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{ + options := DefaultConfig().WithStateScheme(scheme) + options.VmConfig = vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil) + } + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3109,10 +3114,12 @@ func testInitThenFailCreateContract(t *testing.T, scheme string) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{ + options := DefaultConfig().WithStateScheme(scheme) + options.VmConfig = vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil) + } + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3199,7 +3206,8 @@ func testEIP2718Transition(t *testing.T, scheme string) { }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3293,7 +3301,8 @@ func testEIP1559Transition(t *testing.T, scheme string) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3406,7 +3415,8 @@ func testSetCanonical(t *testing.T, scheme string) { diskdb, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{}) defer diskdb.Close() - chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(diskdb, gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3515,7 +3525,8 @@ 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) + options := DefaultConfig().WithStateScheme(scheme) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3649,10 +3660,7 @@ func testCreateThenDelete(t *testing.T, config *params.ChainConfig) { nonce++ }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ - //Debug: true, - //Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3764,7 +3772,7 @@ func TestDeleteThenCreate(t *testing.T) { } }) // Import the canonical chain - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3849,7 +3857,9 @@ func TestTransientStorageReset(t *testing.T) { }) // Initialize the blockchain with 1153 enabled. - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vmConfig, nil) + options := DefaultConfig() + options.VmConfig = vmConfig + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3943,7 +3953,11 @@ func TestEIP3651(t *testing.T) { b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil) + options := DefaultConfig() + options.VmConfig = vm.Config{ + Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks(), + } + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4052,7 +4066,7 @@ func TestPragueRequests(t *testing.T) { } // Insert block to check validation. - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4124,7 +4138,7 @@ func TestEIP7702(t *testing.T) { tx := types.MustSignNewTx(key1, signer, txdata) b.AddTx(tx) }) - chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil) + chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -4202,7 +4216,8 @@ func testChainReorgSnapSync(t *testing.T, ancientLimit uint64) { db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{}) defer db.Close() - chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(rawdb.PathScheme) + chain, _ := NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), options) defer chain.Stop() if n, err := chain.InsertReceiptChain(blocks, types.EncodeBlockReceiptLists(receipts), ancientLimit); err != nil { @@ -4312,12 +4327,14 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64, }() // Enable pruning in cache config. - config := DefaultCacheConfigWithScheme(rawdb.PathScheme) + config := DefaultConfig().WithStateScheme(rawdb.PathScheme) config.ChainHistoryMode = history.KeepPostMerge db, _ := rawdb.Open(rawdb.NewMemoryDatabase(), rawdb.OpenOptions{}) defer db.Close() - chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) + + options := DefaultConfig().WithStateScheme(rawdb.PathScheme) + chain, _ := NewBlockChain(db, genesis, beacon.New(ethash.NewFaker()), options) defer chain.Stop() var ( diff --git a/core/chain_makers.go b/core/chain_makers.go index 37bddcfda5..fe2e25d2d7 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -579,7 +579,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (common.Hash, ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) { db := rawdb.NewMemoryDatabase() - cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig := DefaultConfig().WithStateScheme(rawdb.PathScheme) cacheConfig.SnapshotLimit = 0 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) defer triedb.Close() diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index d81a52e915..cc9672199e 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -119,7 +118,7 @@ func TestGeneratePOSChain(t *testing.T) { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil) + blockchain, _ := NewBlockChain(db, gspec, engine, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(genchain); err != nil { @@ -234,7 +233,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) + blockchain, _ := NewBlockChain(db, gspec, ethash.NewFaker(), DefaultConfig().WithStateScheme(rawdb.HashScheme)) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index 5da9e91b03..2d4a20e6b9 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" ) @@ -50,7 +49,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &proConf, } - proBc, _ := NewBlockChain(proDb, nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) + proBc, _ := NewBlockChain(proDb, progspec, ethash.NewFaker(), nil) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() @@ -62,7 +61,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { BaseFee: big.NewInt(params.InitialBaseFee), Config: &conConf, } - conBc, _ := NewBlockChain(conDb, nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) + conBc, _ := NewBlockChain(conDb, congspec, ethash.NewFaker(), nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -74,7 +73,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain - bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), congspec, ethash.NewFaker(), nil) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -97,7 +96,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain - bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), progspec, ethash.NewFaker(), nil) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -121,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil) + bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), congspec, ethash.NewFaker(), nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) @@ -139,7 +138,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes - bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil) + bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), progspec, ethash.NewFaker(), nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) diff --git a/core/genesis_test.go b/core/genesis_test.go index 726bda86bb..9dc4bfb3df 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -131,7 +130,7 @@ func testSetupGenesis(t *testing.T, scheme string) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) oldcustomg.Commit(db, tdb) - bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil) + bc, _ := NewBlockChain(db, &oldcustomg, ethash.NewFullFaker(), DefaultConfig().WithStateScheme(scheme)) defer bc.Stop() _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index ffdf063812..d175b5eac5 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -125,7 +124,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) + blockchain, _ = NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), nil) tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} ) @@ -293,7 +292,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + blockchain, _ = NewBlockChain(db, gspec, ethash.NewFaker(), nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -332,7 +331,7 @@ func TestStateProcessorErrors(t *testing.T) { }, }, } - blockchain, _ = NewBlockChain(db, nil, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) + blockchain, _ = NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), nil) ) defer blockchain.Stop() for i, tt := range []struct { diff --git a/core/txpool/locals/tx_tracker_test.go b/core/txpool/locals/tx_tracker_test.go index 0668d243fc..367fb6b6da 100644 --- a/core/txpool/locals/tx_tracker_test.go +++ b/core/txpool/locals/tx_tracker_test.go @@ -28,7 +28,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" @@ -65,7 +64,7 @@ func newTestEnv(t *testing.T, n int, gasTip uint64, journal string) *testEnv { }) db := rawdb.NewMemoryDatabase() - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, _ := core.NewBlockChain(db, gspec, ethash.NewFaker(), nil) legacyPool := legacypool.New(legacypool.DefaultConfig, chain) pool, err := txpool.New(gasTip, chain, []txpool.SubPool{legacyPool}) diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index de2280ced1..a89672e6e5 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -119,9 +119,9 @@ func TestProcessVerkle(t *testing.T) { // Verkle trees use the snapshot, which must be enabled before the // data is saved into the tree+database. // genesis := gspec.MustCommit(bcdb, triedb) - cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) - cacheConfig.SnapshotLimit = 0 - blockchain, _ := NewBlockChain(bcdb, cacheConfig, gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil) + options := DefaultConfig().WithStateScheme(rawdb.PathScheme) + options.SnapshotLimit = 0 + blockchain, _ := NewBlockChain(bcdb, gspec, beacon.New(ethash.NewFaker()), options) defer blockchain.Stop() txCost1 := params.TxGas @@ -255,7 +255,7 @@ func TestProcessParentBlockHash(t *testing.T) { }) t.Run("Verkle", func(t *testing.T) { db := rawdb.NewMemoryDatabase() - cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig := DefaultConfig().WithStateScheme(rawdb.PathScheme) cacheConfig.SnapshotLimit = 0 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil)) diff --git a/eth/api_backend_test.go b/eth/api_backend_test.go index dfca24aba7..d0718ede1c 100644 --- a/eth/api_backend_test.go +++ b/eth/api_backend_test.go @@ -34,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/txpool/locals" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -61,7 +60,7 @@ func initBackend(withLocal bool) *EthAPIBackend { db = rawdb.NewMemoryDatabase() engine = beacon.New(ethash.NewFaker()) ) - chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil) + chain, _ := core.NewBlockChain(db, gspec, engine, nil) txconfig := legacypool.DefaultConfig txconfig.Journal = "" // Don't litter the disk with test journals diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 90fd22498a..034026b366 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -68,15 +67,15 @@ func newTestBlockChain(t *testing.T, n int, gspec *core.Genesis, generator func( _, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) // Import the canonical chain - cacheConfig := &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, - Preimages: true, - TrieDirtyDisabled: true, // Archive mode + options := &core.BlockChainConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + Preimages: true, + ArchiveMode: true, // Archive mode } - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConfig, gspec, nil, engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/eth/backend.go b/eth/backend.go index dd0e38596e..5561657ea8 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -21,6 +21,7 @@ import ( "context" "encoding/json" "fmt" + "math" "math/big" "runtime" "sync" @@ -223,19 +224,22 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, } - cacheConfig = &core.CacheConfig{ - TrieCleanLimit: config.TrieCleanCache, - TrieCleanNoPrefetch: config.NoPrefetch, - TrieDirtyLimit: config.TrieDirtyCache, - TrieDirtyDisabled: config.NoPruning, - TrieTimeLimit: config.TrieTimeout, - SnapshotLimit: config.SnapshotCache, - Preimages: config.Preimages, - StateHistory: config.StateHistory, - StateScheme: scheme, - ChainHistoryMode: config.HistoryMode, + options = &core.BlockChainConfig{ + TrieCleanLimit: config.TrieCleanCache, + NoPrefetch: config.NoPrefetch, + TrieDirtyLimit: config.TrieDirtyCache, + ArchiveMode: config.NoPruning, + TrieTimeLimit: config.TrieTimeout, + SnapshotLimit: config.SnapshotCache, + Preimages: config.Preimages, + StateHistory: config.StateHistory, + StateScheme: scheme, + ChainHistoryMode: config.HistoryMode, + TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)), + VmConfig: vmConfig, } ) + if config.VMTrace != "" { traceConfig := json.RawMessage("{}") if config.VMTraceJsonConfig != "" { @@ -255,7 +259,9 @@ 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, &config.TransactionHistory) + options.Overrides = &overrides + + eth.blockchain, err = core.NewBlockChain(chainDb, config.Genesis, eth.engine, options) if err != nil { return nil, err } @@ -303,7 +309,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } // Permit the downloader to use the trie cache allowance during fast sync - cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit + cacheLimit := options.TrieCleanLimit + options.TrieDirtyLimit + options.SnapshotLimit if eth.handler, err = newHandler(&handlerConfig{ NodeID: eth.p2pServer.Self().ID(), Database: chainDb, diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index aeb286b553..669ce003cf 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -30,7 +30,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" "github.com/ethereum/go-ethereum/event" @@ -68,7 +67,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { Alloc: types.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, BaseFee: big.NewInt(params.InitialBaseFee), } - chain, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, err := core.NewBlockChain(db, gspec, ethash.NewFaker(), nil) if err != nil { panic(err) } diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 8fa2e83413..ecd7386f42 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -27,7 +27,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" @@ -217,7 +216,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { if pregenerated { panic("Requested chain generation outside of init") } - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), testGspec, ethash.NewFaker(), nil) if err != nil { panic(err) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 996cbbdcad..bc755f9fa8 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/filtermaps" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -277,8 +276,9 @@ func testFilters(t *testing.T, history uint64, noHistory bool) { gen.AddTx(tx) } }) - var l uint64 - bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l) + options := core.DefaultConfig().WithStateScheme(rawdb.HashScheme) + options.TxLookupLimit = 0 // index all txs + bc, err := core.NewBlockChain(db, gspec, ethash.NewFaker(), options) if err != nil { t.Fatal(err) } @@ -434,8 +434,10 @@ func TestRangeLogs(t *testing.T) { t.Fatal(err) } chain, _ := core.GenerateChain(gspec.Config, gspec.ToBlock(), ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) {}) - var l uint64 - bc, err := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, &l) + + options := core.DefaultConfig().WithStateScheme(rawdb.HashScheme) + options.TxLookupLimit = 0 // index all txs + bc, err := core.NewBlockChain(db, gspec, ethash.NewFaker(), options) if err != nil { t.Fatal(err) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 8e6524446f..02a25bc4d8 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core" "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/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/event" @@ -212,7 +211,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, cancunBlock *big.Int, pe }) // Construct testing chain - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec, nil, engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(db, gspec, engine, &core.BlockChainConfig{NoPrefetch: true}) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 2446c5fccb..058a0d5949 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -27,7 +27,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/event" @@ -97,8 +96,8 @@ func testForkIDSplit(t *testing.T, protocol uint) { gspecNoFork = &core.Genesis{Config: configNoFork} gspecProFork = &core.Genesis{Config: configProFork} - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil) - chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil) + chainNoFork, _ = core.NewBlockChain(dbNoFork, gspecNoFork, engine, nil) + chainProFork, _ = core.NewBlockChain(dbProFork, gspecProFork, engine, nil) _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) diff --git a/eth/handler_test.go b/eth/handler_test.go index fb3103f241..d0da098430 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -27,7 +27,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" @@ -182,7 +181,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler { Config: params.TestChainConfig, Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, } - chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + chain, _ := core.NewBlockChain(db, gspec, ethash.NewFaker(), nil) _, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 2fa10dfa9d..a3419d96ff 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/ethdb" @@ -120,7 +119,7 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generat Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, Difficulty: common.Big0, } - chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil) + chain, _ := core.NewBlockChain(db, gspec, engine, nil) _, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/snap/handler_fuzzing_test.go b/eth/protocols/snap/handler_fuzzing_test.go index 777db6387c..4930ae9ae6 100644 --- a/eth/protocols/snap/handler_fuzzing_test.go +++ b/eth/protocols/snap/handler_fuzzing_test.go @@ -29,7 +29,6 @@ import ( "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/core/vm" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" @@ -117,16 +116,16 @@ func getChain() *core.BlockChain { Alloc: ga, } _, blocks, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), 2, func(i int, gen *core.BlockGen) {}) - cacheConf := &core.CacheConfig{ - TrieCleanLimit: 0, - TrieDirtyLimit: 0, - TrieTimeLimit: 5 * time.Minute, - TrieCleanNoPrefetch: true, - SnapshotLimit: 100, - SnapshotWait: true, + options := &core.BlockChainConfig{ + TrieCleanLimit: 0, + TrieDirtyLimit: 0, + TrieTimeLimit: 5 * time.Minute, + NoPrefetch: true, + SnapshotLimit: 100, + SnapshotWait: true, } trieRoot = blocks[len(blocks)-1].Root() - bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), cacheConf, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + bc, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), options) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index d20d5eaff6..1826c78582 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -77,14 +77,14 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) // Import the canonical chain - cacheConfig := &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, - TrieDirtyDisabled: true, // Archive mode + options := &core.BlockChainConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + ArchiveMode: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(backend.chaindb, gspec, backend.engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1144,14 +1144,14 @@ func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator fu _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) // Import the canonical chain - cacheConfig := &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, - TrieDirtyDisabled: true, // Archive mode + options := &core.BlockChainConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + ArchiveMode: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(backend.chaindb, gspec, backend.engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 57ba628b78..8aedc9d564 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -554,7 +554,9 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG return nil, nil, fmt.Errorf("failed to create call tracer: %v", err) } - chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil) + options := core.DefaultConfig().WithStateScheme(rawdb.PathScheme) + options.VmConfig = vm.Config{Tracer: tracer} + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), genesis, engine, options) if err != nil { return nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 0a157dce79..4d1834d757 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -442,21 +442,16 @@ type testBackend struct { } func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend { - var ( - cacheConfig = &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, - TrieDirtyDisabled: true, // Archive mode - } - ) + options := core.DefaultConfig().WithArchive(true) + options.TxLookupLimit = 0 // index all txs + accman, acc := newTestAccountManager(t) gspec.Alloc[acc.Address] = types.Account{Balance: big.NewInt(params.Ether)} + // Generate blocks for testing db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator) - txlookupLimit := uint64(0) - chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, &txlookupLimit) + + chain, err := core.NewBlockChain(db, gspec, engine, options) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 04d84e2e1d..575ee4d0fd 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -30,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -152,7 +151,7 @@ func createMiner(t *testing.T) *Miner { // Create consensus engine engine := clique.New(chainConfig.Clique, chainDB) // Create Ethereum backend - bc, err := core.NewBlockChain(chainDB, nil, genesis, nil, engine, vm.Config{}, nil) + bc, err := core.NewBlockChain(chainDB, genesis, engine, nil) if err != nil { t.Fatalf("can't create new chain %v", err) } diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index e0791921d6..295962d7ef 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" @@ -118,7 +117,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine default: t.Fatalf("unexpected consensus engine type: %T", engine) } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil) + chain, err := core.NewBlockChain(db, gspec, engine, &core.BlockChainConfig{ArchiveMode: true}) if err != nil { t.Fatalf("core.NewBlockChain failed: %v", err) } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index f029fa7f41..a76037405b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -151,15 +151,21 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t // Wrap the original engine within the beacon-engine engine := beacon.New(ethash.NewFaker()) - cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme, Preimages: true} - if snapshotter { - cache.SnapshotLimit = 1 - cache.SnapshotWait = true + options := &core.BlockChainConfig{ + TrieCleanLimit: 0, + StateScheme: scheme, + Preimages: true, + TxLookupLimit: -1, // disable tx indexing + VmConfig: vm.Config{ + Tracer: tracer, + StatelessSelfValidation: witness, + }, } - chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ - Tracer: tracer, - StatelessSelfValidation: witness, - }, nil) + if snapshotter { + options.SnapshotLimit = 1 + options.SnapshotWait = true + } + chain, err := core.NewBlockChain(db, gspec, engine, options) if err != nil { return err } From d4462828e937d3cdbdc8b1728be5f17100fa91ac Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Jun 2025 14:56:12 +0200 Subject: [PATCH 03/10] .gitea: touch cron workflow files --- .gitea/workflows/release-azure-cleanup.yml | 2 +- .gitea/workflows/release-ppa.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/release-azure-cleanup.yml b/.gitea/workflows/release-azure-cleanup.yml index 311b2196bb..4a20828d2e 100644 --- a/.gitea/workflows/release-azure-cleanup.yml +++ b/.gitea/workflows/release-azure-cleanup.yml @@ -1,6 +1,6 @@ on: schedule: - - cron: '0 14 * * *' + - cron: '0 15 * * *' workflow_dispatch: jobs: diff --git a/.gitea/workflows/release-ppa.yml b/.gitea/workflows/release-ppa.yml index 6c0631dc99..23bffe773d 100644 --- a/.gitea/workflows/release-ppa.yml +++ b/.gitea/workflows/release-ppa.yml @@ -1,6 +1,6 @@ on: schedule: - - cron: '0 15 * * *' + - cron: '0 16 * * *' push: branches: - "release/*" From 09289fd154a45420ec916eb842bfb172df7e0d83 Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 19 Jun 2025 22:19:54 +0800 Subject: [PATCH 04/10] trie: delete secKeyCacheOwner (#31785) The optimization tried to defer allocating the cache map until it was used for the first time. It's a relic from earlier times, when tries were copied often. This seems unnecessary now, so we can just create the map when the trie is created. --------- Co-authored-by: Felix Lange --- trie/secure_trie.go | 46 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index ac20f961e5..0424ecb6e5 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -64,11 +64,10 @@ func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db da // // StateTrie is not safe for concurrent use. type StateTrie struct { - trie Trie - db database.NodeDatabase - preimages preimageStore - secKeyCache map[common.Hash][]byte - secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch + trie Trie + db database.NodeDatabase + preimages preimageStore + secKeyCache map[common.Hash][]byte } // NewStateTrie creates a trie with an existing root node from a backing database. @@ -84,7 +83,11 @@ func NewStateTrie(id *ID, db database.NodeDatabase) (*StateTrie, error) { if err != nil { return nil, err } - tr := &StateTrie{trie: *trie, db: db} + tr := &StateTrie{ + trie: *trie, + db: db, + secKeyCache: make(map[common.Hash][]byte), + } // link the preimage store if it's supported if preimages, ok := db.(preimageStore); ok && preimages.PreimageEnabled() { @@ -162,7 +165,7 @@ func (t *StateTrie) MustUpdate(key, value []byte) { hk := crypto.Keccak256(key) t.trie.MustUpdate(hk, value) if t.preimages != nil { - t.getSecKeyCache()[common.Hash(hk)] = common.CopyBytes(key) + t.secKeyCache[common.Hash(hk)] = common.CopyBytes(key) } } @@ -182,7 +185,7 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { return err } if t.preimages != nil { - t.getSecKeyCache()[common.Hash(hk)] = common.CopyBytes(key) + t.secKeyCache[common.Hash(hk)] = common.CopyBytes(key) } return nil } @@ -198,7 +201,7 @@ func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccoun return err } if t.preimages != nil { - t.getSecKeyCache()[common.Hash(hk)] = address.Bytes() + t.secKeyCache[common.Hash(hk)] = address.Bytes() } return nil } @@ -212,7 +215,7 @@ func (t *StateTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte func (t *StateTrie) MustDelete(key []byte) { hk := crypto.Keccak256(key) if t.preimages != nil { - delete(t.getSecKeyCache(), common.Hash(hk)) + delete(t.secKeyCache, common.Hash(hk)) } t.trie.MustDelete(hk) } @@ -223,7 +226,7 @@ func (t *StateTrie) MustDelete(key []byte) { func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { hk := crypto.Keccak256(key) if t.preimages != nil { - delete(t.getSecKeyCache(), common.Hash(hk)) + delete(t.secKeyCache, common.Hash(hk)) } return t.trie.Delete(hk) } @@ -232,7 +235,7 @@ func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { func (t *StateTrie) DeleteAccount(address common.Address) error { hk := crypto.Keccak256(address.Bytes()) if t.preimages != nil { - delete(t.getSecKeyCache(), common.Hash(hk)) + delete(t.secKeyCache, common.Hash(hk)) } return t.trie.Delete(hk) } @@ -243,7 +246,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { if t.preimages == nil { return nil } - if key, ok := t.getSecKeyCache()[common.BytesToHash(shaKey)]; ok { + if key, ok := t.secKeyCache[common.BytesToHash(shaKey)]; ok { return key } return t.preimages.Preimage(common.BytesToHash(shaKey)) @@ -263,11 +266,11 @@ func (t *StateTrie) Witness() map[string]struct{} { // be created with new root and updated trie database for following usage func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database - if len(t.getSecKeyCache()) > 0 { + if len(t.secKeyCache) > 0 { if t.preimages != nil { t.preimages.InsertPreimage(t.secKeyCache) } - t.secKeyCache = make(map[common.Hash][]byte) + clear(t.secKeyCache) } // Commit the trie and return its modified nodeset. return t.trie.Commit(collectLeaf) @@ -284,7 +287,7 @@ func (t *StateTrie) Copy() *StateTrie { return &StateTrie{ trie: *t.trie.Copy(), db: t.db, - secKeyCache: t.secKeyCache, + secKeyCache: make(map[common.Hash][]byte), preimages: t.preimages, } } @@ -301,17 +304,6 @@ func (t *StateTrie) MustNodeIterator(start []byte) NodeIterator { return t.trie.MustNodeIterator(start) } -// getSecKeyCache returns the current secure key cache, creating a new one if -// ownership changed (i.e. the current secure trie is a copy of another owning -// the actual cache). -func (t *StateTrie) getSecKeyCache() map[common.Hash][]byte { - if t != t.secKeyCacheOwner { - t.secKeyCacheOwner = t - t.secKeyCache = make(map[common.Hash][]byte) - } - return t.secKeyCache -} - func (t *StateTrie) IsVerkle() bool { return false } From 35dd61a3bff4f20ef939d407bbae0890753e90e2 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 19 Jun 2025 20:37:02 +0200 Subject: [PATCH 05/10] .gitea: show environment in release-ppa.yml --- .gitea/workflows/release-ppa.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/release-ppa.yml b/.gitea/workflows/release-ppa.yml index 23bffe773d..f164f85931 100644 --- a/.gitea/workflows/release-ppa.yml +++ b/.gitea/workflows/release-ppa.yml @@ -13,6 +13,10 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Show environment + run: | + env + - name: Set up Go uses: actions/setup-go@v5 with: From 6723388b013c7d5187be720aec50310ce3f45adc Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 20 Jun 2025 12:47:48 +0200 Subject: [PATCH 06/10] crypto/bn256/gnark: align marshaling behavior (#32065) Aligns the marshaling behavior of gnark to google and cloudflare Co-authored-by: kevaundray --- crypto/bn256/gnark/g2.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/crypto/bn256/gnark/g2.go b/crypto/bn256/gnark/g2.go index 07452cc2d8..48a797e5a7 100644 --- a/crypto/bn256/gnark/g2.go +++ b/crypto/bn256/gnark/g2.go @@ -21,7 +21,7 @@ type G2 struct { // Unmarshal deserializes `buf` into `g` // // The input is expected to be in the EVM format: -// 128 bytes: [32-byte x.0][32-byte x.1][32-byte y.0][32-byte y.1] +// 128 bytes: [32-byte x.1][32-byte x.0][32-byte y.1][32-byte y.0] // where each value is a big-endian integer. // // This method also checks whether the point is on the @@ -39,16 +39,16 @@ func (g *G2) Unmarshal(buf []byte) (int, error) { g.inner.Y.A1.SetZero() return 128, nil } - if err := g.inner.X.A0.SetBytesCanonical(buf[0:32]); err != nil { + if err := g.inner.X.A1.SetBytesCanonical(buf[0:32]); err != nil { return 0, err } - if err := g.inner.X.A1.SetBytesCanonical(buf[32:64]); err != nil { + if err := g.inner.X.A0.SetBytesCanonical(buf[32:64]); err != nil { return 0, err } - if err := g.inner.Y.A0.SetBytesCanonical(buf[64:96]); err != nil { + if err := g.inner.Y.A1.SetBytesCanonical(buf[64:96]); err != nil { return 0, err } - if err := g.inner.Y.A1.SetBytesCanonical(buf[96:128]); err != nil { + if err := g.inner.Y.A0.SetBytesCanonical(buf[96:128]); err != nil { return 0, err } @@ -64,22 +64,22 @@ func (g *G2) Unmarshal(buf []byte) (int, error) { // Marshal serializes the point into a byte slice. // // The output is in EVM format: 128 bytes total. -// [32-byte x.0][32-byte x.1][32-byte y.0][32-byte y.1] +// [32-byte x.1][32-byte x.0][32-byte y.1][32-byte y.0] // where each value is a big-endian integer. func (g *G2) Marshal() []byte { output := make([]byte, 128) - xA0Bytes := g.inner.X.A0.Bytes() - copy(output[:32], xA0Bytes[:]) - xA1Bytes := g.inner.X.A1.Bytes() - copy(output[32:64], xA1Bytes[:]) + copy(output[:32], xA1Bytes[:]) - yA0Bytes := g.inner.Y.A0.Bytes() - copy(output[64:96], yA0Bytes[:]) + xA0Bytes := g.inner.X.A0.Bytes() + copy(output[32:64], xA0Bytes[:]) yA1Bytes := g.inner.Y.A1.Bytes() - copy(output[96:128], yA1Bytes[:]) + copy(output[64:96], yA1Bytes[:]) + + yA0Bytes := g.inner.Y.A0.Bytes() + copy(output[96:128], yA0Bytes[:]) return output } From f26b5653e8bf8196eeaae4c5447a0dd84b8aef80 Mon Sep 17 00:00:00 2001 From: Antonio Sanso Date: Fri, 20 Jun 2025 13:18:20 +0200 Subject: [PATCH 07/10] crypto/bn256: add documentation on subgroup checks for G2 (#32066) This PR improves the IsOnCurve methods for BN254 G2 points by: * Clarifying its behavior the docstring, making it explicit that it verifies both the point being on the curve and in the correct subgroup. * Adding an in-line comment explaining the subgroup membership check (c.Mul(Order)). * Minor wording adjustments for readability and consistency. --- crypto/bn256/cloudflare/twist.go | 4 +++- crypto/bn256/google/twist.go | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crypto/bn256/cloudflare/twist.go b/crypto/bn256/cloudflare/twist.go index 2c7a69a4d7..c2e39c57ca 100644 --- a/crypto/bn256/cloudflare/twist.go +++ b/crypto/bn256/cloudflare/twist.go @@ -43,7 +43,7 @@ func (c *twistPoint) Set(a *twistPoint) { c.t.Set(&a.t) } -// IsOnCurve returns true iff c is on the curve. +// IsOnCurve returns true iff c is on the curve and is in the correct subgroup. func (c *twistPoint) IsOnCurve() bool { c.MakeAffine() if c.IsInfinity() { @@ -57,6 +57,8 @@ func (c *twistPoint) IsOnCurve() bool { if *y2 != *x3 { return false } + // Subgroup check: multiply the point by the group order and + // verify that it becomes the point at infinity. cneg := &twistPoint{} cneg.Mul(c, Order) return cneg.z.IsZero() diff --git a/crypto/bn256/google/twist.go b/crypto/bn256/google/twist.go index 43364ff5b7..631d1ca8df 100644 --- a/crypto/bn256/google/twist.go +++ b/crypto/bn256/google/twist.go @@ -67,7 +67,7 @@ func (c *twistPoint) Set(a *twistPoint) { c.t.Set(a.t) } -// IsOnCurve returns true iff c is on the curve where c must be in affine form. +// IsOnCurve returns true iff c is on the curve and is in the correct subgroup, where c must be in affine form. func (c *twistPoint) IsOnCurve() bool { pool := new(bnPool) yy := newGFp2(pool).Square(c.y, pool) @@ -80,6 +80,8 @@ func (c *twistPoint) IsOnCurve() bool { if yy.x.Sign() != 0 || yy.y.Sign() != 0 { return false } + // Subgroup check: multiply the point by the group order and + // verify that it becomes the point at infinity. cneg := newTwistPoint(pool) cneg.Mul(c, Order, pool) return cneg.z.IsZero() From 846d13a31a21acbf3ad4c33be47a68266e54d60d Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Fri, 20 Jun 2025 18:40:41 +0700 Subject: [PATCH 08/10] ethdb: Implement DeleteRange in batch (#31947) implement #31945 --------- Co-authored-by: prpeh Co-authored-by: Gary Rong --- core/rawdb/table.go | 15 ++ core/rawdb/table_test.go | 24 +++ ethdb/batch.go | 14 +- ethdb/database.go | 18 ++ ethdb/dbtest/testsuite.go | 377 +++++++++++++++++++++++++++++++++++++ ethdb/leveldb/leveldb.go | 48 ++++- ethdb/memorydb/memorydb.go | 78 ++++++-- ethdb/pebble/pebble.go | 36 +++- trie/trie_test.go | 1 + 9 files changed, 591 insertions(+), 20 deletions(-) diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 5eb3fe45d1..45c8aecf0c 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -126,6 +126,11 @@ func (t *table) Delete(key []byte) error { // DeleteRange deletes all of the keys (and values) in the range [start,end) // (inclusive on start, exclusive on end). func (t *table) DeleteRange(start, end []byte) error { + // The nilness will be lost by adding the prefix, explicitly converting it + // to a special flag representing the end of key range. + if end == nil { + end = ethdb.MaximumKey + } return t.db.DeleteRange(append([]byte(t.prefix), start...), append([]byte(t.prefix), end...)) } @@ -217,6 +222,16 @@ func (b *tableBatch) Delete(key []byte) error { return b.batch.Delete(append([]byte(b.prefix), key...)) } +// DeleteRange removes all keys in the range [start, end) from the batch for later committing. +func (b *tableBatch) DeleteRange(start, end []byte) error { + // The nilness will be lost by adding the prefix, explicitly converting it + // to a special flag representing the end of key range. + if end == nil { + end = ethdb.MaximumKey + } + return b.batch.DeleteRange(append([]byte(b.prefix), start...), append([]byte(b.prefix), end...)) +} + // ValueSize retrieves the amount of data queued up for writing. func (b *tableBatch) ValueSize() int { return b.batch.ValueSize() diff --git a/core/rawdb/table_test.go b/core/rawdb/table_test.go index aa6adf3e72..36fd331059 100644 --- a/core/rawdb/table_test.go +++ b/core/rawdb/table_test.go @@ -125,4 +125,28 @@ func testTableDatabase(t *testing.T, prefix string) { // Test iterators with prefix and start point check(db.NewIterator([]byte{0xee}, nil), 0, 0) check(db.NewIterator(nil, []byte{0x00}), 6, 0) + + // Test range deletion + db.DeleteRange(nil, nil) + for _, entry := range entries { + _, err := db.Get(entry.key) + if err == nil { + t.Fatal("Unexpected item after deletion") + } + } + // Test range deletion by batch + batch = db.NewBatch() + for _, entry := range entries { + batch.Put(entry.key, entry.value) + } + batch.Write() + batch.Reset() + batch.DeleteRange(nil, nil) + batch.Write() + for _, entry := range entries { + _, err := db.Get(entry.key) + if err == nil { + t.Fatal("Unexpected item after deletion") + } + } } diff --git a/ethdb/batch.go b/ethdb/batch.go index 541f40c838..45b3781cb0 100644 --- a/ethdb/batch.go +++ b/ethdb/batch.go @@ -24,6 +24,7 @@ const IdealBatchSize = 100 * 1024 // when Write is called. A batch cannot be used concurrently. type Batch interface { KeyValueWriter + KeyValueRangeDeleter // ValueSize retrieves the amount of data queued up for writing. ValueSize() int @@ -53,8 +54,9 @@ type Batcher interface { type HookedBatch struct { Batch - OnPut func(key []byte, value []byte) // Callback if a key is inserted - OnDelete func(key []byte) // Callback if a key is deleted + OnPut func(key []byte, value []byte) // Callback if a key is inserted + OnDelete func(key []byte) // Callback if a key is deleted + OnDeleteRange func(start, end []byte) // Callback if a range of keys is deleted } // Put inserts the given value into the key-value data store. @@ -72,3 +74,11 @@ func (b HookedBatch) Delete(key []byte) error { } return b.Batch.Delete(key) } + +// DeleteRange removes all keys in the range [start, end) from the key-value data store. +func (b HookedBatch) DeleteRange(start, end []byte) error { + if b.OnDeleteRange != nil { + b.OnDeleteRange(start, end) + } + return b.Batch.DeleteRange(start, end) +} diff --git a/ethdb/database.go b/ethdb/database.go index b8aef2ae1d..e665a84a61 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -18,10 +18,23 @@ package ethdb import ( + "bytes" "errors" "io" ) +var ( + // MaximumKey is a special marker representing the largest possible key + // in the database. + // + // All prefixed database entries will be smaller than this marker. + // For trie nodes in hash mode, we use a 32-byte slice filled with 0xFF + // because there may be shared prefixes starting with multiple 0xFF bytes. + // Using 32 bytes ensures that only a hash collision could potentially + // match or exceed it. + MaximumKey = bytes.Repeat([]byte{0xff}, 32) +) + // KeyValueReader wraps the Has and Get method of a backing data store. type KeyValueReader interface { // Has retrieves if a key is present in the key-value data store. @@ -46,6 +59,11 @@ var ErrTooManyKeys = errors.New("too many keys in deleted range") type KeyValueRangeDeleter interface { // DeleteRange deletes all of the keys (and values) in the range [start,end) // (inclusive on start, exclusive on end). + // + // A nil start is treated as a key before all keys in the data store; a nil + // end is treated as a key after all keys in the data store. If both is nil + // then the entire data store will be purged. + // // Some implementations of DeleteRange may return ErrTooManyKeys after // partially deleting entries in the given range. DeleteRange(start, end []byte) error diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 52e6b287cf..862ddabb6a 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -401,6 +401,308 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { db.DeleteRange([]byte(""), []byte("a")) checkRange(1, 999, false) + + addRange(1, 999) + db.DeleteRange(nil, nil) + checkRange(1, 999, false) + }) + + t.Run("BatchDeleteRange", func(t *testing.T) { + db := New() + defer db.Close() + + // Helper to add keys + addKeys := func(start, stop int) { + for i := start; i <= stop; i++ { + if err := db.Put([]byte(strconv.Itoa(i)), []byte("val-"+strconv.Itoa(i))); err != nil { + t.Fatal(err) + } + } + } + + // Helper to check if keys exist + checkKeys := func(start, stop int, shouldExist bool) { + for i := start; i <= stop; i++ { + key := []byte(strconv.Itoa(i)) + has, err := db.Has(key) + if err != nil { + t.Fatal(err) + } + if has != shouldExist { + if shouldExist { + t.Fatalf("key %s should exist but doesn't", key) + } else { + t.Fatalf("key %s shouldn't exist but does", key) + } + } + } + } + + // Test 1: Basic range deletion in batch + addKeys(1, 10) + checkKeys(1, 10, true) + + batch := db.NewBatch() + if err := batch.DeleteRange([]byte("3"), []byte("8")); err != nil { + t.Fatal(err) + } + // Keys shouldn't be deleted until Write is called + checkKeys(1, 10, true) + + if err := batch.Write(); err != nil { + t.Fatal(err) + } + // After Write, keys in range should be deleted + // Range is [start, end) - inclusive of start, exclusive of end + checkKeys(1, 2, true) // These should still exist + checkKeys(3, 7, false) // These should be deleted (3 to 7 inclusive) + checkKeys(8, 10, true) // These should still exist (8 is the end boundary, exclusive) + + // Test 2: Delete range with special markers + addKeys(3, 7) + batch = db.NewBatch() + if err := batch.DeleteRange(nil, nil); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + checkKeys(1, 10, false) + + // Test 3: Mix Put, Delete, and DeleteRange in a batch + // Reset database for next test by adding back deleted keys + addKeys(1, 10) + checkKeys(1, 10, true) + + // Create a new batch with multiple operations + batch = db.NewBatch() + if err := batch.Put([]byte("5"), []byte("new-val-5")); err != nil { + t.Fatal(err) + } + if err := batch.Delete([]byte("9")); err != nil { + t.Fatal(err) + } + if err := batch.DeleteRange([]byte("1"), []byte("3")); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + // Check results after batch operations + // Keys 1-2 should be deleted by DeleteRange + checkKeys(1, 2, false) + + // Key 3 should exist (exclusive of end) + has, err := db.Has([]byte("3")) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatalf("key 3 should exist after DeleteRange(1,3)") + } + + // Key 5 should have a new value + val, err := db.Get([]byte("5")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(val, []byte("new-val-5")) { + t.Fatalf("key 5 has wrong value: got %s, want %s", val, "new-val-5") + } + + // Key 9 should be deleted + has, err = db.Has([]byte("9")) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key 9 should be deleted") + } + + // Test 4: Reset batch + batch.Reset() + // Individual deletes work better with both string and numeric comparisons + if err := batch.Delete([]byte("8")); err != nil { + t.Fatal(err) + } + if err := batch.Delete([]byte("10")); err != nil { + t.Fatal(err) + } + if err := batch.Delete([]byte("11")); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + + // Key 8 should be deleted + has, err = db.Has([]byte("8")) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key 8 should be deleted") + } + + // Keys 3-7 should still exist + checkKeys(3, 7, true) + + // Key 10 should be deleted + has, err = db.Has([]byte("10")) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key 10 should be deleted") + } + + // Test 5: Empty range + batch = db.NewBatch() + if err := batch.DeleteRange([]byte("100"), []byte("100")); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + // No existing keys should be affected + checkKeys(3, 7, true) + + // Test 6: Test entire keyspace deletion + // First clear any existing keys + for i := 1; i <= 100; i++ { + db.Delete([]byte(strconv.Itoa(i))) + } + + // Then add some fresh test keys + addKeys(50, 60) + + // Verify keys exist before deletion + checkKeys(50, 60, true) + + batch = db.NewBatch() + if err := batch.DeleteRange([]byte(""), []byte("z")); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + // All keys should be deleted + checkKeys(50, 60, false) + + // Test 7: overlapping range deletion + addKeys(50, 60) + batch = db.NewBatch() + if err := batch.DeleteRange([]byte("50"), []byte("55")); err != nil { + t.Fatal(err) + } + if err := batch.DeleteRange([]byte("52"), []byte("58")); err != nil { + t.Fatal(err) + } + if err := batch.Write(); err != nil { + t.Fatal(err) + } + checkKeys(50, 57, false) + checkKeys(58, 60, true) + }) + + t.Run("BatchReplayWithDeleteRange", func(t *testing.T) { + db := New() + defer db.Close() + + // Setup some initial data + for i := 1; i <= 10; i++ { + if err := db.Put([]byte(strconv.Itoa(i)), []byte("val-"+strconv.Itoa(i))); err != nil { + t.Fatal(err) + } + } + + // Create batch with multiple operations including DeleteRange + batch1 := db.NewBatch() + batch1.Put([]byte("new-key-1"), []byte("new-val-1")) + batch1.DeleteRange([]byte("3"), []byte("7")) // Should delete keys 3-6 but not 7 + batch1.Delete([]byte("8")) + batch1.Put([]byte("new-key-2"), []byte("new-val-2")) + + // Create a second batch to replay into + batch2 := db.NewBatch() + if err := batch1.Replay(batch2); err != nil { + t.Fatal(err) + } + + // Write the second batch + if err := batch2.Write(); err != nil { + t.Fatal(err) + } + + // Verify results + // Original keys 3-6 should be deleted (inclusive of start, exclusive of end) + for i := 3; i <= 6; i++ { + has, err := db.Has([]byte(strconv.Itoa(i))) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key %d should be deleted", i) + } + } + + // Key 7 should NOT be deleted (exclusive of end) + has, err := db.Has([]byte("7")) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatalf("key 7 should NOT be deleted (exclusive of end)") + } + + // Key 8 should be deleted + has, err = db.Has([]byte("8")) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key 8 should be deleted") + } + + // New keys should be added + for _, key := range []string{"new-key-1", "new-key-2"} { + has, err := db.Has([]byte(key)) + if err != nil { + t.Fatal(err) + } + if !has { + t.Fatalf("key %s should exist", key) + } + } + + // Create a third batch for direct replay to database + batch3 := db.NewBatch() + batch3.DeleteRange([]byte("1"), []byte("3")) // Should delete keys 1-2 but not 3 + + // Replay directly to the database + if err := batch3.Replay(db); err != nil { + t.Fatal(err) + } + + // Verify keys 1-2 are now deleted + for i := 1; i <= 2; i++ { + has, err := db.Has([]byte(strconv.Itoa(i))) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key %d should be deleted after direct replay", i) + } + } + + // Verify key 3 is NOT deleted (since it's exclusive of end) + has, err = db.Has([]byte("3")) + if err != nil { + t.Fatal(err) + } + if has { + t.Fatalf("key 3 should still be deleted from previous operation") + } }) } @@ -520,6 +822,81 @@ func BenchDatabaseSuite(b *testing.B, New func() ethdb.KeyValueStore) { benchDeleteRange(b, 10000) }) }) + b.Run("BatchDeleteRange", func(b *testing.B) { + benchBatchDeleteRange := func(b *testing.B, count int) { + db := New() + defer db.Close() + + // Prepare data + for i := 0; i < count; i++ { + db.Put([]byte(strconv.Itoa(i)), nil) + } + + b.ResetTimer() + b.ReportAllocs() + + // Create batch and delete range + batch := db.NewBatch() + batch.DeleteRange([]byte("0"), []byte("999999999")) + batch.Write() + } + + b.Run("BatchDeleteRange100", func(b *testing.B) { + benchBatchDeleteRange(b, 100) + }) + b.Run("BatchDeleteRange1k", func(b *testing.B) { + benchBatchDeleteRange(b, 1000) + }) + b.Run("BatchDeleteRange10k", func(b *testing.B) { + benchBatchDeleteRange(b, 10000) + }) + }) + + b.Run("BatchMixedOps", func(b *testing.B) { + benchBatchMixedOps := func(b *testing.B, count int) { + db := New() + defer db.Close() + + // Prepare initial data + for i := 0; i < count; i++ { + db.Put([]byte(strconv.Itoa(i)), []byte("val")) + } + + b.ResetTimer() + b.ReportAllocs() + + // Create batch with mixed operations + batch := db.NewBatch() + + // Add some new keys + for i := 0; i < count/10; i++ { + batch.Put([]byte(strconv.Itoa(count+i)), []byte("new-val")) + } + + // Delete some individual keys + for i := 0; i < count/20; i++ { + batch.Delete([]byte(strconv.Itoa(i * 2))) + } + + // Delete range of keys + rangeStart := count / 2 + rangeEnd := count * 3 / 4 + batch.DeleteRange([]byte(strconv.Itoa(rangeStart)), []byte(strconv.Itoa(rangeEnd))) + + // Write the batch + batch.Write() + } + + b.Run("BatchMixedOps100", func(b *testing.B) { + benchBatchMixedOps(b, 100) + }) + b.Run("BatchMixedOps1k", func(b *testing.B) { + benchBatchMixedOps(b, 1000) + }) + b.Run("BatchMixedOps10k", func(b *testing.B) { + benchBatchMixedOps(b, 10000) + }) + }) } func iterateKeys(it ethdb.Iterator) []string { diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 223d01aff6..736a44d73d 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -220,7 +220,7 @@ func (db *Database) DeleteRange(start, end []byte) error { defer it.Release() var count int - for it.Next() && bytes.Compare(end, it.Key()) > 0 { + for it.Next() && (end == nil || bytes.Compare(end, it.Key()) > 0) { count++ if count > 10000 { // should not block for more than a second if err := batch.Write(); err != nil { @@ -461,6 +461,38 @@ func (b *batch) Delete(key []byte) error { return nil } +// DeleteRange removes all keys in the range [start, end) from the batch for +// later committing, inclusive on start, exclusive on end. +// +// Note that this is a fallback implementation as leveldb does not natively +// support range deletion in batches. It iterates through the database to find +// keys in the range and adds them to the batch for deletion. +func (b *batch) DeleteRange(start, end []byte) error { + // Create an iterator to scan through the keys in the range + slice := &util.Range{ + Start: start, // If nil, it represents the key before all keys + Limit: end, // If nil, it represents the key after all keys + } + it := b.db.NewIterator(slice, nil) + defer it.Release() + + var count int + for it.Next() { + count++ + key := it.Key() + if count > 10000 { // should not block for more than a second + return ethdb.ErrTooManyKeys + } + // Add this key to the batch for deletion + b.b.Delete(key) + b.size += len(key) + } + if err := it.Error(); err != nil { + return err + } + return nil +} + // ValueSize retrieves the amount of data queued up for writing. func (b *batch) ValueSize() int { return b.size @@ -506,6 +538,20 @@ func (r *replayer) Delete(key []byte) { r.failure = r.writer.Delete(key) } +// DeleteRange removes all keys in the range [start, end) from the key-value data store. +func (r *replayer) DeleteRange(start, end []byte) { + // If the replay already failed, stop executing ops + if r.failure != nil { + return + } + // Check if the writer also supports range deletion + if rangeDeleter, ok := r.writer.(ethdb.KeyValueRangeDeleter); ok { + r.failure = rangeDeleter.DeleteRange(start, end) + } else { + r.failure = fmt.Errorf("ethdb.KeyValueWriter does not implement DeleteRange") + } +} + // bytesPrefixRange returns key range that satisfy // - the given prefix, and // - the given seek position diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index f56727cf4a..5c4c48de64 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -18,7 +18,9 @@ package memorydb import ( + "bytes" "errors" + "fmt" "sort" "strings" "sync" @@ -122,18 +124,24 @@ func (db *Database) Delete(key []byte) error { } // DeleteRange deletes all of the keys (and values) in the range [start,end) -// (inclusive on start, exclusive on end). +// (inclusive on start, exclusive on end). If the start is nil, it represents +// the key before all keys; if the end is nil, it represents the key after +// all keys. func (db *Database) DeleteRange(start, end []byte) error { db.lock.Lock() defer db.lock.Unlock() + if db.db == nil { return errMemorydbClosed } - for key := range db.db { - if key >= string(start) && key < string(end) { - delete(db.db, key) + if start != nil && key < string(start) { + continue } + if end != nil && key >= string(end) { + continue + } + delete(db.db, key) } return nil } @@ -222,6 +230,9 @@ type keyvalue struct { key string value []byte delete bool + + rangeFrom []byte + rangeTo []byte } // batch is a write-only memory batch that commits changes to its host @@ -234,18 +245,29 @@ type batch struct { // Put inserts the given value into the batch for later committing. func (b *batch) Put(key, value []byte) error { - b.writes = append(b.writes, keyvalue{string(key), common.CopyBytes(value), false}) + b.writes = append(b.writes, keyvalue{key: string(key), value: common.CopyBytes(value)}) b.size += len(key) + len(value) return nil } // Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { - b.writes = append(b.writes, keyvalue{string(key), nil, true}) + b.writes = append(b.writes, keyvalue{key: string(key), delete: true}) b.size += len(key) return nil } +// DeleteRange removes all keys in the range [start, end) from the batch for later committing. +func (b *batch) DeleteRange(start, end []byte) error { + b.writes = append(b.writes, keyvalue{ + rangeFrom: bytes.Clone(start), + rangeTo: bytes.Clone(end), + delete: true, + }) + b.size += len(start) + len(end) + return nil +} + // ValueSize retrieves the amount of data queued up for writing. func (b *batch) ValueSize() int { return b.size @@ -259,12 +281,26 @@ func (b *batch) Write() error { if b.db.db == nil { return errMemorydbClosed } - for _, keyvalue := range b.writes { - if keyvalue.delete { - delete(b.db.db, keyvalue.key) + for _, entry := range b.writes { + if entry.delete { + if entry.key != "" { + // Single key deletion + delete(b.db.db, entry.key) + } else { + // Range deletion (inclusive of start, exclusive of end) + for key := range b.db.db { + if entry.rangeFrom != nil && key < string(entry.rangeFrom) { + continue + } + if entry.rangeTo != nil && key >= string(entry.rangeTo) { + continue + } + delete(b.db.db, key) + } + } continue } - b.db.db[keyvalue.key] = keyvalue.value + b.db.db[entry.key] = entry.value } return nil } @@ -277,14 +313,26 @@ func (b *batch) Reset() { // Replay replays the batch contents. func (b *batch) Replay(w ethdb.KeyValueWriter) error { - for _, keyvalue := range b.writes { - if keyvalue.delete { - if err := w.Delete([]byte(keyvalue.key)); err != nil { - return err + for _, entry := range b.writes { + if entry.delete { + if entry.key != "" { + // Single key deletion + if err := w.Delete([]byte(entry.key)); err != nil { + return err + } + } else { + // Range deletion + if rangeDeleter, ok := w.(ethdb.KeyValueRangeDeleter); ok { + if err := rangeDeleter.DeleteRange(entry.rangeFrom, entry.rangeTo); err != nil { + return err + } + } else { + return fmt.Errorf("ethdb.KeyValueWriter does not implement DeleteRange") + } } continue } - if err := w.Put([]byte(keyvalue.key), keyvalue.value); err != nil { + if err := w.Put([]byte(entry.key), entry.value); err != nil { return err } } diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index ef687bd464..ac9eb9bdba 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -18,7 +18,6 @@ package pebble import ( - "bytes" "fmt" "runtime" "strings" @@ -417,9 +416,16 @@ func (d *Database) Delete(key []byte) error { func (d *Database) DeleteRange(start, end []byte) error { d.quitLock.RLock() defer d.quitLock.RUnlock() + if d.closed { return pebble.ErrClosed } + // There is no special flag to represent the end of key range + // in pebble(nil in leveldb). Use an ugly hack to construct a + // large key to represent it. + if end == nil { + end = ethdb.MaximumKey + } return d.db.DeleteRange(start, end, d.writeOptions) } @@ -478,7 +484,7 @@ func (d *Database) Compact(start []byte, limit []byte) error { // 0xff-s, so 32 ensures than only a hash collision could touch it. // https://github.com/cockroachdb/pebble/issues/2359#issuecomment-1443995833 if limit == nil { - limit = bytes.Repeat([]byte{0xff}, 32) + limit = ethdb.MaximumKey } return d.db.Compact(start, limit, true) // Parallelization is preferred } @@ -633,6 +639,23 @@ func (b *batch) Delete(key []byte) error { return nil } +// DeleteRange removes all keys in the range [start, end) from the batch for +// later committing, inclusive on start, exclusive on end. +func (b *batch) DeleteRange(start, end []byte) error { + // There is no special flag to represent the end of key range + // in pebble(nil in leveldb). Use an ugly hack to construct a + // large key to represent it. + if end == nil { + end = ethdb.MaximumKey + } + if err := b.b.DeleteRange(start, end, nil); err != nil { + return err + } + // Approximate size impact - just the keys + b.size += len(start) + len(end) + return nil +} + // ValueSize retrieves the amount of data queued up for writing. func (b *batch) ValueSize() int { return b.size @@ -672,6 +695,15 @@ func (b *batch) Replay(w ethdb.KeyValueWriter) error { if err = w.Delete(k); err != nil { return err } + } else if kind == pebble.InternalKeyKindRangeDelete { + // For range deletion, k is the start key and v is the end key + if rangeDeleter, ok := w.(ethdb.KeyValueRangeDeleter); ok { + if err = rangeDeleter.DeleteRange(k, v); err != nil { + return err + } + } else { + return fmt.Errorf("ethdb.KeyValueWriter does not implement DeleteRange") + } } else { return fmt.Errorf("unhandled operation, keytype: %v", kind) } diff --git a/trie/trie_test.go b/trie/trie_test.go index 91fde6dbf2..b806ae6b0c 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -876,6 +876,7 @@ func (b *spongeBatch) Put(key, value []byte) error { return nil } func (b *spongeBatch) Delete(key []byte) error { panic("implement me") } +func (b *spongeBatch) DeleteRange(start, end []byte) error { panic("implement me") } func (b *spongeBatch) ValueSize() int { return 100 } func (b *spongeBatch) Write() error { return nil } func (b *spongeBatch) Reset() {} From c7b8924fe437fb22f671c83171154ff5ed134088 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Sat, 21 Jun 2025 12:58:04 +0800 Subject: [PATCH 09/10] core/state: expose the state reader stats (#31998) This pull request introduces a mechanism to expose statistics from the state reader, specifically related to cache utilization during state prefetching. To improve state access performance, a pair of state readers is constructed with a shared local cache. One reader to execute transactions ahead of time to warm up the cache. The other reader is used by the actual chain processing logic, which can benefit from the prefetched states. This PR adds visibility into how effective the cache is by exposing relevant usage statistics. --------- Signed-off-by: Csaba Kiraly Co-authored-by: Csaba Kiraly --- core/blockchain.go | 30 +++++++++-- core/state/database.go | 11 ++-- core/state/reader.go | 117 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 139 insertions(+), 19 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 25b37b5cce..ec979a6b17 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -77,6 +77,16 @@ var ( storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil) storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil) + accountCacheHitMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/hit", nil) + accountCacheMissMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/miss", nil) + storageCacheHitMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/process/hit", nil) + storageCacheMissMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/process/miss", nil) + + accountCacheHitPrefetchMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/prefetch/hit", nil) + accountCacheMissPrefetchMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/prefetch/miss", nil) + storageCacheHitPrefetchMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/prefetch/hit", nil) + storageCacheMissPrefetchMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/prefetch/miss", nil) + accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil) storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil) @@ -1944,18 +1954,32 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s // // Note: the main processor and prefetcher share the same reader with a local // cache for mitigating the overhead of state access. - reader, err := bc.statedb.ReaderWithCache(parentRoot) + prefetch, process, err := bc.statedb.ReadersWithCacheStats(parentRoot) if err != nil { return nil, err } - throwaway, err := state.NewWithReader(parentRoot, bc.statedb, reader) + throwaway, err := state.NewWithReader(parentRoot, bc.statedb, prefetch) if err != nil { return nil, err } - statedb, err = state.NewWithReader(parentRoot, bc.statedb, reader) + statedb, err = state.NewWithReader(parentRoot, bc.statedb, process) if err != nil { return nil, err } + // Upload the statistics of reader at the end + defer func() { + stats := prefetch.GetStats() + accountCacheHitPrefetchMeter.Mark(stats.AccountHit) + accountCacheMissPrefetchMeter.Mark(stats.AccountMiss) + storageCacheHitPrefetchMeter.Mark(stats.StorageHit) + storageCacheMissPrefetchMeter.Mark(stats.StorageMiss) + stats = process.GetStats() + accountCacheHitMeter.Mark(stats.AccountHit) + accountCacheMissMeter.Mark(stats.AccountMiss) + storageCacheHitMeter.Mark(stats.StorageHit) + storageCacheMissMeter.Mark(stats.StorageMiss) + }() + go func(start time.Time, throwaway *state.StateDB, block *types.Block) { // Disable tracing for prefetcher executions. vmCfg := bc.cfg.VmConfig diff --git a/core/state/database.go b/core/state/database.go index aec841f59b..5fb198a629 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -209,13 +209,16 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil } -// ReaderWithCache creates a state reader with internal local cache. -func (db *CachingDB) ReaderWithCache(stateRoot common.Hash) (Reader, error) { +// ReadersWithCacheStats creates a pair of state readers sharing the same internal cache and +// same backing Reader, but exposing separate statistics. +// and statistics. +func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, error) { reader, err := db.Reader(stateRoot) if err != nil { - return nil, err + return nil, nil, err } - return newReaderWithCache(reader), nil + shared := newReaderWithCache(reader) + return newReaderWithCacheStats(shared), newReaderWithCacheStats(shared), nil } // OpenTrie opens the main account trie at a specific root hash. diff --git a/core/state/reader.go b/core/state/reader.go index 695521a71e..4628f4d5db 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -19,6 +19,7 @@ package state import ( "errors" "sync" + "sync/atomic" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" @@ -82,6 +83,20 @@ type Reader interface { StateReader } +// ReaderStats wraps the statistics of reader. +type ReaderStats struct { + AccountHit int64 + AccountMiss int64 + StorageHit int64 + StorageMiss int64 +} + +// ReaderWithStats wraps the additional method to retrieve the reader statistics from. +type ReaderWithStats interface { + Reader + GetStats() ReaderStats +} + // cachingCodeReader implements ContractCodeReader, accessing contract code either in // local key-value store or the shared code cache. // @@ -414,35 +429,43 @@ func newReaderWithCache(reader Reader) *readerWithCache { return r } -// Account implements StateReader, retrieving the account specified by the address. -// The returned account might be nil if it's not existent. +// account retrieves the account specified by the address along with a flag +// indicating whether it's found in the cache or not. The returned account +// might be nil if it's not existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) { +func (r *readerWithCache) account(addr common.Address) (*types.StateAccount, bool, error) { // Try to resolve the requested account in the local cache r.accountLock.RLock() acct, ok := r.accounts[addr] r.accountLock.RUnlock() if ok { - return acct, nil + return acct, true, nil } // Try to resolve the requested account from the underlying reader acct, err := r.Reader.Account(addr) if err != nil { - return nil, err + return nil, false, err } r.accountLock.Lock() r.accounts[addr] = acct r.accountLock.Unlock() - return acct, nil + return acct, false, nil } -// Storage implements StateReader, retrieving the storage slot specified by the -// address and slot key. The returned storage slot might be empty if it's not -// existent. +// Account implements StateReader, retrieving the account specified by the address. +// The returned account might be nil if it's not existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { +func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) { + account, _, err := r.account(addr) + return account, err +} + +// storage retrieves the storage slot specified by the address and slot key, along +// with a flag indicating whether it's found in the cache or not. The returned +// storage slot might be empty if it's not existent. +func (r *readerWithCache) storage(addr common.Address, slot common.Hash) (common.Hash, bool, error) { var ( value common.Hash ok bool @@ -456,12 +479,12 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common } bucket.lock.RUnlock() if ok { - return value, nil + return value, true, nil } // Try to resolve the requested storage slot from the underlying reader value, err := r.Reader.Storage(addr, slot) if err != nil { - return common.Hash{}, err + return common.Hash{}, false, err } bucket.lock.Lock() slots, ok = bucket.storages[addr] @@ -472,5 +495,75 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common slots[slot] = value bucket.lock.Unlock() + return value, false, nil +} + +// Storage implements StateReader, retrieving the storage slot specified by the +// address and slot key. The returned storage slot might be empty if it's not +// existent. +// +// An error will be returned if the state is corrupted in the underlying reader. +func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { + value, _, err := r.storage(addr, slot) + return value, err +} + +type readerWithCacheStats struct { + *readerWithCache + accountHit atomic.Int64 + accountMiss atomic.Int64 + storageHit atomic.Int64 + storageMiss atomic.Int64 +} + +// newReaderWithCacheStats constructs the reader with additional statistics tracked. +func newReaderWithCacheStats(reader *readerWithCache) *readerWithCacheStats { + return &readerWithCacheStats{ + readerWithCache: reader, + } +} + +// Account implements StateReader, retrieving the account specified by the address. +// The returned account might be nil if it's not existent. +// +// An error will be returned if the state is corrupted in the underlying reader. +func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount, error) { + account, incache, err := r.readerWithCache.account(addr) + if err != nil { + return nil, err + } + if incache { + r.accountHit.Add(1) + } else { + r.accountMiss.Add(1) + } + return account, nil +} + +// Storage implements StateReader, retrieving the storage slot specified by the +// address and slot key. The returned storage slot might be empty if it's not +// existent. +// +// An error will be returned if the state is corrupted in the underlying reader. +func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { + value, incache, err := r.readerWithCache.storage(addr, slot) + if err != nil { + return common.Hash{}, err + } + if incache { + r.storageHit.Add(1) + } else { + r.storageMiss.Add(1) + } return value, nil } + +// GetStats implements ReaderWithStats, returning the statistics of state reader. +func (r *readerWithCacheStats) GetStats() ReaderStats { + return ReaderStats{ + AccountHit: r.accountHit.Load(), + AccountMiss: r.accountMiss.Load(), + StorageHit: r.storageHit.Load(), + StorageMiss: r.storageMiss.Load(), + } +} From 6eab053088e343a84a60691fec8228959afbe76e Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Sat, 21 Jun 2025 07:00:32 +0200 Subject: [PATCH 10/10] core/state: improve the prefetcher concurrency allowance (#32071) Improve the prefetcher concurrency allowance. --- core/state_prefetcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index f3129f57cd..2f40e3dc97 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -57,7 +57,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c workers errgroup.Group reader = statedb.Reader() ) - workers.SetLimit(runtime.NumCPU() / 2) + workers.SetLimit(4 * runtime.NumCPU() / 5) // Aggressively run the prefetching // Iterate over and process the individual transactions for i, tx := range block.Transactions() {