Merge branch 'ethereum:master' into portal

This commit is contained in:
Chen Kai 2024-02-29 20:09:50 +08:00 committed by GitHub
commit 1942fef8fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 149 additions and 105 deletions

View file

@ -18,6 +18,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
@ -182,7 +183,7 @@ func open(ctx *cli.Context, epoch uint64) (*era.Era, error) {
// that the accumulator matches the expected value. // that the accumulator matches the expected value.
func verify(ctx *cli.Context) error { func verify(ctx *cli.Context) error {
if ctx.Args().Len() != 1 { if ctx.Args().Len() != 1 {
return fmt.Errorf("missing accumulators file") return errors.New("missing accumulators file")
} }
roots, err := readHashes(ctx.Args().First()) roots, err := readHashes(ctx.Args().First())
@ -203,7 +204,7 @@ func verify(ctx *cli.Context) error {
} }
if len(entries) != len(roots) { if len(entries) != len(roots) {
return fmt.Errorf("number of era1 files should match the number of accumulator hashes") return errors.New("number of era1 files should match the number of accumulator hashes")
} }
// Verify each epoch matches the expected root. // Verify each epoch matches the expected root.
@ -308,7 +309,7 @@ func checkAccumulator(e *era.Era) error {
func readHashes(f string) ([]common.Hash, error) { func readHashes(f string) ([]common.Hash, error) {
b, err := os.ReadFile(f) b, err := os.ReadFile(f)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to open accumulators file") return nil, errors.New("unable to open accumulators file")
} }
s := strings.Split(string(b), "\n") s := strings.Split(string(b), "\n")
// Remove empty last element, if present. // Remove empty last element, if present.

View file

@ -444,7 +444,7 @@ func importHistory(ctx *cli.Context) error {
return fmt.Errorf("no era1 files found in %s", dir) return fmt.Errorf("no era1 files found in %s", dir)
} }
if len(networks) > 1 { if len(networks) > 1 {
return fmt.Errorf("multiple networks found, use a network flag to specify desired network") return errors.New("multiple networks found, use a network flag to specify desired network")
} }
network = networks[0] network = networks[0]
} }
@ -514,13 +514,10 @@ func importPreimages(ctx *cli.Context) error {
return nil return nil
} }
func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, ethdb.Database, common.Hash, error) { func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
var header *types.Header var header *types.Header
if ctx.NArg() > 1 { if ctx.NArg() > 1 {
return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg()) return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
} }
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
arg := ctx.Args().First() arg := ctx.Args().First()
@ -529,17 +526,17 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
if number := rawdb.ReadHeaderNumber(db, hash); number != nil { if number := rawdb.ReadHeaderNumber(db, hash); number != nil {
header = rawdb.ReadHeader(db, hash, *number) header = rawdb.ReadHeader(db, hash, *number)
} else { } else {
return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash) return nil, common.Hash{}, fmt.Errorf("block %x not found", hash)
} }
} else { } else {
number, err := strconv.ParseUint(arg, 10, 64) number, err := strconv.ParseUint(arg, 10, 64)
if err != nil { if err != nil {
return nil, nil, common.Hash{}, err return nil, common.Hash{}, err
} }
if hash := rawdb.ReadCanonicalHash(db, number); hash != (common.Hash{}) { if hash := rawdb.ReadCanonicalHash(db, number); hash != (common.Hash{}) {
header = rawdb.ReadHeader(db, hash, number) header = rawdb.ReadHeader(db, hash, number)
} else { } else {
return nil, nil, common.Hash{}, fmt.Errorf("header for block %d not found", number) return nil, common.Hash{}, fmt.Errorf("header for block %d not found", number)
} }
} }
} else { } else {
@ -547,7 +544,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
header = rawdb.ReadHeadHeader(db) header = rawdb.ReadHeadHeader(db)
} }
if header == nil { if header == nil {
return nil, nil, common.Hash{}, errors.New("no head block found") return nil, common.Hash{}, errors.New("no head block found")
} }
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name)) startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
var start common.Hash var start common.Hash
@ -559,7 +556,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
start = crypto.Keccak256Hash(startArg) start = crypto.Keccak256Hash(startArg)
log.Info("Converting start-address to hash", "address", common.BytesToAddress(startArg), "hash", start.Hex()) log.Info("Converting start-address to hash", "address", common.BytesToAddress(startArg), "hash", start.Hex())
default: default:
return nil, nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg) return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
} }
var conf = &state.DumpConfig{ var conf = &state.DumpConfig{
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name), SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
@ -571,14 +568,17 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(), log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage, "skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage,
"start", hexutil.Encode(conf.Start), "limit", conf.Max) "start", hexutil.Encode(conf.Start), "limit", conf.Max)
return conf, db, header.Root, nil return conf, header.Root, nil
} }
func dump(ctx *cli.Context) error { func dump(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
defer stack.Close() defer stack.Close()
conf, db, root, err := parseDumpConfig(ctx, stack) db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
conf, root, err := parseDumpConfig(ctx, stack, db)
if err != nil { if err != nil {
return err return err
} }

View file

@ -541,7 +541,10 @@ func dumpState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
defer stack.Close() defer stack.Close()
conf, db, root, err := parseDumpConfig(ctx, stack) db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
conf, root, err := parseDumpConfig(ctx, stack, db)
if err != nil { if err != nil {
return err return err
} }

View file

@ -245,7 +245,7 @@ func readList(filename string) ([]string, error) {
// starting from genesis. // starting from genesis.
func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, network string) error { func ImportHistory(chain *core.BlockChain, db ethdb.Database, dir string, network string) error {
if chain.CurrentSnapBlock().Number.BitLen() != 0 { if chain.CurrentSnapBlock().Number.BitLen() != 0 {
return fmt.Errorf("history import only supported when starting from genesis") return errors.New("history import only supported when starting from genesis")
} }
entries, err := era.ReadDir(dir, network) entries, err := era.ReadDir(dir, network)
if err != nil { if err != nil {

View file

@ -1668,6 +1668,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 { if ctx.String(GCModeFlag.Name) == "archive" && cfg.TransactionHistory != 0 {
cfg.TransactionHistory = 0 cfg.TransactionHistory = 0
log.Warn("Disabled transaction unindexing for archive node") log.Warn("Disabled transaction unindexing for archive node")
cfg.StateScheme = rawdb.HashScheme
log.Warn("Forcing hash state-scheme for archive mode")
} }
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) { if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheTrieFlag.Name) {
cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100 cfg.TrieCleanCache = ctx.Int(CacheFlag.Name) * ctx.Int(CacheTrieFlag.Name) / 100

View file

@ -315,7 +315,7 @@ func ReadStateScheme(db ethdb.Reader) string {
// the stored state. // the stored state.
// //
// - If the provided scheme is none, use the scheme consistent with persistent // - If the provided scheme is none, use the scheme consistent with persistent
// state, or fallback to hash-based scheme if state is empty. // state, or fallback to path-based scheme if state is empty.
// //
// - If the provided scheme is hash, use hash-based scheme or error out if not // - If the provided scheme is hash, use hash-based scheme or error out if not
// compatible with persistent state scheme. // compatible with persistent state scheme.
@ -329,10 +329,8 @@ func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
stored := ReadStateScheme(disk) stored := ReadStateScheme(disk)
if provided == "" { if provided == "" {
if stored == "" { if stored == "" {
// use default scheme for empty database, flip it when log.Info("State schema set to default", "scheme", "path")
// path mode is chosen as default return PathScheme, nil // use default scheme for empty database
log.Info("State schema set to default", "scheme", "hash")
return HashScheme, nil
} }
log.Info("State scheme set to already existing", "scheme", stored) log.Info("State scheme set to already existing", "scheme", stored)
return stored, nil // reuse scheme of persistent scheme return stored, nil // reuse scheme of persistent scheme

View file

@ -113,8 +113,8 @@ var (
skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header
// Path-based storage scheme of merkle patricia trie. // Path-based storage scheme of merkle patricia trie.
trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node TrieNodeAccountPrefix = []byte("A") // TrieNodeAccountPrefix + hexPath -> trie node
trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
@ -265,15 +265,15 @@ func stateIDKey(root common.Hash) []byte {
return append(stateIDPrefix, root.Bytes()...) return append(stateIDPrefix, root.Bytes()...)
} }
// accountTrieNodeKey = trieNodeAccountPrefix + nodePath. // accountTrieNodeKey = TrieNodeAccountPrefix + nodePath.
func accountTrieNodeKey(path []byte) []byte { func accountTrieNodeKey(path []byte) []byte {
return append(trieNodeAccountPrefix, path...) return append(TrieNodeAccountPrefix, path...)
} }
// storageTrieNodeKey = trieNodeStoragePrefix + accountHash + nodePath. // storageTrieNodeKey = TrieNodeStoragePrefix + accountHash + nodePath.
func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte { func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte {
buf := make([]byte, len(trieNodeStoragePrefix)+common.HashLength+len(path)) buf := make([]byte, len(TrieNodeStoragePrefix)+common.HashLength+len(path))
n := copy(buf, trieNodeStoragePrefix) n := copy(buf, TrieNodeStoragePrefix)
n += copy(buf[n:], accountHash.Bytes()) n += copy(buf[n:], accountHash.Bytes())
copy(buf[n:], path) copy(buf[n:], path)
return buf return buf
@ -294,16 +294,16 @@ func IsLegacyTrieNode(key []byte, val []byte) bool {
// account trie node in path-based state scheme, and returns the resolved // account trie node in path-based state scheme, and returns the resolved
// node path if so. // node path if so.
func ResolveAccountTrieNodeKey(key []byte) (bool, []byte) { func ResolveAccountTrieNodeKey(key []byte) (bool, []byte) {
if !bytes.HasPrefix(key, trieNodeAccountPrefix) { if !bytes.HasPrefix(key, TrieNodeAccountPrefix) {
return false, nil return false, nil
} }
// The remaining key should only consist a hex node path // The remaining key should only consist a hex node path
// whose length is in the range 0 to 64 (64 is excluded // whose length is in the range 0 to 64 (64 is excluded
// since leaves are always wrapped with shortNode). // since leaves are always wrapped with shortNode).
if len(key) >= len(trieNodeAccountPrefix)+common.HashLength*2 { if len(key) >= len(TrieNodeAccountPrefix)+common.HashLength*2 {
return false, nil return false, nil
} }
return true, key[len(trieNodeAccountPrefix):] return true, key[len(TrieNodeAccountPrefix):]
} }
// IsAccountTrieNode reports whether a provided database entry is an account // IsAccountTrieNode reports whether a provided database entry is an account
@ -317,20 +317,20 @@ func IsAccountTrieNode(key []byte) bool {
// trie node in path-based state scheme, and returns the resolved account hash // trie node in path-based state scheme, and returns the resolved account hash
// and node path if so. // and node path if so.
func ResolveStorageTrieNode(key []byte) (bool, common.Hash, []byte) { func ResolveStorageTrieNode(key []byte) (bool, common.Hash, []byte) {
if !bytes.HasPrefix(key, trieNodeStoragePrefix) { if !bytes.HasPrefix(key, TrieNodeStoragePrefix) {
return false, common.Hash{}, nil return false, common.Hash{}, nil
} }
// The remaining key consists of 2 parts: // The remaining key consists of 2 parts:
// - 32 bytes account hash // - 32 bytes account hash
// - hex node path whose length is in the range 0 to 64 // - hex node path whose length is in the range 0 to 64
if len(key) < len(trieNodeStoragePrefix)+common.HashLength { if len(key) < len(TrieNodeStoragePrefix)+common.HashLength {
return false, common.Hash{}, nil return false, common.Hash{}, nil
} }
if len(key) >= len(trieNodeStoragePrefix)+common.HashLength+common.HashLength*2 { if len(key) >= len(TrieNodeStoragePrefix)+common.HashLength+common.HashLength*2 {
return false, common.Hash{}, nil return false, common.Hash{}, nil
} }
accountHash := common.BytesToHash(key[len(trieNodeStoragePrefix) : len(trieNodeStoragePrefix)+common.HashLength]) accountHash := common.BytesToHash(key[len(TrieNodeStoragePrefix) : len(TrieNodeStoragePrefix)+common.HashLength])
return true, accountHash, key[len(trieNodeStoragePrefix)+common.HashLength:] return true, accountHash, key[len(TrieNodeStoragePrefix)+common.HashLength:]
} }
// IsStorageTrieNode reports whether a provided database entry is a storage // IsStorageTrieNode reports whether a provided database entry is a storage

View file

@ -54,4 +54,10 @@ var (
// ErrFutureReplacePending is returned if a future transaction replaces a pending // ErrFutureReplacePending is returned if a future transaction replaces a pending
// one. Future transactions should only be able to replace other future transactions. // one. Future transactions should only be able to replace other future transactions.
ErrFutureReplacePending = errors.New("future transaction tries to replace pending") ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
// ErrAlreadyReserved is returned if the sender address has a pending transaction
// in a different subpool. For example, this error is returned in response to any
// input transaction of non-blob type when a blob transaction from this sender
// remains pending (and vice-versa).
ErrAlreadyReserved = errors.New("address already reserved")
) )

View file

@ -164,7 +164,12 @@ func (journal *journal) rotate(all map[common.Address]types.Transactions) error
return err return err
} }
journal.writer = sink journal.writer = sink
log.Info("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all))
logger := log.Info
if len(all) == 0 {
logger = log.Debug
}
logger("Regenerated local transaction journal", "transactions", journaled, "accounts", len(all))
return nil return nil
} }

View file

@ -122,7 +122,7 @@ func (p *TxPool) reserver(id int, subpool SubPool) AddressReserver {
log.Error("pool attempted to reserve already-owned address", "address", addr) log.Error("pool attempted to reserve already-owned address", "address", addr)
return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed return nil // Ignore fault to give the pool a chance to recover while the bug gets fixed
} }
return errors.New("address already reserved") return ErrAlreadyReserved
} }
p.reservations[addr] = subpool p.reservations[addr] = subpool
if metrics.Enabled { if metrics.Enabled {

View file

@ -18,6 +18,7 @@ package txpool
import ( import (
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"math/big" "math/big"
@ -120,13 +121,13 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
} }
sidecar := tx.BlobTxSidecar() sidecar := tx.BlobTxSidecar()
if sidecar == nil { if sidecar == nil {
return fmt.Errorf("missing sidecar in blob transaction") return errors.New("missing sidecar in blob transaction")
} }
// Ensure the number of items in the blob transaction and various side // Ensure the number of items in the blob transaction and various side
// data match up before doing any expensive validations // data match up before doing any expensive validations
hashes := tx.BlobHashes() hashes := tx.BlobHashes()
if len(hashes) == 0 { if len(hashes) == 0 {
return fmt.Errorf("blobless blob transaction") return errors.New("blobless blob transaction")
} }
if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob {
return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) return fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob)

View file

@ -305,7 +305,7 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
) )
dataOffset64, overflow := dataOffset.Uint64WithOverflow() dataOffset64, overflow := dataOffset.Uint64WithOverflow()
if overflow { if overflow {
dataOffset64 = 0xffffffffffffffff dataOffset64 = math.MaxUint64
} }
// These values are checked for overflow during gas cost calculation // These values are checked for overflow during gas cost calculation
memOffset64 := memOffset.Uint64() memOffset64 := memOffset.Uint64()

View file

@ -190,21 +190,21 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
// attributes. It supports both PayloadAttributesV1 and PayloadAttributesV2. // attributes. It supports both PayloadAttributesV1 and PayloadAttributesV2.
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
if params != nil { if params != nil {
if params.BeaconRoot != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root"))
}
switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) { switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) {
case forks.Paris: case forks.Paris:
if params.Withdrawals != nil { if params.Withdrawals != nil {
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("withdrawals before shanghai")) return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai"))
} }
case forks.Shanghai: case forks.Shanghai:
if params.Withdrawals == nil { if params.Withdrawals == nil {
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals")) return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals"))
} }
default: default:
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads")) return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV2 must only be called with paris and shanghai payloads"))
} }
if params.BeaconRoot != nil {
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("unexpected beacon root"))
}
} }
return api.forkchoiceUpdated(update, params, engine.PayloadV2, false) return api.forkchoiceUpdated(update, params, engine.PayloadV2, false)
} }
@ -213,15 +213,11 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
// in the payload attributes. It supports only PayloadAttributesV3. // in the payload attributes. It supports only PayloadAttributesV3.
func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, params *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) {
if params != nil { if params != nil {
// TODO(matt): according to https://github.com/ethereum/execution-apis/pull/498,
// payload attributes that are invalid should return error
// engine.InvalidPayloadAttributes. Once hive updates this, we should update
// on our end.
if params.Withdrawals == nil { if params.Withdrawals == nil {
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing withdrawals")) return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing withdrawals"))
} }
if params.BeaconRoot == nil { if params.BeaconRoot == nil {
return engine.STATUS_INVALID, engine.InvalidParams.With(errors.New("missing beacon root")) return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root"))
} }
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun { if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads")) return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))

View file

@ -100,7 +100,7 @@ func (ps *peerSet) registerSnapExtension(peer *snap.Peer) error {
return nil return nil
} }
// waitExtensions blocks until all satellite protocols are connected and tracked // waitSnapExtension blocks until all satellite protocols are connected and tracked
// by the peerset. // by the peerset.
func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) {
// If the peer does not support a compatible `snap`, don't wait // If the peer does not support a compatible `snap`, don't wait

View file

@ -136,7 +136,7 @@ func (p *Peer) dispatchRequest(req *Request) error {
} }
} }
// dispatchRequest fulfils a pending request and delivers it to the requested // dispatchResponse fulfils a pending request and delivers it to the requested
// sink. // sink.
func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error { func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error {
resOp := &response{ resOp := &response{

View file

@ -161,7 +161,7 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
return return
} }
// Avoid processing nested calls when only caring about top call // Avoid processing nested calls when only caring about top call
if t.config.OnlyTopCall && depth > 0 { if t.config.OnlyTopCall && depth > 1 {
return return
} }
// Skip if tracing was interrupted // Skip if tracing was interrupted

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -452,6 +453,7 @@ func newGQLService(t *testing.T, stack *node.Node, shanghai bool, gspec *core.Ge
TrieDirtyCache: 5, TrieDirtyCache: 5,
TrieTimeout: 60 * time.Minute, TrieTimeout: 60 * time.Minute,
SnapshotCache: 5, SnapshotCache: 5,
StateScheme: rawdb.HashScheme,
} }
var engine consensus.Engine = ethash.NewFaker() var engine consensus.Engine = ethash.NewFaker()
if shanghai { if shanghai {

View file

@ -17,6 +17,7 @@
package era package era
import ( import (
"errors"
"fmt" "fmt"
"math/big" "math/big"
@ -28,7 +29,7 @@ import (
// accumulator of header records. // accumulator of header records.
func ComputeAccumulator(hashes []common.Hash, tds []*big.Int) (common.Hash, error) { func ComputeAccumulator(hashes []common.Hash, tds []*big.Int) (common.Hash, error) {
if len(hashes) != len(tds) { if len(hashes) != len(tds) {
return common.Hash{}, fmt.Errorf("must have equal number hashes as td values") return common.Hash{}, errors.New("must have equal number hashes as td values")
} }
if len(hashes) > MaxEra1Size { if len(hashes) > MaxEra1Size {
return common.Hash{}, fmt.Errorf("too many records: have %d, max %d", len(hashes), MaxEra1Size) return common.Hash{}, fmt.Errorf("too many records: have %d, max %d", len(hashes), MaxEra1Size)

View file

@ -18,6 +18,7 @@ package era
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@ -158,7 +159,7 @@ func (b *Builder) AddRLP(header, body, receipts []byte, number uint64, hash comm
// corresponding e2store entries. // corresponding e2store entries.
func (b *Builder) Finalize() (common.Hash, error) { func (b *Builder) Finalize() (common.Hash, error) {
if b.startNum == nil { if b.startNum == nil {
return common.Hash{}, fmt.Errorf("finalize called on empty builder") return common.Hash{}, errors.New("finalize called on empty builder")
} }
// Compute accumulator root and write entry. // Compute accumulator root and write entry.
root, err := ComputeAccumulator(b.hashes, b.tds) root, err := ComputeAccumulator(b.hashes, b.tds)

View file

@ -18,6 +18,7 @@ package e2store
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
) )
@ -160,7 +161,7 @@ func (r *Reader) ReadMetadataAt(off int64) (typ uint16, length uint32, err error
// Check reserved bytes of header. // Check reserved bytes of header.
if b[6] != 0 || b[7] != 0 { if b[6] != 0 || b[7] != 0 {
return 0, 0, fmt.Errorf("reserved bytes are non-zero") return 0, 0, errors.New("reserved bytes are non-zero")
} }
return typ, length, nil return typ, length, nil

View file

@ -18,7 +18,7 @@ package e2store
import ( import (
"bytes" "bytes"
"fmt" "errors"
"io" "io"
"testing" "testing"
@ -92,7 +92,7 @@ func TestDecode(t *testing.T) {
}, },
{ // basic invalid decoding { // basic invalid decoding
have: "ffff000000000001", have: "ffff000000000001",
err: fmt.Errorf("reserved bytes are non-zero"), err: errors.New("reserved bytes are non-zero"),
}, },
{ // no more entries to read, returns EOF { // no more entries to read, returns EOF
have: "", have: "",

View file

@ -18,6 +18,7 @@ package era
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@ -127,7 +128,7 @@ func (e *Era) Close() error {
func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) { func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) {
if e.m.start > num || e.m.start+e.m.count <= num { if e.m.start > num || e.m.start+e.m.count <= num {
return nil, fmt.Errorf("out-of-bounds") return nil, errors.New("out-of-bounds")
} }
off, err := e.readOffset(num) off, err := e.readOffset(num)
if err != nil { if err != nil {

View file

@ -17,6 +17,7 @@
package era package era
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@ -30,7 +31,7 @@ type Iterator struct {
inner *RawIterator inner *RawIterator
} }
// NewRawIterator returns a new Iterator instance. Next must be immediately // NewIterator returns a new Iterator instance. Next must be immediately
// called on new iterators to load the first item. // called on new iterators to load the first item.
func NewIterator(e *Era) (*Iterator, error) { func NewIterator(e *Era) (*Iterator, error) {
inner, err := NewRawIterator(e) inner, err := NewRawIterator(e)
@ -61,7 +62,7 @@ func (it *Iterator) Error() error {
// Block returns the block for the iterator's current position. // Block returns the block for the iterator's current position.
func (it *Iterator) Block() (*types.Block, error) { func (it *Iterator) Block() (*types.Block, error) {
if it.inner.Header == nil || it.inner.Body == nil { if it.inner.Header == nil || it.inner.Body == nil {
return nil, fmt.Errorf("header and body must be non-nil") return nil, errors.New("header and body must be non-nil")
} }
var ( var (
header types.Header header types.Header

View file

@ -1272,10 +1272,14 @@ func TestFillBlobTransaction(t *testing.T) {
func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs { func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs {
var ( var (
gas = tx.Gas() gas = tx.Gas()
nonce = tx.Nonce() nonce = tx.Nonce()
input = tx.Data() input = tx.Data()
accessList *types.AccessList
) )
if acl := tx.AccessList(); acl != nil {
accessList = &acl
}
return TransactionArgs{ return TransactionArgs{
From: &from, From: &from,
To: tx.To(), To: tx.To(),
@ -1286,10 +1290,9 @@ func argsFromTransaction(tx *types.Transaction, from common.Address) Transaction
Nonce: (*hexutil.Uint64)(&nonce), Nonce: (*hexutil.Uint64)(&nonce),
Input: (*hexutil.Bytes)(&input), Input: (*hexutil.Bytes)(&input),
ChainID: (*hexutil.Big)(tx.ChainId()), ChainID: (*hexutil.Big)(tx.ChainId()),
// TODO: impl accessList conversion AccessList: accessList,
//AccessList: tx.AccessList(), BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()),
BlobFeeCap: (*hexutil.Big)(tx.BlobGasFeeCap()), BlobHashes: tx.BlobHashes(),
BlobHashes: tx.BlobHashes(),
} }
} }

View file

@ -148,7 +148,7 @@ func (NilSample) Clear() {}
func (NilSample) Snapshot() SampleSnapshot { return (*emptySnapshot)(nil) } func (NilSample) Snapshot() SampleSnapshot { return (*emptySnapshot)(nil) }
func (NilSample) Update(v int64) {} func (NilSample) Update(v int64) {}
// SamplePercentiles returns an arbitrary percentile of the slice of int64. // SamplePercentile returns an arbitrary percentile of the slice of int64.
func SamplePercentile(values []int64, p float64) float64 { func SamplePercentile(values []int64, p float64) float64 {
return CalculatePercentiles(values, []float64{p})[0] return CalculatePercentiles(values, []float64{p})[0]
} }

View file

@ -947,7 +947,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
if genParams.parentHash != (common.Hash{}) { if genParams.parentHash != (common.Hash{}) {
block := w.chain.GetBlockByHash(genParams.parentHash) block := w.chain.GetBlockByHash(genParams.parentHash)
if block == nil { if block == nil {
return nil, fmt.Errorf("missing parent") return nil, errors.New("missing parent")
} }
parent = block.Header() parent = block.Header()
} }

View file

@ -19,6 +19,7 @@ package node
import ( import (
"compress/gzip" "compress/gzip"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -299,7 +300,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
defer h.mu.Unlock() defer h.mu.Unlock()
if h.rpcAllowed() { if h.rpcAllowed() {
return fmt.Errorf("JSON-RPC over HTTP is already enabled") return errors.New("JSON-RPC over HTTP is already enabled")
} }
// Create RPC server and handler. // Create RPC server and handler.
@ -335,7 +336,7 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
defer h.mu.Unlock() defer h.mu.Unlock()
if h.wsAllowed() { if h.wsAllowed() {
return fmt.Errorf("JSON-RPC over WebSocket is already enabled") return errors.New("JSON-RPC over WebSocket is already enabled")
} }
// Create RPC server and handler. // Create RPC server and handler.
srv := rpc.NewServer() srv := rpc.NewServer()

View file

@ -364,7 +364,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) {
return nil, err return nil, err
} }
if respN.ID() != n.ID() { if respN.ID() != n.ID() {
return nil, fmt.Errorf("invalid ID in response record") return nil, errors.New("invalid ID in response record")
} }
if respN.Seq() < n.Seq() { if respN.Seq() < n.Seq() {
return n, nil // response record is older return n, nil // response record is older

View file

@ -496,7 +496,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s
} }
} }
if _, ok := seen[node.ID()]; ok { if _, ok := seen[node.ID()]; ok {
return nil, fmt.Errorf("duplicate record") return nil, errors.New("duplicate record")
} }
seen[node.ID()] = struct{}{} seen[node.ID()] = struct{}{}
return node, nil return node, nil

View file

@ -367,11 +367,11 @@ func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoarey
// key is part of the ID nonce signature. // key is part of the ID nonce signature.
var remotePubkey = new(ecdsa.PublicKey) var remotePubkey = new(ecdsa.PublicKey)
if err := challenge.Node.Load((*enode.Secp256k1)(remotePubkey)); err != nil { if err := challenge.Node.Load((*enode.Secp256k1)(remotePubkey)); err != nil {
return nil, nil, fmt.Errorf("can't find secp256k1 key for recipient") return nil, nil, errors.New("can't find secp256k1 key for recipient")
} }
ephkey, err := c.sc.ephemeralKeyGen() ephkey, err := c.sc.ephemeralKeyGen()
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("can't generate ephemeral key") return nil, nil, errors.New("can't generate ephemeral key")
} }
ephpubkey := EncodePubkey(&ephkey.PublicKey) ephpubkey := EncodePubkey(&ephkey.PublicKey)
auth.pubkey = ephpubkey[:] auth.pubkey = ephpubkey[:]
@ -395,7 +395,7 @@ func (c *Codec) makeHandshakeAuth(toID enode.ID, addr string, challenge *Whoarey
// Create session keys. // Create session keys.
sec := deriveKeys(sha256.New, ephkey, remotePubkey, c.localnode.ID(), challenge.Node.ID(), cdata) sec := deriveKeys(sha256.New, ephkey, remotePubkey, c.localnode.ID(), challenge.Node.ID(), cdata)
if sec == nil { if sec == nil {
return nil, nil, fmt.Errorf("key derivation failed") return nil, nil, errors.New("key derivation failed")
} }
return auth, sec, err return auth, sec, err
} }

View file

@ -191,7 +191,7 @@ func (c *Client) resolveEntry(ctx context.Context, domain, hash string) (entry,
func (c *Client) doResolveEntry(ctx context.Context, domain, hash string) (entry, error) { func (c *Client) doResolveEntry(ctx context.Context, domain, hash string) (entry, error) {
wantHash, err := b32format.DecodeString(hash) wantHash, err := b32format.DecodeString(hash)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid base32 hash") return nil, errors.New("invalid base32 hash")
} }
name := hash + "." + domain name := hash + "." + domain
txts, err := c.cfg.Resolver.LookupTXT(ctx, hash+"."+domain) txts, err := c.cfg.Resolver.LookupTXT(ctx, hash+"."+domain)

View file

@ -21,6 +21,7 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"encoding/base32" "encoding/base32"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"io" "io"
"strings" "strings"
@ -341,7 +342,7 @@ func parseLinkEntry(e string) (entry, error) {
func parseLink(e string) (*linkEntry, error) { func parseLink(e string) (*linkEntry, error) {
if !strings.HasPrefix(e, linkPrefix) { if !strings.HasPrefix(e, linkPrefix) {
return nil, fmt.Errorf("wrong/missing scheme 'enrtree' in URL") return nil, errors.New("wrong/missing scheme 'enrtree' in URL")
} }
e = e[len(linkPrefix):] e = e[len(linkPrefix):]

View file

@ -18,7 +18,7 @@ package enode
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "errors"
"io" "io"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
@ -67,7 +67,7 @@ func (V4ID) Verify(r *enr.Record, sig []byte) error {
if err := r.Load(&entry); err != nil { if err := r.Load(&entry); err != nil {
return err return err
} else if len(entry) != 33 { } else if len(entry) != 33 {
return fmt.Errorf("invalid public key") return errors.New("invalid public key")
} }
h := sha3.NewLegacyKeccak256() h := sha3.NewLegacyKeccak256()

View file

@ -84,7 +84,7 @@ func OpenDB(path string) (*DB, error) {
return newPersistentDB(path) return newPersistentDB(path)
} }
// newMemoryNodeDB creates a new in-memory node database without a persistent backend. // newMemoryDB creates a new in-memory node database without a persistent backend.
func newMemoryDB() (*DB, error) { func newMemoryDB() (*DB, error) {
db, err := leveldb.Open(storage.NewMemStorage(), nil) db, err := leveldb.Open(storage.NewMemStorage(), nil)
if err != nil { if err != nil {
@ -93,7 +93,7 @@ func newMemoryDB() (*DB, error) {
return &DB{lvl: db, quit: make(chan struct{})}, nil return &DB{lvl: db, quit: make(chan struct{})}, nil
} }
// newPersistentNodeDB creates/opens a leveldb backed persistent node database, // newPersistentDB creates/opens a leveldb backed persistent node database,
// also flushing its contents in case of a version mismatch. // also flushing its contents in case of a version mismatch.
func newPersistentDB(path string) (*DB, error) { func newPersistentDB(path string) (*DB, error) {
opts := &opt.Options{OpenFilesCacheCapacity: 5} opts := &opt.Options{OpenFilesCacheCapacity: 5}

View file

@ -17,6 +17,7 @@
package nat package nat
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"strings" "strings"
@ -46,7 +47,7 @@ func (n *pmp) ExternalIP() (net.IP, error) {
func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) {
if lifetime <= 0 { if lifetime <= 0 {
return 0, fmt.Errorf("lifetime must not be <= 0") return 0, errors.New("lifetime must not be <= 0")
} }
// Note order of port arguments is switched between our // Note order of port arguments is switched between our
// AddMapping and the client's AddPortMapping. // AddMapping and the client's AddPortMapping.

View file

@ -460,7 +460,7 @@ func startExecNodeStack() (*node.Node, error) {
// decode the config // decode the config
confEnv := os.Getenv(envNodeConfig) confEnv := os.Getenv(envNodeConfig)
if confEnv == "" { if confEnv == "" {
return nil, fmt.Errorf("missing " + envNodeConfig) return nil, errors.New("missing " + envNodeConfig)
} }
var conf execNodeConfig var conf execNodeConfig
if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { if err := json.Unmarshal([]byte(confEnv), &conf); err != nil {

View file

@ -22,8 +22,8 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 13 // Minor version component of the current release VersionMinor = 14 // Minor version component of the current release
VersionPatch = 14 // Patch version component of the current release VersionPatch = 0 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -324,7 +324,7 @@ func (h *handler) addRequestOp(op *requestOp) {
} }
} }
// removeRequestOps stops waiting for the given request IDs. // removeRequestOp stops waiting for the given request IDs.
func (h *handler) removeRequestOp(op *requestOp) { func (h *handler) removeRequestOp(op *requestOp) {
for _, id := range op.ids { for _, id := range op.ids {
delete(h.respWait, string(id)) delete(h.respWait, string(id))

View file

@ -708,7 +708,7 @@ func formatPrimitiveValue(encType string, encValue interface{}) (string, error)
func (t Types) validate() error { func (t Types) validate() error {
for typeKey, typeArr := range t { for typeKey, typeArr := range t {
if len(typeKey) == 0 { if len(typeKey) == 0 {
return fmt.Errorf("empty type key") return errors.New("empty type key")
} }
for i, typeObj := range typeArr { for i, typeObj := range typeArr {
if len(typeObj.Type) == 0 { if len(typeObj.Type) == 0 {

View file

@ -260,7 +260,7 @@ func fromHex(data any) ([]byte, error) {
return nil, fmt.Errorf("wrong type %T", data) return nil, fmt.Errorf("wrong type %T", data)
} }
// typeDataRequest tries to convert the data into a SignDataRequest. // typedDataRequest tries to convert the data into a SignDataRequest.
func typedDataRequest(data any) (*SignDataRequest, error) { func typedDataRequest(data any) (*SignDataRequest, error) {
var typedData apitypes.TypedData var typedData apitypes.TypedData
if td, ok := data.(apitypes.TypedData); ok { if td, ok := data.(apitypes.TypedData); ok {

View file

@ -556,7 +556,7 @@ func runRandTest(rt randTest) error {
checktr.MustUpdate(it.Key, it.Value) checktr.MustUpdate(it.Key, it.Value)
} }
if tr.Hash() != checktr.Hash() { if tr.Hash() != checktr.Hash() {
rt[i].err = fmt.Errorf("hash mismatch in opItercheckhash") rt[i].err = errors.New("hash mismatch in opItercheckhash")
} }
case opNodeDiff: case opNodeDiff:
var ( var (
@ -594,19 +594,19 @@ func runRandTest(rt randTest) error {
} }
} }
if len(insertExp) != len(tr.tracer.inserts) { if len(insertExp) != len(tr.tracer.inserts) {
rt[i].err = fmt.Errorf("insert set mismatch") rt[i].err = errors.New("insert set mismatch")
} }
if len(deleteExp) != len(tr.tracer.deletes) { if len(deleteExp) != len(tr.tracer.deletes) {
rt[i].err = fmt.Errorf("delete set mismatch") rt[i].err = errors.New("delete set mismatch")
} }
for insert := range tr.tracer.inserts { for insert := range tr.tracer.inserts {
if _, present := insertExp[insert]; !present { if _, present := insertExp[insert]; !present {
rt[i].err = fmt.Errorf("missing inserted node") rt[i].err = errors.New("missing inserted node")
} }
} }
for del := range tr.tracer.deletes { for del := range tr.tracer.deletes {
if _, present := deleteExp[del]; !present { if _, present := deleteExp[del]; !present {
rt[i].err = fmt.Errorf("missing deleted node") rt[i].err = errors.New("missing deleted node")
} }
} }
} }

View file

@ -203,7 +203,6 @@ func New(diskdb ethdb.Database, config *Config) *Database {
log.Crit("Failed to disable database", "err", err) // impossible to happen log.Crit("Failed to disable database", "err", err) // impossible to happen
} }
} }
log.Warn("Path-based state scheme is an experimental feature")
return db return db
} }
@ -391,17 +390,23 @@ func (db *Database) Recoverable(root common.Hash) bool {
if *id >= dl.stateID() { if *id >= dl.stateID() {
return false return false
} }
// This is a temporary workaround for the unavailability of the freezer in
// dev mode. As a consequence, the Pathdb loses the ability for deep reorg
// in certain cases.
// TODO(rjl493456442): Implement the in-memory ancient store.
if db.freezer == nil {
return false
}
// Ensure the requested state is a canonical state and all state // Ensure the requested state is a canonical state and all state
// histories in range [id+1, disklayer.ID] are present and complete. // histories in range [id+1, disklayer.ID] are present and complete.
parent := root
return checkHistories(db.freezer, *id+1, dl.stateID()-*id, func(m *meta) error { return checkHistories(db.freezer, *id+1, dl.stateID()-*id, func(m *meta) error {
if m.parent != parent { if m.parent != root {
return errors.New("unexpected state history") return errors.New("unexpected state history")
} }
if len(m.incomplete) > 0 { if len(m.incomplete) > 0 {
return errors.New("incomplete state history") return errors.New("incomplete state history")
} }
parent = m.root root = m.root
return nil return nil
}) == nil }) == nil
} }

View file

@ -215,7 +215,7 @@ func (m *meta) encode() []byte {
// decode unpacks the meta object from byte stream. // decode unpacks the meta object from byte stream.
func (m *meta) decode(blob []byte) error { func (m *meta) decode(blob []byte) error {
if len(blob) < 1 { if len(blob) < 1 {
return fmt.Errorf("no version tag") return errors.New("no version tag")
} }
switch blob[0] { switch blob[0] {
case stateHistoryVersion: case stateHistoryVersion:

View file

@ -204,6 +204,19 @@ func (b *nodebuffer) setSize(size int, db ethdb.KeyValueStore, clean *fastcache.
return b.flush(db, clean, id, false) return b.flush(db, clean, id, false)
} }
// allocBatch returns a database batch with pre-allocated buffer.
func (b *nodebuffer) allocBatch(db ethdb.KeyValueStore) ethdb.Batch {
var metasize int
for owner, nodes := range b.nodes {
if owner == (common.Hash{}) {
metasize += len(nodes) * len(rawdb.TrieNodeAccountPrefix) // database key prefix
} else {
metasize += len(nodes) * (len(rawdb.TrieNodeStoragePrefix) + common.HashLength) // database key prefix + owner
}
}
return db.NewBatchWithSize((metasize + int(b.size)) * 11 / 10) // extra 10% for potential pebble internal stuff
}
// flush persists the in-memory dirty trie node into the disk if the configured // flush persists the in-memory dirty trie node into the disk if the configured
// memory threshold is reached. Note, all data must be written atomically. // memory threshold is reached. Note, all data must be written atomically.
func (b *nodebuffer) flush(db ethdb.KeyValueStore, clean *fastcache.Cache, id uint64, force bool) error { func (b *nodebuffer) flush(db ethdb.KeyValueStore, clean *fastcache.Cache, id uint64, force bool) error {
@ -217,7 +230,7 @@ func (b *nodebuffer) flush(db ethdb.KeyValueStore, clean *fastcache.Cache, id ui
} }
var ( var (
start = time.Now() start = time.Now()
batch = db.NewBatchWithSize(int(b.size)) batch = b.allocBatch(db)
) )
nodes := writeNodes(batch, b.nodes, clean) nodes := writeNodes(batch, b.nodes, clean)
rawdb.WritePersistentStateID(batch, id) rawdb.WritePersistentStateID(batch, id)