From af087d05817d7b00282ca9bf76dfa9051ee10096 Mon Sep 17 00:00:00 2001 From: Po Date: Tue, 5 Aug 2025 07:28:48 +0200 Subject: [PATCH] fix: bal prefetcher empty account bug caused by merging 7702 code --- core/blockchain_insert.go | 1 - core/paralle_state_provider.go | 2 +- core/parallel_state_processor.go | 34 ++++++++++-------- core/state/reader.go | 62 ++------------------------------ core/state/statedb.go | 35 +++++++++--------- core/state/statedb_readerbal.go | 10 +----- 6 files changed, 43 insertions(+), 101 deletions(-) diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 05235b4491..7edd674f17 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -47,7 +47,6 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn mgasps = float64(st.usedGas) * 1000 / float64(elapsed) ) // Update the Mgas per second gauge - chainMgaspsGauge.Update(int64(mgasps)) mgaspsHist.Update(int64(mgasps)) // If we're at the last block of the batch or report period reached, log diff --git a/core/paralle_state_provider.go b/core/paralle_state_provider.go index 50566b37a9..b8e3fd0cbb 100644 --- a/core/paralle_state_provider.go +++ b/core/paralle_state_provider.go @@ -52,7 +52,7 @@ func (s *SequentialPrestateProvider) PrestateAtIndex(i int) (*state.StateDB, err } statedb.SetTxContext(tx.Hash(), i) - _, err = ApplyTransactionWithEVM(msg, s.gp, statedb, blockNumber, blockHash, tx, s.usedGas, s.evm) + _, err = ApplyTransactionWithEVM(msg, s.gp, statedb, blockNumber, blockHash, s.block.Time(), tx, s.usedGas, s.evm) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index 34f34fe20c..2b76ce468e 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -197,7 +197,7 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st } // todo: handle gp race gpcp := *gp - receipt, entries, err := ApplyTransactionWithParallelEVM(msg, &gpcp, cleanStatedb, blockNumber, blockHash, tx, usedGas, evm) + receipt, entries, err := ApplyTransactionWithParallelEVM(msg, &gpcp, cleanStatedb, blockNumber, blockHash, block.Time(), tx, usedGas, evm) if err != nil { return err } @@ -234,8 +234,7 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st } // Read requests if Prague is enabled. - // commented out EIP-7002, EIP-7251 and p.chain.engine.Finalize for now, since statedb might cause concurrent map writes (journal.go:211) when postState = statedb.Copy() - // evm := vm.NewEVM(context, statedb, p.config, cfg) + var requests [][]byte if p.config.IsPrague(block.Number(), block.Time()) { requests = [][]byte{} @@ -243,18 +242,25 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil { return nil, err } - // // EIP-7002 - // if err := ProcessWithdrawalQueue(&requests, evm); err != nil { - // return nil, err - // } - // // EIP-7251 - // if err := ProcessConsolidationQueue(&requests, evm); err != nil { - // return nil, err - // } + // Commented out EIP-7002, EIP-7251 and p.chain.engine.Finalize for now, since statedb might cause concurrent map writes (journal.go:211) when postState = statedb.Copy() + if preStateType == SeqPreState { + evm := vm.NewEVM(context, statedb, p.config, cfg) + // // EIP-7002 + if err := ProcessWithdrawalQueue(&requests, evm); err != nil { + return nil, err + } + // // EIP-7251 + if err := ProcessConsolidationQueue(&requests, evm); err != nil { + return nil, err + } + } + } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - // p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) + if preStateType == SeqPreState { + p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) + } return &ProcessResult{ Receipts: receipts, @@ -264,7 +270,7 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st }, nil } -func ApplyTransactionWithParallelEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, entries []state.JournalEntry, err error) { +func ApplyTransactionWithParallelEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, entries []state.JournalEntry, err error) { if hooks := evm.Config.Tracer; hooks != nil { if hooks.OnTxStart != nil { hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) @@ -295,5 +301,5 @@ func ApplyTransactionWithParallelEVM(msg *Message, gp *GasPool, statedb *state.S statedb.AccessEvents().Merge(evm.AccessEvents) } - return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), entries, nil + return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, *usedGas, root), entries, nil } diff --git a/core/state/reader.go b/core/state/reader.go index 28dc92da18..fd786e2f89 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -73,9 +73,6 @@ type StateReader interface { // - Returns an error only if an unexpected issue occurs // - The returned storage slot is safe to modify after the call Storage(addr common.Address, slot common.Hash) (common.Hash, error) - - AccountBAL(addr common.Address) (*types.StateAccount, error) - StorageBAL(addr common.Address, slot common.Hash) (common.Hash, error) } // Reader defines the interface for accessing accounts, storage slots and contract @@ -191,10 +188,6 @@ func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) { return acct, nil } -func (r *flatReader) AccountBAL(addr common.Address) (*types.StateAccount, error) { - return r.Account(addr) -} - // Storage implements StateReader, retrieving the storage slot specified by the // address and slot key. // @@ -223,10 +216,6 @@ func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, return value, nil } -func (r *flatReader) StorageBAL(addr common.Address, key common.Hash) (common.Hash, error) { - return r.Storage(addr, key) -} - // trieReader implements the StateReader interface, providing functions to access // state from the referenced trie. // @@ -293,14 +282,6 @@ func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) { return r.account(addr) } -func (r *trieReader) AccountBAL(addr common.Address) (*types.StateAccount, error) { - account, err := r.mainTrie.GetAccount(addr) - if err != nil { - return nil, err - } - return account, nil -} - // Storage implements StateReader, retrieving the storage slot specified by the // address and slot key. // @@ -347,10 +328,6 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, return value, nil } -func (r *trieReader) StorageBAL(addr common.Address, key common.Hash) (common.Hash, error) { - return r.Storage(addr, key) -} - // multiStateReader is the aggregation of a list of StateReader interface, // providing state access by leveraging all readers. The checking priority // is determined by the position in the reader list. @@ -391,24 +368,6 @@ func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, er return nil, errors.Join(errs...) } -func (r *multiStateReader) AccountBAL(addr common.Address) (*types.StateAccount, error) { - var errs []error - for _, reader := range r.readers { - switch reader.(type) { - case *flatReader: - { - acct, err := reader.AccountBAL(addr) - if err == nil { - return acct, nil - } - errs = append(errs, err) - } - } - } - errs = append(errs, errors.New("no flatReader")) - return nil, errors.Join(errs...) -} - // Storage implementing StateReader interface, retrieving the storage slot // associated with a particular account address and slot key. // @@ -427,24 +386,6 @@ func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (commo return common.Hash{}, errors.Join(errs...) } -func (r *multiStateReader) StorageBAL(addr common.Address, slot common.Hash) (common.Hash, error) { - var errs []error - for _, reader := range r.readers { - switch reader.(type) { - case *flatReader: - { - slot, err := reader.Storage(addr, slot) - if err == nil { - return slot, nil - } - errs = append(errs, err) - } - } - } - errs = append(errs, errors.New("no flatReader")) - return common.Hash{}, errors.Join(errs...) -} - // reader is the wrapper of ContractCodeReader and StateReader interface. type reader struct { ContractCodeReader @@ -690,6 +631,9 @@ func (r *readerWithBAL) Account(addr common.Address) (*types.StateAccount, error acct, err := r.Reader.Account(addr) if acct == nil || err != nil { // acct is nil, just return the postAcct + if acctVal.Nonce == 0 && acctVal.Balance == nil && len(acctVal.Code) == 0 { + return nil, fmt.Errorf("account not exist") + } return &types.StateAccount{ Nonce: acctVal.Nonce, Balance: acctVal.Balance, diff --git a/core/state/statedb.go b/core/state/statedb.go index 3093d06c17..b37a980a2c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -249,8 +249,13 @@ func New(root common.Hash, db Database) (*StateDB, error) { // NewWithReader creates a new state for the specified state root. Unlike New, // this function accepts an additional Reader which is bound to the given root. func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, error) { + tr, err := db.OpenTrie(root) + if err != nil { + return nil, err + } sdb := &StateDB{ db: db, + trie: tr, originalRoot: root, reader: reader, stateObjects: make(map[common.Address]*stateObject), @@ -373,17 +378,16 @@ func (s *StateDB) prefetchBalPreblockKeys() { lenMaxSlots += len(acl.StorageKeys) workers.Go(func() error { - acctBal, err := s.reader.AccountBAL(addr) + acctBal, err := s.reader.Account(addr) var obj *stateObject if err != nil { log.Error("fail to fetch account from BALs:", addr) - acct, err := s.reader.Account(addr) - if err != nil { - panic("fail to fetch account from BALs") - } - obj = newObject(s, addr, acct) + panic("fail to fetch account from BALs") } else { - obj = newObject(s, addr, acctBal) + // If obj is nil, we shouldn't newObject, it will cause invalid gas used error. Because 7702 will use Exist(addr) to decide where an account exists, which should be false if account is nil, but if we newObject it'll be true. + if acctBal != nil { + obj = newObject(s, addr, acctBal) + } } accounts <- obj return nil @@ -393,8 +397,10 @@ func (s *StateDB) prefetchBalPreblockKeys() { for range len(preBal) { obj := <-accounts - // must set it first to avoid accounts read later in storageBAL fetching - s.setStateObject(obj) + // must set it first to avoid accounts read later in storage fetching + if obj != nil { + s.setStateObject(obj) + } } close(accounts) @@ -407,7 +413,7 @@ func (s *StateDB) prefetchBalPreblockKeys() { obj := s.stateObjects[addr] - if obj.origin == nil { + if obj == nil || obj.origin == nil { continue } @@ -415,16 +421,11 @@ func (s *StateDB) prefetchBalPreblockKeys() { for _, key := range keys { workers.Go(func() error { - val, err := s.reader.StorageBAL(addr, key) + val, err := s.reader.Storage(addr, key) kv := &StorageKV{&addr, &key, &val} if err != nil { log.Error("fail to fetch storage from BALs:", addr, key) - // It's not safe to concurrent read from trie with StorageBAL, so we use the locked version Storage as fallback - val, err := s.reader.Storage(addr, key) - if err != nil { - panic("fail to fetch storage from BALs") - } - kv.val = &val + panic("fail to fetch storage from BALs") } storages <- kv diff --git a/core/state/statedb_readerbal.go b/core/state/statedb_readerbal.go index d35d576fc4..37845e918f 100644 --- a/core/state/statedb_readerbal.go +++ b/core/state/statedb_readerbal.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -// All states must has been cachae to statedb. +// All states must has been cached to statedb. func (s *StateDB) Account(addr common.Address) (*types.StateAccount, error) { // s.getStateObject() shouldn't be used, cause when acct is nil, it'll load account from DB and result concurrent map writes for accts obj := s.stateObjects[addr] @@ -34,11 +34,3 @@ func (s *StateDB) Storage(addr common.Address, slot common.Hash) (common.Hash, e } return common.Hash{}, nil } - -func (s *StateDB) AccountBAL(addr common.Address) (*types.StateAccount, error) { - panic("AccountBAL not implemented for statedb") -} - -func (s *StateDB) StorageBAL(addr common.Address, slot common.Hash) (common.Hash, error) { - panic("StorageBAL not implemented for statedb") -}