From 6e8a54fbb4735b8b7bd215de1428380f4fdf75d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 16 Oct 2024 21:08:11 +0300 Subject: [PATCH] core/exex: expose account and storage trie iterators --- core/exex/exex/adapter_chain.go | 4 ++- core/exex/exex/adapter_state.go | 44 ++++++++++++++++++++++++++++++--- core/exex/interface_chain.go | 3 ++- core/exex/interface_state.go | 35 ++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/core/exex/exex/adapter_chain.go b/core/exex/exex/adapter_chain.go index feb1044bd5..5b1005cf06 100644 --- a/core/exex/exex/adapter_chain.go +++ b/core/exex/exex/adapter_chain.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/exex" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" ) @@ -32,6 +33,7 @@ type gethChain interface { GetHeaderByNumber(number uint64) *types.Header GetBlockByNumber(number uint64) *types.Block StateAt(root common.Hash) (*state.StateDB, error) + Snapshots() *snapshot.Tree GetReceiptsByNumber(number uint64) types.Receipts } @@ -75,7 +77,7 @@ func (a *chainAdapter) State(root common.Hash) exex.State { if err != nil { return nil } - return wrapState(state) + return wrapState(root, state, a.chain.Snapshots()) } // Receipts retrieves a set of receits belonging to all transactions within diff --git a/core/exex/exex/adapter_state.go b/core/exex/exex/adapter_state.go index 9e94a99f38..0e31707fde 100644 --- a/core/exex/exex/adapter_state.go +++ b/core/exex/exex/adapter_state.go @@ -19,6 +19,7 @@ package exex import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/exex" + "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/vm" "github.com/holiman/uint256" ) @@ -26,12 +27,18 @@ import ( // stateAdapter is an adapter to convert Geth's internal state db (unstable // and legacy API) into the exex state interface (stable API). type stateAdapter struct { - state vm.StateDB + root common.Hash // Root hash of the state being accessed + state vm.StateDB // State database backed by a trie + snaps *snapshot.Tree // State database backed by a snapshot } // wrapState wraps a Geth internal state object into an exex stable API. -func wrapState(state vm.StateDB) exex.State { - return &stateAdapter{state: state} +func wrapState(root common.Hash, state vm.StateDB, snaps *snapshot.Tree) exex.State { + return &stateAdapter{ + root: root, + state: state, + snaps: snaps, + } } // Balance retrieves the balance of the given account, or 0 if the account is @@ -57,3 +64,34 @@ func (a *stateAdapter) Code(addr common.Address) []byte { func (a *stateAdapter) Storage(addr common.Address, slot common.Hash) common.Hash { return a.state.GetState(addr, slot) } + +// AccountIterator retrieves an iterator to walk across all the known accounts in +// the Ethereum state trie from a starting position. +func (a *stateAdapter) AccountIterator(seek common.Hash) snapshot.AccountIterator { + if a.snaps == nil { + return nil + } + it, err := a.snaps.AccountIterator(a.root, seek) + if err != nil { + return nil + } + return it +} + +// StorageIterator retrieves an iterator to walk across all the known storage slots +// the Ethereum state trie of a given account, from a starting position. +// +// The iteration order is the Merkle-Patricia order (storage slot hash alphabetically). +// +// Note, the account is the hash of the address. This is due to the AccountIterator +// also walking the state in hash order, not address order. +func (a *stateAdapter) StorageIterator(account common.Hash, seek common.Hash) snapshot.StorageIterator { + if a.snaps == nil { + return nil + } + it, err := a.snaps.StorageIterator(a.root, account, seek) + if err != nil { + return nil + } + return it +} diff --git a/core/exex/interface_chain.go b/core/exex/interface_chain.go index e09fa54160..b855c654a3 100644 --- a/core/exex/interface_chain.go +++ b/core/exex/interface_chain.go @@ -37,7 +37,8 @@ type Chain interface { // chain. Blocks on side-chains are not exposed by the Chain interface. Block(number uint64) *types.Block - // State retrieves a state accessor at a given root hash. + // State retrieves a state accessor at a given root hash, or nil if the state + // associated with the given block has already been pruned. State(root common.Hash) State // Receipts retrieves a set of receipts belonging to all transactions within diff --git a/core/exex/interface_state.go b/core/exex/interface_state.go index d7823093d5..5a511dfc71 100644 --- a/core/exex/interface_state.go +++ b/core/exex/interface_state.go @@ -1,7 +1,24 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + package exex import ( "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/holiman/uint256" ) @@ -22,4 +39,22 @@ type State interface { // Storage retrieves the value associated with a specific storage slot key // within a specific account. Storage(addr common.Address, slot common.Hash) common.Hash + + // AccountIterator retrieves an iterator to walk across all the known accounts + // in the Ethereum state trie from a starting position, or returns nil if the + // requested state is unavailable in snapshot (accelerated access) form. + // + // Iteration is in Merkle-Patricia order (address hash alphabetically). + AccountIterator(seek common.Hash) snapshot.AccountIterator + + // StorageIterator retrieves an iterator to walk across all the known storage + // slots the Ethereum state trie of a given account, from a starting position, + // or returns nil if the requested state is unavailable in snapshot (accelerated + // access) form. + // + // Iteration is in Merkle-Patricia order (storage slot hash alphabetically). + // + // The account is the hash of the address. This is due to the AccountIterator + // also walking the state in hash order, not address order. + StorageIterator(account common.Hash, seek common.Hash) snapshot.StorageIterator }