This commit is contained in:
Jared Wasinger 2024-02-19 21:10:13 -08:00
parent 100d2e34e1
commit d6d48f3713
8 changed files with 31 additions and 99 deletions

View file

@ -38,7 +38,6 @@ var (
type triePrefetcher struct {
db Database // Database to fetch trie nodes through
root common.Hash // Root hash of the account trie for metrics
fetches map[string]Trie // Partially or fully fetched tries. Only populated for inactive copies.
fetchers map[string]*subfetcher // Subfetchers for each trie
deliveryMissMeter metrics.Meter
@ -71,16 +70,14 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre
}
return p
}
func (p *triePrefetcher) wait() {
for _, fetcher := range p.fetchers {
fetcher.wait()
}
}
// close iterates over all the subfetchers, aborts any that were left spinning
// and reports the stats to the metrics subsystem.
// close iterates over all the subfetchers, waits on any that were left spinning
// and reports the stats to the metrics subsystem. close should not be called
// more than once on a triePrefetcher instance.
func (p *triePrefetcher) close() {
for _, fetcher := range p.fetchers {
fetcher.wait() // safe to do multiple times
if metrics.Enabled {
if fetcher.root == p.root {
p.accountLoadMeter.Mark(int64(len(fetcher.seen)))
@ -103,34 +100,10 @@ func (p *triePrefetcher) close() {
}
}
}
// Clear out all fetchers (will crash on a second call, deliberate)
p.fetchers = nil
}
// copy creates a deep-but-inactive copy of the trie prefetcher. Any trie data
// already loaded will be copied over, but no goroutines will be started. This
// is mostly used in the miner which creates a copy of it's actively mutated
// state to be sealed while it may further mutate the state.
func (p *triePrefetcher) copy() *triePrefetcher {
copy := &triePrefetcher{
db: p.db,
root: p.root,
fetches: make(map[string]Trie), // Active prefetchers use the fetches map
deliveryMissMeter: p.deliveryMissMeter,
accountLoadMeter: p.accountLoadMeter,
accountDupMeter: p.accountDupMeter,
accountSkipMeter: p.accountSkipMeter,
accountWasteMeter: p.accountWasteMeter,
storageLoadMeter: p.storageLoadMeter,
storageDupMeter: p.storageDupMeter,
storageSkipMeter: p.storageSkipMeter,
storageWasteMeter: p.storageWasteMeter,
}
return copy
}
// prefetch schedules a batch of trie items to prefetch.
//
// prefetch is called from two locations:
// 1. Finalize of the state-objects storage roots. This happens at the end
// of every transaction, meaning that if several transactions touches
@ -138,12 +111,6 @@ func (p *triePrefetcher) copy() *triePrefetcher {
// repeated.
// 2. Finalize of the main account trie. This happens only once per block.
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) {
// If the prefetcher is an inactive one, bail out
if p.fetches != nil {
return
}
// Active fetcher, schedule the retrievals
id := p.trieID(owner, root)
fetcher := p.fetchers[id]
if fetcher == nil {
@ -156,18 +123,8 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm
// trie returns the trie matching the root hash, or nil if the prefetcher doesn't
// have it.
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
// If the prefetcher is inactive, return from existing deep copies
id := p.trieID(owner, root)
if p.fetches != nil {
trie := p.fetches[id]
if trie == nil {
p.deliveryMissMeter.Mark(1)
return nil
}
return p.db.CopyTrie(trie)
}
// Otherwise the prefetcher is active, bail if no trie was prefetched for this root
fetcher := p.fetchers[id]
// Bail if no trie was prefetched for this root
fetcher := p.fetchers[p.trieID(owner, root)]
if fetcher == nil {
p.deliveryMissMeter.Mark(1)
return nil

View file

@ -319,18 +319,6 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
return nil
}
// EncodeRLPWithZeroRoot encodes a block (with header state root set to 0x00...0) to RLP
func (b *Block) EncodeRLPWithZeroRoot(w io.Writer) error {
old := b.header.Root
b.header.Root = common.Hash{}
err := b.EncodeRLP(w)
b.header.Root = old
if err != nil {
return err
}
return nil
}
// EncodeRLP serializes a block as RLP.
func (b *Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &extblock{

View file

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"math"
)
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
@ -365,7 +366,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
)
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = 0xffffffffffffffff
uint64CodeOffset = math.MaxUint64
}
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
@ -383,7 +384,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
)
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
if overflow {
uint64CodeOffset = 0xffffffffffffffff
uint64CodeOffset = math.MaxUint64
}
addr := common.Address(a.Bytes20())
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
@ -428,8 +429,8 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
if interpreter.evm.StateDB.Empty(address) {
slot.Clear()
} else {
_ = interpreter.evm.StateDB.GetCode(address) // ensure the account leaf is fetched and included in the witness
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
_ = interpreter.evm.StateDB.GetCode(address) // ensure the account leaf is fetched and included in the witness
witness.AddCodeHash(interpreter.evm.StateDB.GetCodeHash(address))
}
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())

View file

@ -20,8 +20,6 @@ import (
"context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"os"
"time"
"github.com/ethereum/go-ethereum/core"
@ -449,7 +447,9 @@ func (api *DebugAPI) GetTrieFlushInterval() (string, error) {
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
}
func BuildProof(number uint64, bc *core.BlockChain) ([]byte, error) {
// BuildStatelessProof executes a block, collecting the accessed pre-state into
// a Witness. The RLP-encoded witness is returned.
func BuildStatelessProof(number uint64, bc *core.BlockChain) ([]byte, error) {
if number == 0 {
panic("cannot build genesis block proof")
}
@ -459,19 +459,8 @@ func BuildProof(number uint64, bc *core.BlockChain) ([]byte, error) {
return nil, err
}
db.EnableWitnessRecording()
db.StartPrefetcher("apidebug")
db.StartPrefetcher("debug_buildStatelessProof")
block := bc.GetBlockByNumber(number)
logconfig := &logger.Config{
EnableMemory: false,
DisableStack: false,
DisableStorage: false,
EnableReturnData: true,
Debug: true,
}
tracer := logger.NewJSONLogger(logconfig, os.Stdout)
_ = tracer
stateProcessor := core.NewStateProcessor(bc.Config(), bc, bc.Engine())
_, _, _, err = stateProcessor.Process(block, db, vm.Config{})
if err != nil {
@ -489,6 +478,8 @@ func BuildProof(number uint64, bc *core.BlockChain) ([]byte, error) {
return enc, nil
}
func (api *DebugAPI) BuildProof(num rpc.BlockNumber) ([]byte, error) {
return BuildProof(uint64(num), api.eth.blockchain)
// BuildStatelessProof executes a block, collecting the accessed pre-state into
// a Witness. The RLP-encoded witness is returned.
func (api *DebugAPI) BuildStatelessProof(num rpc.BlockNumber) ([]byte, error) {
return BuildStatelessProof(uint64(num), api.eth.blockchain)
}

View file

@ -502,8 +502,8 @@ web3._extend({
params: 0
}),
new web3._extend.Method({
name: 'buildProof',
call: 'debug_buildProof',
name: 'buildStatelessProof',
call: 'debug_buildStatelessProof',
params: 1
}),
],

View file

@ -59,8 +59,8 @@ func (t *BlockTest) UnmarshalJSON(in []byte) error {
type btJSON struct {
Blocks []btBlock `json:"blocks"`
Genesis btHeader `json:"genesisBlockHeader"`
Pre core.GenesisAlloc `json:"pre"`
Post core.GenesisAlloc `json:"postState"`
Pre types.GenesisAlloc `json:"pre"`
Post types.GenesisAlloc `json:"postState"`
BestBlock common.UnprefixedHash `json:"lastblockhash"`
Network string `json:"network"`
SealEngine string `json:"sealEngine"`
@ -155,7 +155,7 @@ func (t *BlockTest) run(stateless bool, snapshotter bool, scheme string, tracer
// Wrap the original engine within the beacon-engine
engine := beacon.New(ethash.NewFaker())
cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme, Preimages: true, TrieDirtyDisabled: true}
cache := &core.CacheConfig{TrieCleanLimit: 0, StateScheme: scheme, Preimages: true}
if snapshotter {
cache.SnapshotLimit = 1
cache.SnapshotWait = true
@ -197,7 +197,7 @@ func (t *BlockTest) run(stateless bool, snapshotter bool, scheme string, tracer
if stateless {
for _, blk := range validBlocks {
proof, err := eth.BuildProof(blk.BlockHeader.Number.Uint64(), chain)
proof, err := eth.BuildStatelessProof(blk.BlockHeader.Number.Uint64(), chain)
if err != nil {
return fmt.Errorf("failed to build proof: %v", err)
}

View file

@ -107,7 +107,7 @@ func NewEmpty(db database.Database) *Trie {
}
// MustNodeIterator is a wrapper of NodeIterator and will omit any encountered
// error but just printg out an error message.
// error but just print out an error message.
func (t *Trie) MustNodeIterator(start []byte) NodeIterator {
it, err := t.NodeIterator(start)
if err != nil {
@ -581,10 +581,6 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) {
return n, nil
}
// TODO: for resolveAndTrack, differentiate between hash node resolve failure in stateless
// vs normal execution. In normal mode, it represents an error with database
// consistency. In stateless execution, it means that the witness is incomplete.
// resolveAndTrack loads node from the underlying store with the given node hash
// and path prefix and also tracks the loaded node blob in tracer treated as the
// node's original value. The rlp-encoded blob is preferred to be loaded from
@ -606,10 +602,14 @@ func (t *Trie) Hash() common.Hash {
return common.BytesToHash(hash.(hashNode))
}
// AccessList returns a map of path->blob containing all trie nodes that have
// been accessed.
func (t *Trie) AccessList() map[string][]byte {
return t.tracer.accessList
}
// CommitAndObtainAccessList does the same thing as Commit, but also returns
// the access list of the trie.
func (t *Trie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
accessList := t.tracer.accessList
// Commit will reset the tracer accessList, so after this

View file

@ -45,11 +45,6 @@ var HashDefaults = &Config{
HashDB: hashdb.Defaults,
}
var PathDefaults = &Config{
Preimages: false,
PathDB: pathdb.Defaults,
}
// backend defines the methods needed to access/update trie nodes in different
// state scheme.
type backend interface {