From f6f8616006a9a1c764f8828ca0f4756ca9a25748 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 8 Nov 2021 18:21:44 +0100 Subject: [PATCH] simplify code by removing all stateless references (#25) --- core/blockchain.go | 12 +---- core/state/statedb.go | 117 ---------------------------------------- core/state_processor.go | 37 ------------- core/types.go | 3 -- 4 files changed, 1 insertion(+), 168 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index f7eb3120ee25..86ab4a4a5d8b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1831,17 +1831,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er receipts types.Receipts logs []*types.Log ) - if len(block.Header().VerkleProof) == 0 { - receipts, logs, _, usedGas, err = bc.processor.Process(block, statedb, bc.vmConfig) - } else { - var leaves map[common.Hash]common.Hash - leaves, err = trie.DeserializeAndVerifyVerkleProof(block.Header().VerkleProof) - if err != nil { - return it.index, err - } - statedb.SetStateless(leaves) - receipts, logs, usedGas, err = bc.processor.ProcessStateless(block, statedb, bc.vmConfig, leaves) - } + receipts, logs, _, usedGas, err = bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) diff --git a/core/state/statedb.go b/core/state/statedb.go index 94263e95df4d..54996805e24f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -102,9 +102,6 @@ type StateDB struct { // Per-transaction access list accessList *accessList - // Stateless locations for this block - stateless map[common.Hash]common.Hash - // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. journal *journal @@ -423,12 +420,6 @@ func (s *StateDB) SetCode(addr common.Address, code []byte) { } } -// SetStateless sets the vales recovered from the execution of a stateless -// block. -func (s *StateDB) SetStateless(leaves map[common.Hash]common.Hash) { - s.stateless = leaves -} - func (s *StateDB) SetState(addr common.Address, key, value common.Hash) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { @@ -470,46 +461,6 @@ func (s *StateDB) Suicide(addr common.Address) bool { // Setting, updating & deleting state object methods. // -func (s *StateDB) updateStatelessStateObject(obj *stateObject) { - addr := obj.Address() - - var ( - ok bool - n common.Hash - v common.Hash - b common.Hash - cs common.Hash - ch common.Hash - ) - - versionKey := common.BytesToHash(trieUtils.GetTreeKeyVersion(addr[:])) - if v, ok = s.stateless[versionKey]; ok { - nonceKey := common.BytesToHash(trieUtils.GetTreeKeyNonce(addr[:])) - if n, ok = s.stateless[nonceKey]; ok { - balanceKey := common.BytesToHash(trieUtils.GetTreeKeyBalance(addr[:])) - if b, ok = s.stateless[balanceKey]; ok { - codeHashKey := common.BytesToHash(trieUtils.GetTreeKeyCodeKeccak(addr[:])) - if _, ok = s.stateless[codeHashKey]; ok { - v[0] = byte(0) - binary.BigEndian.PutUint64(n[:], obj.data.Nonce) - copy(ch[:], obj.data.CodeHash[:]) - copy(b[:], obj.data.Balance.Bytes()) - binary.BigEndian.PutUint64(cs[:], uint64(len(obj.code))) - - // TODO(@gballet) stateless tree update - // i.e. perform a "delta" update on all - // commitments. go-verkle currently has - // no support for these. - } - } - } - } - - if !ok { - s.setError(fmt.Errorf("updateStatelessStateObject (%x) missing", addr[:])) - } -} - // updateStateObject writes the given object to the trie. func (s *StateDB) updateStateObject(obj *stateObject) { // Track the amount of time wasted on updating the account from the trie @@ -519,12 +470,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) { // Encode the account and update the account trie addr := obj.Address() - // bypass the snapshot and writing to tree if in stateless mode - if s.stateless != nil { - s.updateStatelessStateObject(obj) - return - } - if err := s.trie.TryUpdateAccount(addr[:], &obj.data); err != nil { s.setError(fmt.Errorf("updateStateObject (%x) error: %w", addr[:], err)) } @@ -545,21 +490,12 @@ func (s *StateDB) updateStateObject(obj *stateObject) { } } -func (s *StateDB) deleteStatelessStateObject(obj *stateObject) { - // unsupported - panic("not currently supported") -} - // deleteStateObject removes the given object from the state trie. func (s *StateDB) deleteStateObject(obj *stateObject) { // Track the amount of time wasted on deleting the account from the trie if metrics.EnabledExpensive { defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) } - if s.stateless != nil { - s.deleteStatelessStateObject(obj) - return - } // Delete the account from the trie if !s.trie.IsVerkle() { @@ -586,48 +522,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return nil } -func (s *StateDB) getStatelessDeletedStateObject(addr common.Address) *stateObject { - // Check that it is present in the witness, if running - // in stateless execution mode. - chunk := trieUtils.GetTreeKeyNonce(addr[:]) - nb, ok := s.stateless[common.BytesToHash(chunk)] - if !ok { - log.Error("Failed to decode state object", "addr", addr) - s.setError(fmt.Errorf("could not find nonce chunk in proof: %x", chunk)) - // TODO(gballet) remove after debug, and check the issue is found - panic("inivalid chunk") - return nil - } - chunk = trieUtils.GetTreeKeyBalance(addr[:]) - bb, ok := s.stateless[common.BytesToHash(chunk)] - if !ok { - log.Error("Failed to decode state object", "addr", addr) - s.setError(fmt.Errorf("could not find balance chunk in proof: %x", chunk)) - // TODO(gballet) remove after debug, and check the issue is found - panic("inivalid chunk") - return nil - } - chunk = trieUtils.GetTreeKeyCodeKeccak(addr[:]) - cb, ok := s.stateless[common.BytesToHash(chunk)] - if !ok { - // Assume that this is an externally-owned account, and that - // the code has not been accessed. - // TODO(gballet) write this down, just like deletions, so - // that an error can be triggered if trying to access the - // account code. - copy(cb[:], emptyCodeHash) - } - data := &types.StateAccount{ - Nonce: binary.BigEndian.Uint64(nb[:8]), - Balance: big.NewInt(0).SetBytes(bb[:]), - CodeHash: cb[:], - } - // Insert into the live set - obj := newObject(s, addr, *data) - s.setStateObject(obj) - return obj -} - // getDeletedStateObject is similar to getStateObject, but instead of returning // nil for a deleted state object, it returns the actual object with the deleted // flag set. This is needed by the state journal to revert to the correct s- @@ -642,10 +536,6 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { data *types.StateAccount err error ) - // if executing statelessly, bypass the snapshot and the db. - if s.stateless != nil { - return s.getStatelessDeletedStateObject(addr) - } if s.snap != nil { if metrics.EnabledExpensive { defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now()) @@ -852,13 +742,6 @@ func (s *StateDB) Copy() *StateDB { // to not blow up if we ever decide copy it in the middle of a transaction state.accessList = s.accessList.Copy() - if s.stateless != nil { - state.stateless = make(map[common.Hash]common.Hash, len(s.stateless)) - for addr, value := range s.stateless { - state.stateless[addr] = value - } - } - // If there's a prefetcher running, make an inactive copy of it that can // only access data but does not actively preload (since the user will not // know that they need to explicitly terminate an active copy). diff --git a/core/state_processor.go b/core/state_processor.go index 6d77fce3d06f..7219fed22dda 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -94,43 +94,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, accesses, *usedGas, nil } -func (p *StateProcessor) ProcessStateless(block *types.Block, statedb *state.StateDB, cfg vm.Config, leaves map[common.Hash]common.Hash) (types.Receipts, []*types.Log, uint64, error) { - var ( - receipts types.Receipts - usedGas = new(uint64) - header = block.Header() - blockHash = block.Hash() - blockNumber = block.Number() - allLogs []*types.Log - gp = new(GasPool).AddGas(block.GasLimit()) - ) - // Mutate the block and state according to any hard-fork specs - if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { - misc.ApplyDAOHardFork(statedb) - } - blockContext := NewEVMBlockContext(header, p.bc, nil) - blockContext.StatelessAccesses = leaves - vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) - // Iterate over and process the individual transactions - for i, tx := range block.Transactions() { - msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) - if err != nil { - return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) - } - statedb.Prepare(tx.Hash(), i) - receipt, _, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) - if err != nil { - return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) - } - receipts = append(receipts, receipt) - allLogs = append(allLogs, receipt.Logs...) - } - // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), nil) - - return receipts, allLogs, *usedGas, nil -} - func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, *types.AccessWitness, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) diff --git a/core/types.go b/core/types.go index 6ec0a4ac17c3..6534007a8c12 100644 --- a/core/types.go +++ b/core/types.go @@ -17,7 +17,6 @@ package core import ( - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -49,6 +48,4 @@ type Processor interface { // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *types.AccessWitness, uint64, error) - - ProcessStateless(block *types.Block, statedb *state.StateDB, cfg vm.Config, accesses map[common.Hash]common.Hash) (types.Receipts, []*types.Log, uint64, error) }