diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b7885608bc..fab83ac929 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -156,6 +156,7 @@ var ( utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, + utils.DebugCollectWitnessFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ecf6acc186..81e40c1b41 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -604,6 +604,11 @@ var ( Usage: "Disables db compaction after import", Category: flags.LoggingCategory, } + DebugCollectWitnessFlag = &cli.BoolFlag{ + Name: "collectwitnesses", + Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.", + Category: flags.MiscCategory, + } // MISC settings SyncTargetFlag = &cli.StringFlag{ @@ -2204,6 +2209,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh vmcfg.Tracer = t } } + vmcfg.EnableWitnessCollection = ctx.Bool(DebugCollectWitnessFlag.Name) // Disable transaction indexing/unindexing by default. chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index 7c8ab3abc4..a9047619c1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - statedb.StartPrefetcher("chain") + statedb.StartPrefetcher("chain", bc.vmConfig.EnableWitnessCollection) } activeState = statedb diff --git a/core/state/state_object.go b/core/state/state_object.go index b7a215bd17..bc5817ea51 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -212,6 +212,9 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { } value.SetBytes(content) } + if s.data.Root != types.EmptyRootHash { + s.db.prefetcher.prefetchWitness(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}) + } } // If the snapshot is unavailable or reading from it fails, load from the database. if s.db.snap == nil || err != nil { diff --git a/core/state/statedb.go b/core/state/statedb.go index 61e76cdd77..160a2a0782 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -200,14 +200,14 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string) { +func (s *StateDB) StartPrefetcher(namespace string, collectWitnesses bool) { if s.prefetcher != nil { s.prefetcher.terminate(false) s.prefetcher.report() s.prefetcher = nil } if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, collectWitnesses) // With the switch to the Proof-of-Stake consensus algorithm, block production // rewards are now handled at the consensus layer. Consequently, a block may @@ -587,6 +587,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { if acc == nil { return nil } + s.prefetcher.prefetchWitness(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}) data = &types.StateAccount{ Nonce: acc.Nonce, Balance: acc.Balance, diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 5e5afbbecc..07d13623b6 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -40,10 +40,11 @@ var ( // // Note, the prefetcher's API is not thread safe. type triePrefetcher struct { - db Database // Database to fetch trie nodes through - root common.Hash // Root hash of the account trie for metrics - fetchers map[string]*subfetcher // Subfetchers for each trie - term chan struct{} // Channel to signal interruption + db Database // Database to fetch trie nodes through + root common.Hash // Root hash of the account trie for metrics + fetchers map[string]*subfetcher // Subfetchers for each trie + term chan struct{} // Channel to signal interruption + collectWitnesses bool // whether to allow prefetch calls for witness collection deliveryMissMeter metrics.Meter accountLoadMeter metrics.Meter @@ -54,13 +55,14 @@ type triePrefetcher struct { storageWasteMeter metrics.Meter } -func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { +func newTriePrefetcher(db Database, root common.Hash, namespace string, collectWitnesses bool) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace return &triePrefetcher{ - db: db, - root: root, - fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map - term: make(chan struct{}), + db: db, + root: root, + fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map + term: make(chan struct{}), + collectWitnesses: collectWitnesses, deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), @@ -142,6 +144,14 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm return fetcher.schedule(keys) } +// prefetchWitness calls prefetch if witness collection is enabled. +func (p *triePrefetcher) prefetchWitness(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { + if p.collectWitnesses { + return p.prefetch(owner, root, addr, keys) + } + return nil +} + // trie returns the trie matching the root hash, blocking until the fetcher of // the given trie terminates. If no fetcher exists for the request, nil will be // returned. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 66a20f434e..2b1ea38483 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -33,6 +33,7 @@ type Config struct { NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled + EnableWitnessCollection bool // true if witness collection is enabled } // ScopeContext contains the things that are per-call, such as stack and memory,