mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
more
This commit is contained in:
parent
100d2e34e1
commit
d6d48f3713
8 changed files with 31 additions and 99 deletions
|
|
@ -38,7 +38,6 @@ var (
|
||||||
type triePrefetcher struct {
|
type triePrefetcher struct {
|
||||||
db Database // Database to fetch trie nodes through
|
db Database // Database to fetch trie nodes through
|
||||||
root common.Hash // Root hash of the account trie for metrics
|
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
|
fetchers map[string]*subfetcher // Subfetchers for each trie
|
||||||
|
|
||||||
deliveryMissMeter metrics.Meter
|
deliveryMissMeter metrics.Meter
|
||||||
|
|
@ -71,16 +70,14 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre
|
||||||
}
|
}
|
||||||
return p
|
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
|
// close iterates over all the subfetchers, waits on any that were left spinning
|
||||||
// and reports the stats to the metrics subsystem.
|
// and reports the stats to the metrics subsystem. close should not be called
|
||||||
|
// more than once on a triePrefetcher instance.
|
||||||
func (p *triePrefetcher) close() {
|
func (p *triePrefetcher) close() {
|
||||||
for _, fetcher := range p.fetchers {
|
for _, fetcher := range p.fetchers {
|
||||||
|
fetcher.wait() // safe to do multiple times
|
||||||
|
|
||||||
if metrics.Enabled {
|
if metrics.Enabled {
|
||||||
if fetcher.root == p.root {
|
if fetcher.root == p.root {
|
||||||
p.accountLoadMeter.Mark(int64(len(fetcher.seen)))
|
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 schedules a batch of trie items to prefetch.
|
||||||
|
//
|
||||||
// prefetch is called from two locations:
|
// prefetch is called from two locations:
|
||||||
// 1. Finalize of the state-objects storage roots. This happens at the end
|
// 1. Finalize of the state-objects storage roots. This happens at the end
|
||||||
// of every transaction, meaning that if several transactions touches
|
// of every transaction, meaning that if several transactions touches
|
||||||
|
|
@ -138,12 +111,6 @@ func (p *triePrefetcher) copy() *triePrefetcher {
|
||||||
// repeated.
|
// repeated.
|
||||||
// 2. Finalize of the main account trie. This happens only once per block.
|
// 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) {
|
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)
|
id := p.trieID(owner, root)
|
||||||
fetcher := p.fetchers[id]
|
fetcher := p.fetchers[id]
|
||||||
if fetcher == nil {
|
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
|
// trie returns the trie matching the root hash, or nil if the prefetcher doesn't
|
||||||
// have it.
|
// have it.
|
||||||
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
|
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
|
||||||
// If the prefetcher is inactive, return from existing deep copies
|
// Bail if no trie was prefetched for this root
|
||||||
id := p.trieID(owner, root)
|
fetcher := p.fetchers[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]
|
|
||||||
if fetcher == nil {
|
if fetcher == nil {
|
||||||
p.deliveryMissMeter.Mark(1)
|
p.deliveryMissMeter.Mark(1)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -319,18 +319,6 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error {
|
||||||
return nil
|
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.
|
// EncodeRLP serializes a block as RLP.
|
||||||
func (b *Block) EncodeRLP(w io.Writer) error {
|
func (b *Block) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, &extblock{
|
return rlp.Encode(w, &extblock{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
func opAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
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()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = 0xffffffffffffffff
|
uint64CodeOffset = math.MaxUint64
|
||||||
}
|
}
|
||||||
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
codeCopy := getData(scope.Contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
@ -383,7 +384,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
)
|
)
|
||||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
uint64CodeOffset = 0xffffffffffffffff
|
uint64CodeOffset = math.MaxUint64
|
||||||
}
|
}
|
||||||
addr := common.Address(a.Bytes20())
|
addr := common.Address(a.Bytes20())
|
||||||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
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) {
|
if interpreter.evm.StateDB.Empty(address) {
|
||||||
slot.Clear()
|
slot.Clear()
|
||||||
} else {
|
} 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 {
|
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))
|
witness.AddCodeHash(interpreter.evm.StateDB.GetCodeHash(address))
|
||||||
}
|
}
|
||||||
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
|
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -449,7 +447,9 @@ func (api *DebugAPI) GetTrieFlushInterval() (string, error) {
|
||||||
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
|
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 {
|
if number == 0 {
|
||||||
panic("cannot build genesis block proof")
|
panic("cannot build genesis block proof")
|
||||||
}
|
}
|
||||||
|
|
@ -459,19 +459,8 @@ func BuildProof(number uint64, bc *core.BlockChain) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
db.EnableWitnessRecording()
|
db.EnableWitnessRecording()
|
||||||
db.StartPrefetcher("apidebug")
|
db.StartPrefetcher("debug_buildStatelessProof")
|
||||||
block := bc.GetBlockByNumber(number)
|
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())
|
stateProcessor := core.NewStateProcessor(bc.Config(), bc, bc.Engine())
|
||||||
_, _, _, err = stateProcessor.Process(block, db, vm.Config{})
|
_, _, _, err = stateProcessor.Process(block, db, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -489,6 +478,8 @@ func BuildProof(number uint64, bc *core.BlockChain) ([]byte, error) {
|
||||||
return enc, nil
|
return enc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *DebugAPI) BuildProof(num rpc.BlockNumber) ([]byte, error) {
|
// BuildStatelessProof executes a block, collecting the accessed pre-state into
|
||||||
return BuildProof(uint64(num), api.eth.blockchain)
|
// a Witness. The RLP-encoded witness is returned.
|
||||||
|
func (api *DebugAPI) BuildStatelessProof(num rpc.BlockNumber) ([]byte, error) {
|
||||||
|
return BuildStatelessProof(uint64(num), api.eth.blockchain)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -502,8 +502,8 @@ web3._extend({
|
||||||
params: 0
|
params: 0
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'buildProof',
|
name: 'buildStatelessProof',
|
||||||
call: 'debug_buildProof',
|
call: 'debug_buildStatelessProof',
|
||||||
params: 1
|
params: 1
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ func (t *BlockTest) UnmarshalJSON(in []byte) error {
|
||||||
type btJSON struct {
|
type btJSON struct {
|
||||||
Blocks []btBlock `json:"blocks"`
|
Blocks []btBlock `json:"blocks"`
|
||||||
Genesis btHeader `json:"genesisBlockHeader"`
|
Genesis btHeader `json:"genesisBlockHeader"`
|
||||||
Pre core.GenesisAlloc `json:"pre"`
|
Pre types.GenesisAlloc `json:"pre"`
|
||||||
Post core.GenesisAlloc `json:"postState"`
|
Post types.GenesisAlloc `json:"postState"`
|
||||||
BestBlock common.UnprefixedHash `json:"lastblockhash"`
|
BestBlock common.UnprefixedHash `json:"lastblockhash"`
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
SealEngine string `json:"sealEngine"`
|
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
|
// Wrap the original engine within the beacon-engine
|
||||||
engine := beacon.New(ethash.NewFaker())
|
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 {
|
if snapshotter {
|
||||||
cache.SnapshotLimit = 1
|
cache.SnapshotLimit = 1
|
||||||
cache.SnapshotWait = true
|
cache.SnapshotWait = true
|
||||||
|
|
@ -197,7 +197,7 @@ func (t *BlockTest) run(stateless bool, snapshotter bool, scheme string, tracer
|
||||||
|
|
||||||
if stateless {
|
if stateless {
|
||||||
for _, blk := range validBlocks {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to build proof: %v", err)
|
return fmt.Errorf("failed to build proof: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
trie/trie.go
10
trie/trie.go
|
|
@ -107,7 +107,7 @@ func NewEmpty(db database.Database) *Trie {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustNodeIterator is a wrapper of NodeIterator and will omit any encountered
|
// 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 {
|
func (t *Trie) MustNodeIterator(start []byte) NodeIterator {
|
||||||
it, err := t.NodeIterator(start)
|
it, err := t.NodeIterator(start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -581,10 +581,6 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) {
|
||||||
return n, nil
|
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
|
// 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
|
// 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
|
// 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))
|
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 {
|
func (t *Trie) AccessList() map[string][]byte {
|
||||||
return t.tracer.accessList
|
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) {
|
func (t *Trie) CommitAndObtainAccessList(collectLeaf bool) (common.Hash, *trienode.NodeSet, map[string][]byte, error) {
|
||||||
accessList := t.tracer.accessList
|
accessList := t.tracer.accessList
|
||||||
// Commit will reset the tracer accessList, so after this
|
// Commit will reset the tracer accessList, so after this
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,6 @@ var HashDefaults = &Config{
|
||||||
HashDB: hashdb.Defaults,
|
HashDB: hashdb.Defaults,
|
||||||
}
|
}
|
||||||
|
|
||||||
var PathDefaults = &Config{
|
|
||||||
Preimages: false,
|
|
||||||
PathDB: pathdb.Defaults,
|
|
||||||
}
|
|
||||||
|
|
||||||
// backend defines the methods needed to access/update trie nodes in different
|
// backend defines the methods needed to access/update trie nodes in different
|
||||||
// state scheme.
|
// state scheme.
|
||||||
type backend interface {
|
type backend interface {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue