mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge branch 'master' into change_secKeyCache_type
This commit is contained in:
commit
8af918d7ad
35 changed files with 637 additions and 430 deletions
116
accounts/abi/abigen/testdata/v2/structs-abi.go.txt
vendored
116
accounts/abi/abigen/testdata/v2/structs-abi.go.txt
vendored
|
|
@ -1,116 +0,0 @@
|
||||||
// Code generated via abigen V2 - DO NOT EDIT.
|
|
||||||
// This file is a generated binding and any manual changes will be lost.
|
|
||||||
|
|
||||||
package v1bindtests
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/v2"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
|
||||||
var (
|
|
||||||
_ = bytes.Equal
|
|
||||||
_ = errors.New
|
|
||||||
_ = big.NewInt
|
|
||||||
_ = common.Big1
|
|
||||||
_ = types.BloomLookup
|
|
||||||
_ = abi.ConvertType
|
|
||||||
)
|
|
||||||
|
|
||||||
// Struct0 is an auto generated low-level Go binding around an user-defined struct.
|
|
||||||
type Struct0 struct {
|
|
||||||
B [32]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// StructsMetaData contains all meta data concerning the Structs contract.
|
|
||||||
var StructsMetaData = bind.MetaData{
|
|
||||||
ABI: "[{\"inputs\":[],\"name\":\"F\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[]\",\"name\":\"c\",\"type\":\"uint256[]\"},{\"internalType\":\"bool[]\",\"name\":\"d\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"G\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"B\",\"type\":\"bytes32\"}],\"internalType\":\"structStructs.A[]\",\"name\":\"a\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
|
|
||||||
ID: "Structs",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Structs is an auto generated Go binding around an Ethereum contract.
|
|
||||||
type Structs struct {
|
|
||||||
abi abi.ABI
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStructs creates a new instance of Structs.
|
|
||||||
func NewStructs() *Structs {
|
|
||||||
parsed, err := StructsMetaData.ParseABI()
|
|
||||||
if err != nil {
|
|
||||||
panic(errors.New("invalid ABI: " + err.Error()))
|
|
||||||
}
|
|
||||||
return &Structs{abi: *parsed}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instance creates a wrapper for a deployed contract instance at the given address.
|
|
||||||
<<<<<<< HEAD
|
|
||||||
// Use this to create the instance object passed to abigen v2 library functions Call, Transact, etc.
|
|
||||||
func (c *Structs) Instance(backend bind.ContractBackend, addr common.Address) *bind.BoundContract {
|
|
||||||
return bind.NewBoundContract(addr, c.abi, backend, backend, backend)
|
|
||||||
=======
|
|
||||||
// Use this to create the instance object passed to abigen v2 library functions Call,
|
|
||||||
// Transact, etc.
|
|
||||||
func (c *Structs) Instance(backend bind.ContractBackend, addr common.Address) bind.BoundContract {
|
|
||||||
return bind.NewBoundContract(backend, addr, c.abi)
|
|
||||||
>>>>>>> 854c25e086 (accounts/abi/abigen: improve v2 template)
|
|
||||||
}
|
|
||||||
|
|
||||||
// F is the Go binding used to pack the parameters required for calling
|
|
||||||
// the contract method 0x28811f59.
|
|
||||||
//
|
|
||||||
// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d)
|
|
||||||
func (structs *Structs) PackF() ([]byte, error) {
|
|
||||||
return structs.abi.Pack("F")
|
|
||||||
}
|
|
||||||
|
|
||||||
// FOutput serves as a container for the return parameters of contract
|
|
||||||
// method F.
|
|
||||||
type FOutput struct {
|
|
||||||
A []Struct0
|
|
||||||
C []*big.Int
|
|
||||||
D []bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnpackF is the Go binding that unpacks the parameters returned
|
|
||||||
// from invoking the contract method with ID 0x28811f59.
|
|
||||||
//
|
|
||||||
// Solidity: function F() view returns((bytes32)[] a, uint256[] c, bool[] d)
|
|
||||||
func (structs *Structs) UnpackF(data []byte) (*FOutput, error) {
|
|
||||||
out, err := structs.abi.Unpack("F", data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret := new(FOutput)
|
|
||||||
ret.A = *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0)
|
|
||||||
ret.C = *abi.ConvertType(out[1], new([]*big.Int)).(*[]*big.Int)
|
|
||||||
ret.D = *abi.ConvertType(out[2], new([]bool)).(*[]bool)
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// G is the Go binding used to pack the parameters required for calling
|
|
||||||
// the contract method 0x6fecb623.
|
|
||||||
//
|
|
||||||
// Solidity: function G() view returns((bytes32)[] a)
|
|
||||||
func (structs *Structs) PackG() ([]byte, error) {
|
|
||||||
return structs.abi.Pack("G")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnpackG is the Go binding that unpacks the parameters returned
|
|
||||||
// from invoking the contract method with ID 0x6fecb623.
|
|
||||||
//
|
|
||||||
// Solidity: function G() view returns((bytes32)[] a)
|
|
||||||
func (structs *Structs) UnpackG(data []byte) (*[]Struct0, error) {
|
|
||||||
out, err := structs.abi.Unpack("G", data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
out0 := *abi.ConvertType(out[0], new([]Struct0)).(*[]Struct0)
|
|
||||||
return &out0, nil
|
|
||||||
}
|
|
||||||
|
|
@ -102,17 +102,17 @@ func TestAttachWelcome(t *testing.T) {
|
||||||
"--http", "--http.port", httpPort,
|
"--http", "--http.port", httpPort,
|
||||||
"--ws", "--ws.port", wsPort)
|
"--ws", "--ws.port", wsPort)
|
||||||
t.Run("ipc", func(t *testing.T) {
|
t.Run("ipc", func(t *testing.T) {
|
||||||
waitForEndpoint(t, ipc, 4*time.Second)
|
waitForEndpoint(t, ipc, 2*time.Minute)
|
||||||
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
|
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
|
||||||
})
|
})
|
||||||
t.Run("http", func(t *testing.T) {
|
t.Run("http", func(t *testing.T) {
|
||||||
endpoint := "http://127.0.0.1:" + httpPort
|
endpoint := "http://127.0.0.1:" + httpPort
|
||||||
waitForEndpoint(t, endpoint, 4*time.Second)
|
waitForEndpoint(t, endpoint, 2*time.Minute)
|
||||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||||
})
|
})
|
||||||
t.Run("ws", func(t *testing.T) {
|
t.Run("ws", func(t *testing.T) {
|
||||||
endpoint := "ws://127.0.0.1:" + wsPort
|
endpoint := "ws://127.0.0.1:" + wsPort
|
||||||
waitForEndpoint(t, endpoint, 4*time.Second)
|
waitForEndpoint(t, endpoint, 2*time.Minute)
|
||||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||||
})
|
})
|
||||||
geth.Kill()
|
geth.Kill()
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ var (
|
||||||
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
||||||
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
|
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
|
||||||
|
|
||||||
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
||||||
|
chainMgaspsGauge = metrics.NewRegisteredGauge("chain/mgasps", nil)
|
||||||
|
|
||||||
accountReadTimer = metrics.NewRegisteredResettingTimer("chain/account/reads", nil)
|
accountReadTimer = metrics.NewRegisteredResettingTimer("chain/account/reads", nil)
|
||||||
accountHashTimer = metrics.NewRegisteredResettingTimer("chain/account/hashes", nil)
|
accountHashTimer = metrics.NewRegisteredResettingTimer("chain/account/hashes", nil)
|
||||||
|
|
@ -92,8 +93,10 @@ var (
|
||||||
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
||||||
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
|
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
|
||||||
|
|
||||||
blockPrefetchExecuteTimer = metrics.NewRegisteredTimer("chain/prefetch/executes", nil)
|
blockPrefetchExecuteTimer = metrics.NewRegisteredResettingTimer("chain/prefetch/executes", nil)
|
||||||
blockPrefetchInterruptMeter = metrics.NewRegisteredMeter("chain/prefetch/interrupts", nil)
|
blockPrefetchInterruptMeter = metrics.NewRegisteredMeter("chain/prefetch/interrupts", nil)
|
||||||
|
blockPrefetchTxsInvalidMeter = metrics.NewRegisteredMeter("chain/prefetch/txs/invalid", nil)
|
||||||
|
blockPrefetchTxsValidMeter = metrics.NewRegisteredMeter("chain/prefetch/txs/valid", nil)
|
||||||
|
|
||||||
errInsertionInterrupted = errors.New("insertion is interrupted")
|
errInsertionInterrupted = errors.New("insertion is interrupted")
|
||||||
errChainStopped = errors.New("blockchain is stopped")
|
errChainStopped = errors.New("blockchain is stopped")
|
||||||
|
|
@ -1758,18 +1761,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
bc.reportBlock(block, nil, err)
|
bc.reportBlock(block, nil, err)
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
// No validation errors for the first block (or chain prefix skipped)
|
|
||||||
var activeState *state.StateDB
|
|
||||||
defer func() {
|
|
||||||
// The chain importer is starting and stopping trie prefetchers. If a bad
|
|
||||||
// block or other error is hit however, an early return may not properly
|
|
||||||
// terminate the background threads. This defer ensures that we clean up
|
|
||||||
// and dangling prefetcher, without deferring each and holding on live refs.
|
|
||||||
if activeState != nil {
|
|
||||||
activeState.StopPrefetcher()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Track the singleton witness from this chain insertion (if any)
|
// Track the singleton witness from this chain insertion (if any)
|
||||||
var witness *stateless.Witness
|
var witness *stateless.Witness
|
||||||
|
|
||||||
|
|
@ -1825,63 +1816,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Retrieve the parent block and it's state to execute on top
|
// Retrieve the parent block and it's state to execute on top
|
||||||
start := time.Now()
|
|
||||||
parent := it.previous()
|
parent := it.previous()
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||||
}
|
}
|
||||||
statedb, err := state.New(parent.Root, bc.statedb)
|
|
||||||
if err != nil {
|
|
||||||
return nil, it.index, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are past Byzantium, enable prefetching to pull in trie node paths
|
|
||||||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
|
||||||
// useless due to the intermediate root hashing after each transaction.
|
|
||||||
if bc.chainConfig.IsByzantium(block.Number()) {
|
|
||||||
// Generate witnesses either if we're self-testing, or if it's the
|
|
||||||
// only block being inserted. A bit crude, but witnesses are huge,
|
|
||||||
// so we refuse to make an entire chain of them.
|
|
||||||
if bc.vmConfig.StatelessSelfValidation || (makeWitness && len(chain) == 1) {
|
|
||||||
witness, err = stateless.NewWitness(block.Header(), bc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, it.index, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statedb.StartPrefetcher("chain", witness)
|
|
||||||
}
|
|
||||||
activeState = statedb
|
|
||||||
|
|
||||||
// If we have a followup block, run that against the current state to pre-cache
|
|
||||||
// transactions and probabilistically some of the account/storage trie nodes.
|
|
||||||
var followupInterrupt atomic.Bool
|
|
||||||
if !bc.cacheConfig.TrieCleanNoPrefetch {
|
|
||||||
if followup, err := it.peek(); followup != nil && err == nil {
|
|
||||||
throwaway, _ := state.New(parent.Root, bc.statedb)
|
|
||||||
|
|
||||||
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
|
|
||||||
// Disable tracing for prefetcher executions.
|
|
||||||
vmCfg := bc.vmConfig
|
|
||||||
vmCfg.Tracer = nil
|
|
||||||
bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt)
|
|
||||||
|
|
||||||
blockPrefetchExecuteTimer.Update(time.Since(start))
|
|
||||||
if followupInterrupt.Load() {
|
|
||||||
blockPrefetchInterruptMeter.Mark(1)
|
|
||||||
}
|
|
||||||
}(time.Now(), followup, throwaway)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The traced section of block import.
|
// The traced section of block import.
|
||||||
res, err := bc.processBlock(block, statedb, start, setHead)
|
start := time.Now()
|
||||||
followupInterrupt.Store(true)
|
res, err := bc.processBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
// Report the import stats before returning the various results
|
// Report the import stats before returning the various results
|
||||||
stats.processed++
|
stats.processed++
|
||||||
stats.usedGas += res.usedGas
|
stats.usedGas += res.usedGas
|
||||||
|
witness = res.witness
|
||||||
|
|
||||||
var snapDiffItems, snapBufItems common.StorageSize
|
var snapDiffItems, snapBufItems common.StorageSize
|
||||||
if bc.snaps != nil {
|
if bc.snaps != nil {
|
||||||
|
|
@ -1937,11 +1885,74 @@ type blockProcessingResult struct {
|
||||||
usedGas uint64
|
usedGas uint64
|
||||||
procTime time.Duration
|
procTime time.Duration
|
||||||
status WriteStatus
|
status WriteStatus
|
||||||
|
witness *stateless.Witness
|
||||||
}
|
}
|
||||||
|
|
||||||
// processBlock executes and validates the given block. If there was no error
|
// processBlock executes and validates the given block. If there was no error
|
||||||
// it writes the block and associated state to database.
|
// it writes the block and associated state to database.
|
||||||
func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, setHead bool) (_ *blockProcessingResult, blockEndErr error) {
|
func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
startTime = time.Now()
|
||||||
|
statedb *state.StateDB
|
||||||
|
interrupt atomic.Bool
|
||||||
|
)
|
||||||
|
defer interrupt.Store(true) // terminate the prefetch at the end
|
||||||
|
|
||||||
|
if bc.cacheConfig.TrieCleanNoPrefetch {
|
||||||
|
statedb, err = state.New(parentRoot, bc.statedb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If prefetching is enabled, run that against the current state to pre-cache
|
||||||
|
// transactions and probabilistically some of the account/storage trie nodes.
|
||||||
|
//
|
||||||
|
// Note: the main processor and prefetcher share the same reader with a local
|
||||||
|
// cache for mitigating the overhead of state access.
|
||||||
|
reader, err := bc.statedb.ReaderWithCache(parentRoot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
throwaway, err := state.NewWithReader(parentRoot, bc.statedb, reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
statedb, err = state.NewWithReader(parentRoot, bc.statedb, reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
|
||||||
|
// Disable tracing for prefetcher executions.
|
||||||
|
vmCfg := bc.vmConfig
|
||||||
|
vmCfg.Tracer = nil
|
||||||
|
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
|
||||||
|
|
||||||
|
blockPrefetchExecuteTimer.Update(time.Since(start))
|
||||||
|
if interrupt.Load() {
|
||||||
|
blockPrefetchInterruptMeter.Mark(1)
|
||||||
|
}
|
||||||
|
}(time.Now(), throwaway, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are past Byzantium, enable prefetching to pull in trie node paths
|
||||||
|
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||||
|
// useless due to the intermediate root hashing after each transaction.
|
||||||
|
var witness *stateless.Witness
|
||||||
|
if bc.chainConfig.IsByzantium(block.Number()) {
|
||||||
|
// Generate witnesses either if we're self-testing, or if it's the
|
||||||
|
// only block being inserted. A bit crude, but witnesses are huge,
|
||||||
|
// so we refuse to make an entire chain of them.
|
||||||
|
if bc.vmConfig.StatelessSelfValidation || makeWitness {
|
||||||
|
witness, err = stateless.NewWitness(block.Header(), bc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statedb.StartPrefetcher("chain", witness)
|
||||||
|
defer statedb.StopPrefetcher()
|
||||||
|
}
|
||||||
|
|
||||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||||
bc.logger.OnBlockStart(tracing.BlockEvent{
|
bc.logger.OnBlockStart(tracing.BlockEvent{
|
||||||
Block: block,
|
Block: block,
|
||||||
|
|
@ -2000,7 +2011,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xvtime := time.Since(xvstart)
|
xvtime := time.Since(xvstart)
|
||||||
proctime := time.Since(start) // processing + validation + cross validation
|
proctime := time.Since(startTime) // processing + validation + cross validation
|
||||||
|
|
||||||
// Update the metrics touched during block processing and validation
|
// Update the metrics touched during block processing and validation
|
||||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||||
|
|
@ -2041,9 +2052,14 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
||||||
|
|
||||||
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||||
blockInsertTimer.UpdateSince(start)
|
blockInsertTimer.UpdateSince(startTime)
|
||||||
|
|
||||||
return &blockProcessingResult{usedGas: res.GasUsed, procTime: proctime, status: status}, nil
|
return &blockProcessingResult{
|
||||||
|
usedGas: res.GasUsed,
|
||||||
|
procTime: proctime,
|
||||||
|
status: status,
|
||||||
|
witness: witness,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
||||||
|
|
@ -2527,14 +2543,22 @@ func (bc *BlockChain) reportBlock(block *types.Block, res *ProcessResult, err er
|
||||||
// logForkReadiness will write a log when a future fork is scheduled, but not
|
// logForkReadiness will write a log when a future fork is scheduled, but not
|
||||||
// active. This is useful so operators know their client is ready for the fork.
|
// active. This is useful so operators know their client is ready for the fork.
|
||||||
func (bc *BlockChain) logForkReadiness(block *types.Block) {
|
func (bc *BlockChain) logForkReadiness(block *types.Block) {
|
||||||
c := bc.Config()
|
config := bc.Config()
|
||||||
current, last := c.LatestFork(block.Time()), c.LatestFork(math.MaxUint64)
|
current, last := config.LatestFork(block.Time()), config.LatestFork(math.MaxUint64)
|
||||||
t := c.Timestamp(last)
|
|
||||||
if t == nil {
|
// Short circuit if the timestamp of the last fork is undefined,
|
||||||
|
// or if the network has already passed the last configured fork.
|
||||||
|
t := config.Timestamp(last)
|
||||||
|
if t == nil || current >= last {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
at := time.Unix(int64(*t), 0)
|
at := time.Unix(int64(*t), 0)
|
||||||
if current < last && time.Now().After(bc.lastForkReadyAlert.Add(forkReadyInterval)) {
|
|
||||||
|
// Only log if:
|
||||||
|
// - Current time is before the fork activation time
|
||||||
|
// - Enough time has passed since last alert
|
||||||
|
now := time.Now()
|
||||||
|
if now.Before(at) && now.After(bc.lastForkReadyAlert.Add(forkReadyInterval)) {
|
||||||
log.Info("Ready for fork activation", "fork", last, "date", at.Format(time.RFC822),
|
log.Info("Ready for fork activation", "fork", last, "date", at.Format(time.RFC822),
|
||||||
"remaining", time.Until(at).Round(time.Second), "timestamp", at.Unix())
|
"remaining", time.Until(at).Round(time.Second), "timestamp", at.Unix())
|
||||||
bc.lastForkReadyAlert = time.Now()
|
bc.lastForkReadyAlert = time.Now()
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,12 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
|
||||||
// Fetch the timings for the batch
|
// Fetch the timings for the batch
|
||||||
var (
|
var (
|
||||||
now = mclock.Now()
|
now = mclock.Now()
|
||||||
elapsed = now.Sub(st.startTime)
|
elapsed = now.Sub(st.startTime) + 1 // prevent zero division
|
||||||
|
mgasps = float64(st.usedGas) * 1000 / float64(elapsed)
|
||||||
)
|
)
|
||||||
|
// Update the Mgas per second gauge
|
||||||
|
chainMgaspsGauge.Update(int64(mgasps))
|
||||||
|
|
||||||
// If we're at the last block of the batch or report period reached, log
|
// If we're at the last block of the batch or report period reached, log
|
||||||
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
if index == len(chain)-1 || elapsed >= statsReportLimit {
|
||||||
// Count the number of transactions in this segment
|
// Count the number of transactions in this segment
|
||||||
|
|
@ -58,7 +62,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
|
||||||
context := []interface{}{
|
context := []interface{}{
|
||||||
"number", end.Number(), "hash", end.Hash(),
|
"number", end.Number(), "hash", end.Hash(),
|
||||||
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
|
||||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
||||||
}
|
}
|
||||||
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
||||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||||
|
|
@ -138,6 +142,7 @@ func (it *insertIterator) next() (*types.Block, error) {
|
||||||
//
|
//
|
||||||
// Both header and body validation errors (nil too) is cached into the iterator
|
// Both header and body validation errors (nil too) is cached into the iterator
|
||||||
// to avoid duplicating work on the following next() call.
|
// to avoid duplicating work on the following next() call.
|
||||||
|
// nolint:unused
|
||||||
func (it *insertIterator) peek() (*types.Block, error) {
|
func (it *insertIterator) peek() (*types.Block, error) {
|
||||||
// If we reached the end of the chain, abort
|
// If we reached the end of the chain, abort
|
||||||
if it.index+1 >= len(it.chain) {
|
if it.index+1 >= len(it.chain) {
|
||||||
|
|
|
||||||
|
|
@ -258,13 +258,21 @@ func ReadStateHistory(db ethdb.AncientReaderOp, id uint64) ([]byte, []byte, []by
|
||||||
// WriteStateHistory writes the provided state history to database. Compute the
|
// WriteStateHistory writes the provided state history to database. Compute the
|
||||||
// position of state history in freezer by minus one since the id of first state
|
// position of state history in freezer by minus one since the id of first state
|
||||||
// history starts from one(zero for initial state).
|
// history starts from one(zero for initial state).
|
||||||
func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte, accounts []byte, storages []byte) {
|
func WriteStateHistory(db ethdb.AncientWriter, id uint64, meta []byte, accountIndex []byte, storageIndex []byte, accounts []byte, storages []byte) error {
|
||||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
_, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||||
op.AppendRaw(stateHistoryMeta, id-1, meta)
|
if err := op.AppendRaw(stateHistoryMeta, id-1, meta); err != nil {
|
||||||
op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex)
|
return err
|
||||||
op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex)
|
}
|
||||||
op.AppendRaw(stateHistoryAccountData, id-1, accounts)
|
if err := op.AppendRaw(stateHistoryAccountIndex, id-1, accountIndex); err != nil {
|
||||||
op.AppendRaw(stateHistoryStorageData, id-1, storages)
|
return err
|
||||||
return nil
|
}
|
||||||
|
if err := op.AppendRaw(stateHistoryStorageIndex, id-1, storageIndex); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := op.AppendRaw(stateHistoryAccountData, id-1, accounts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return op.AppendRaw(stateHistoryStorageData, id-1, storages)
|
||||||
})
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package rawdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -45,25 +44,6 @@ const HashScheme = "hash"
|
||||||
// on extra state diffs to survive deep reorg.
|
// on extra state diffs to survive deep reorg.
|
||||||
const PathScheme = "path"
|
const PathScheme = "path"
|
||||||
|
|
||||||
// hasher is used to compute the sha256 hash of the provided data.
|
|
||||||
type hasher struct{ sha crypto.KeccakState }
|
|
||||||
|
|
||||||
var hasherPool = sync.Pool{
|
|
||||||
New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} },
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHasher() *hasher {
|
|
||||||
return hasherPool.Get().(*hasher)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hasher) hash(data []byte) common.Hash {
|
|
||||||
return crypto.HashData(h.sha, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hasher) release() {
|
|
||||||
hasherPool.Put(h)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAccountTrieNode retrieves the account trie node with the specified node path.
|
// ReadAccountTrieNode retrieves the account trie node with the specified node path.
|
||||||
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte {
|
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte {
|
||||||
data, _ := db.Get(accountTrieNodeKey(path))
|
data, _ := db.Get(accountTrieNodeKey(path))
|
||||||
|
|
@ -170,9 +150,7 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
h := newHasher()
|
return crypto.Keccak256Hash(blob) == hash // exists but not match
|
||||||
defer h.release()
|
|
||||||
return h.hash(blob) == hash // exists but not match
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unknown scheme %v", scheme))
|
panic(fmt.Sprintf("Unknown scheme %v", scheme))
|
||||||
}
|
}
|
||||||
|
|
@ -194,9 +172,7 @@ func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
h := newHasher()
|
if crypto.Keccak256Hash(blob) != hash {
|
||||||
defer h.release()
|
|
||||||
if h.hash(blob) != hash {
|
|
||||||
return nil // exists but not match
|
return nil // exists but not match
|
||||||
}
|
}
|
||||||
return blob
|
return blob
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Number of codehash->size associations to keep.
|
// Number of codehash->size associations to keep.
|
||||||
codeSizeCacheSize = 100000
|
codeSizeCacheSize = 1_000_000 // 4 megabytes in total
|
||||||
|
|
||||||
// Cache size granted for caching clean code.
|
// Cache size granted for caching clean code.
|
||||||
codeCacheSize = 64 * 1024 * 1024
|
codeCacheSize = 256 * 1024 * 1024
|
||||||
|
|
||||||
// Number of address->curve point associations to keep.
|
// Number of address->curve point associations to keep.
|
||||||
pointCacheSize = 4096
|
pointCacheSize = 4096
|
||||||
|
|
@ -208,6 +208,15 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReaderWithCache creates a state reader with internal local cache.
|
||||||
|
func (db *CachingDB) ReaderWithCache(stateRoot common.Hash) (Reader, error) {
|
||||||
|
reader, err := db.Reader(stateRoot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newReaderWithCache(reader), nil
|
||||||
|
}
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||||
if db.triedb.IsVerkle() {
|
if db.triedb.IsVerkle() {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
|
|
@ -51,6 +52,9 @@ type ContractCodeReader interface {
|
||||||
|
|
||||||
// StateReader defines the interface for accessing accounts and storage slots
|
// StateReader defines the interface for accessing accounts and storage slots
|
||||||
// associated with a specific state.
|
// associated with a specific state.
|
||||||
|
//
|
||||||
|
// StateReader is assumed to be thread-safe and implementation must take care
|
||||||
|
// of the concurrency issue by themselves.
|
||||||
type StateReader interface {
|
type StateReader interface {
|
||||||
// Account retrieves the account associated with a particular address.
|
// Account retrieves the account associated with a particular address.
|
||||||
//
|
//
|
||||||
|
|
@ -70,6 +74,9 @@ type StateReader interface {
|
||||||
|
|
||||||
// Reader defines the interface for accessing accounts, storage slots and contract
|
// Reader defines the interface for accessing accounts, storage slots and contract
|
||||||
// code associated with a specific state.
|
// code associated with a specific state.
|
||||||
|
//
|
||||||
|
// Reader is assumed to be thread-safe and implementation must take care of the
|
||||||
|
// concurrency issue by themselves.
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
ContractCodeReader
|
ContractCodeReader
|
||||||
StateReader
|
StateReader
|
||||||
|
|
@ -77,6 +84,8 @@ type Reader interface {
|
||||||
|
|
||||||
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
|
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
|
||||||
// local key-value store or the shared code cache.
|
// local key-value store or the shared code cache.
|
||||||
|
//
|
||||||
|
// cachingCodeReader is safe for concurrent access.
|
||||||
type cachingCodeReader struct {
|
type cachingCodeReader struct {
|
||||||
db ethdb.KeyValueReader
|
db ethdb.KeyValueReader
|
||||||
|
|
||||||
|
|
@ -123,18 +132,14 @@ func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash)
|
||||||
return len(code), nil
|
return len(code), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// flatReader wraps a database state reader.
|
// flatReader wraps a database state reader and is safe for concurrent access.
|
||||||
type flatReader struct {
|
type flatReader struct {
|
||||||
reader database.StateReader
|
reader database.StateReader
|
||||||
buff crypto.KeccakState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newFlatReader constructs a state reader with on the given state root.
|
// newFlatReader constructs a state reader with on the given state root.
|
||||||
func newFlatReader(reader database.StateReader) *flatReader {
|
func newFlatReader(reader database.StateReader) *flatReader {
|
||||||
return &flatReader{
|
return &flatReader{reader: reader}
|
||||||
reader: reader,
|
|
||||||
buff: crypto.NewKeccakState(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements StateReader, retrieving the account specified by the address.
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
|
|
@ -144,7 +149,7 @@ func newFlatReader(reader database.StateReader) *flatReader {
|
||||||
//
|
//
|
||||||
// The returned account might be nil if it's not existent.
|
// The returned account might be nil if it's not existent.
|
||||||
func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes()))
|
account, err := r.reader.Account(crypto.Keccak256Hash(addr.Bytes()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -174,8 +179,8 @@ func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
//
|
//
|
||||||
// The returned storage slot might be empty if it's not existent.
|
// The returned storage slot might be empty if it's not existent.
|
||||||
func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||||
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
addrHash := crypto.Keccak256Hash(addr.Bytes())
|
||||||
slotHash := crypto.HashData(r.buff, key.Bytes())
|
slotHash := crypto.Keccak256Hash(key.Bytes())
|
||||||
ret, err := r.reader.Storage(addrHash, slotHash)
|
ret, err := r.reader.Storage(addrHash, slotHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
|
|
@ -196,13 +201,20 @@ func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash,
|
||||||
|
|
||||||
// trieReader implements the StateReader interface, providing functions to access
|
// trieReader implements the StateReader interface, providing functions to access
|
||||||
// state from the referenced trie.
|
// state from the referenced trie.
|
||||||
|
//
|
||||||
|
// trieReader is safe for concurrent read.
|
||||||
type trieReader struct {
|
type trieReader struct {
|
||||||
root common.Hash // State root which uniquely represent a state
|
root common.Hash // State root which uniquely represent a state
|
||||||
db *triedb.Database // Database for loading trie
|
db *triedb.Database // Database for loading trie
|
||||||
buff crypto.KeccakState // Buffer for keccak256 hashing
|
buff crypto.KeccakState // Buffer for keccak256 hashing
|
||||||
mainTrie Trie // Main trie, resolved in constructor
|
|
||||||
|
// Main trie, resolved in constructor. Note either the Merkle-Patricia-tree
|
||||||
|
// or Verkle-tree is not safe for concurrent read.
|
||||||
|
mainTrie Trie
|
||||||
|
|
||||||
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
|
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
|
||||||
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
|
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
|
||||||
|
lock sync.Mutex // Lock for protecting concurrent read
|
||||||
}
|
}
|
||||||
|
|
||||||
// trieReader constructs a trie reader of the specific state. An error will be
|
// trieReader constructs a trie reader of the specific state. An error will be
|
||||||
|
|
@ -230,11 +242,8 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements StateReader, retrieving the account specified by the address.
|
// account is the inner version of Account and assumes the r.lock is already held.
|
||||||
//
|
func (r *trieReader) account(addr common.Address) (*types.StateAccount, error) {
|
||||||
// An error will be returned if the trie state is corrupted. An nil account
|
|
||||||
// will be returned if it's not existent in the trie.
|
|
||||||
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
|
||||||
account, err := r.mainTrie.GetAccount(addr)
|
account, err := r.mainTrie.GetAccount(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -247,12 +256,26 @@ func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
|
//
|
||||||
|
// An error will be returned if the trie state is corrupted. An nil account
|
||||||
|
// will be returned if it's not existent in the trie.
|
||||||
|
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
r.lock.Lock()
|
||||||
|
defer r.lock.Unlock()
|
||||||
|
|
||||||
|
return r.account(addr)
|
||||||
|
}
|
||||||
|
|
||||||
// Storage implements StateReader, retrieving the storage slot specified by the
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
// address and slot key.
|
// address and slot key.
|
||||||
//
|
//
|
||||||
// An error will be returned if the trie state is corrupted. An empty storage
|
// An error will be returned if the trie state is corrupted. An empty storage
|
||||||
// slot will be returned if it's not existent in the trie.
|
// slot will be returned if it's not existent in the trie.
|
||||||
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||||
|
r.lock.Lock()
|
||||||
|
defer r.lock.Unlock()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tr Trie
|
tr Trie
|
||||||
found bool
|
found bool
|
||||||
|
|
@ -268,7 +291,7 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash,
|
||||||
// The storage slot is accessed without account caching. It's unexpected
|
// The storage slot is accessed without account caching. It's unexpected
|
||||||
// behavior but try to resolve the account first anyway.
|
// behavior but try to resolve the account first anyway.
|
||||||
if !ok {
|
if !ok {
|
||||||
_, err := r.Account(addr)
|
_, err := r.account(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -293,6 +316,9 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash,
|
||||||
// multiStateReader is the aggregation of a list of StateReader interface,
|
// multiStateReader is the aggregation of a list of StateReader interface,
|
||||||
// providing state access by leveraging all readers. The checking priority
|
// providing state access by leveraging all readers. The checking priority
|
||||||
// is determined by the position in the reader list.
|
// is determined by the position in the reader list.
|
||||||
|
//
|
||||||
|
// multiStateReader is safe for concurrent read and assumes all underlying
|
||||||
|
// readers are thread-safe as well.
|
||||||
type multiStateReader struct {
|
type multiStateReader struct {
|
||||||
readers []StateReader // List of state readers, sorted by checking priority
|
readers []StateReader // List of state readers, sorted by checking priority
|
||||||
}
|
}
|
||||||
|
|
@ -358,3 +384,95 @@ func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader {
|
||||||
StateReader: stateReader,
|
StateReader: stateReader,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readerWithCache is a wrapper around Reader that maintains additional state caches
|
||||||
|
// to support concurrent state access.
|
||||||
|
type readerWithCache struct {
|
||||||
|
Reader // safe for concurrent read
|
||||||
|
|
||||||
|
// Previously resolved state entries.
|
||||||
|
accounts map[common.Address]*types.StateAccount
|
||||||
|
accountLock sync.RWMutex
|
||||||
|
|
||||||
|
// List of storage buckets, each of which is thread-safe.
|
||||||
|
// This reader is typically used in scenarios requiring concurrent
|
||||||
|
// access to storage. Using multiple buckets helps mitigate
|
||||||
|
// the overhead caused by locking.
|
||||||
|
storageBuckets [16]struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
storages map[common.Address]map[common.Hash]common.Hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newReaderWithCache constructs the reader with local cache.
|
||||||
|
func newReaderWithCache(reader Reader) *readerWithCache {
|
||||||
|
r := &readerWithCache{
|
||||||
|
Reader: reader,
|
||||||
|
accounts: make(map[common.Address]*types.StateAccount),
|
||||||
|
}
|
||||||
|
for i := range r.storageBuckets {
|
||||||
|
r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
|
// The returned account might be nil if it's not existent.
|
||||||
|
//
|
||||||
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
|
func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
// Try to resolve the requested account in the local cache
|
||||||
|
r.accountLock.RLock()
|
||||||
|
acct, ok := r.accounts[addr]
|
||||||
|
r.accountLock.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return acct, nil
|
||||||
|
}
|
||||||
|
// Try to resolve the requested account from the underlying reader
|
||||||
|
acct, err := r.Reader.Account(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r.accountLock.Lock()
|
||||||
|
r.accounts[addr] = acct
|
||||||
|
r.accountLock.Unlock()
|
||||||
|
return acct, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
|
// address and slot key. The returned storage slot might be empty if it's not
|
||||||
|
// existent.
|
||||||
|
//
|
||||||
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
|
func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
|
var (
|
||||||
|
value common.Hash
|
||||||
|
ok bool
|
||||||
|
bucket = &r.storageBuckets[addr[0]&0x0f]
|
||||||
|
)
|
||||||
|
// Try to resolve the requested storage slot in the local cache
|
||||||
|
bucket.lock.RLock()
|
||||||
|
slots, ok := bucket.storages[addr]
|
||||||
|
if ok {
|
||||||
|
value, ok = slots[slot]
|
||||||
|
}
|
||||||
|
bucket.lock.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
// Try to resolve the requested storage slot from the underlying reader
|
||||||
|
value, err := r.Reader.Storage(addr, slot)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
bucket.lock.Lock()
|
||||||
|
slots, ok = bucket.storages[addr]
|
||||||
|
if !ok {
|
||||||
|
slots = make(map[common.Hash]common.Hash)
|
||||||
|
bucket.storages[addr] = slots
|
||||||
|
}
|
||||||
|
slots[slot] = value
|
||||||
|
bucket.lock.Unlock()
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,11 +159,17 @@ type StateDB struct {
|
||||||
|
|
||||||
// New creates a new state from a given trie.
|
// New creates a new state from a given trie.
|
||||||
func New(root common.Hash, db Database) (*StateDB, error) {
|
func New(root common.Hash, db Database) (*StateDB, error) {
|
||||||
tr, err := db.OpenTrie(root)
|
reader, err := db.Reader(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader, err := db.Reader(root)
|
return NewWithReader(root, db, reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithReader creates a new state for the specified state root. Unlike New,
|
||||||
|
// this function accepts an additional Reader which is bound to the given root.
|
||||||
|
func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, error) {
|
||||||
|
tr, err := db.OpenTrie(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +298,7 @@ func (s *StateDB) SubRefund(gas uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exist reports whether the given account address exists in the state.
|
// Exist reports whether the given account address exists in the state.
|
||||||
// Notably this also returns true for self-destructed accounts.
|
// Notably this also returns true for self-destructed accounts within the current transaction.
|
||||||
func (s *StateDB) Exist(addr common.Address) bool {
|
func (s *StateDB) Exist(addr common.Address) bool {
|
||||||
return s.getStateObject(addr) != nil
|
return s.getStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
@ -392,6 +398,12 @@ func (s *StateDB) Database() Database {
|
||||||
return s.db
|
return s.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reader retrieves the low level database reader supporting the
|
||||||
|
// lower level operations.
|
||||||
|
func (s *StateDB) Reader() Reader {
|
||||||
|
return s.reader
|
||||||
|
}
|
||||||
|
|
||||||
func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -650,11 +662,10 @@ func (s *StateDB) CreateContract(addr common.Address) {
|
||||||
// Snapshots of the copied state cannot be applied to the copy.
|
// Snapshots of the copied state cannot be applied to the copy.
|
||||||
func (s *StateDB) Copy() *StateDB {
|
func (s *StateDB) Copy() *StateDB {
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
reader, _ := s.db.Reader(s.originalRoot) // impossible to fail
|
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
db: s.db,
|
db: s.db,
|
||||||
trie: mustCopyTrie(s.trie),
|
trie: mustCopyTrie(s.trie),
|
||||||
reader: reader,
|
reader: s.reader,
|
||||||
originalRoot: s.originalRoot,
|
originalRoot: s.originalRoot,
|
||||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||||
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,22 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"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/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
// statePrefetcher is a basic Prefetcher, which blindly executes a block on top
|
// statePrefetcher is a basic Prefetcher that executes transactions from a block
|
||||||
// of an arbitrary state with the goal of prefetching potentially useful state
|
// on top of the parent state, aiming to prefetch potentially useful state data
|
||||||
// data from disk before the main block processor start executing.
|
// from disk. Transactions are executed in parallel to fully leverage the
|
||||||
|
// SSD's read performance.
|
||||||
type statePrefetcher struct {
|
type statePrefetcher struct {
|
||||||
config *params.ChainConfig // Chain configuration options
|
config *params.ChainConfig // Chain configuration options
|
||||||
chain *HeaderChain // Canonical block chain
|
chain *HeaderChain // Canonical block chain
|
||||||
|
|
@ -43,41 +48,81 @@ func newStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePr
|
||||||
|
|
||||||
// Prefetch processes the state changes according to the Ethereum rules by running
|
// Prefetch processes the state changes according to the Ethereum rules by running
|
||||||
// the transaction messages using the statedb, but any changes are discarded. The
|
// the transaction messages using the statedb, but any changes are discarded. The
|
||||||
// only goal is to pre-cache transaction signatures and state trie nodes.
|
// only goal is to warm the state caches.
|
||||||
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) {
|
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) {
|
||||||
var (
|
var (
|
||||||
header = block.Header()
|
fails atomic.Int64
|
||||||
gaspool = new(GasPool).AddGas(block.GasLimit())
|
header = block.Header()
|
||||||
blockContext = NewEVMBlockContext(header, p.chain, nil)
|
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||||
evm = vm.NewEVM(blockContext, statedb, p.config, cfg)
|
workers errgroup.Group
|
||||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
reader = statedb.Reader()
|
||||||
)
|
)
|
||||||
// Iterate over and process the individual transactions
|
workers.SetLimit(runtime.NumCPU() / 2)
|
||||||
byzantium := p.config.IsByzantium(block.Number())
|
|
||||||
for i, tx := range block.Transactions() {
|
|
||||||
// If block precaching was interrupted, abort
|
|
||||||
if interrupt != nil && interrupt.Load() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Convert the transaction into an executable message and pre-cache its sender
|
|
||||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
|
||||||
if err != nil {
|
|
||||||
return // Also invalid block, bail out
|
|
||||||
}
|
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
|
||||||
|
|
||||||
// We attempt to apply a transaction. The goal is not to execute
|
// Iterate over and process the individual transactions
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
for i, tx := range block.Transactions() {
|
||||||
if _, err := ApplyMessage(evm, msg, gaspool); err != nil {
|
stateCpy := statedb.Copy() // closure
|
||||||
return // Ugh, something went horribly wrong, bail out
|
workers.Go(func() error {
|
||||||
}
|
// If block precaching was interrupted, abort
|
||||||
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
|
if interrupt != nil && interrupt.Load() {
|
||||||
if !byzantium {
|
return nil
|
||||||
statedb.IntermediateRoot(true)
|
}
|
||||||
}
|
// Preload the touched accounts and storage slots in advance
|
||||||
}
|
sender, err := types.Sender(signer, tx)
|
||||||
// If were post-byzantium, pre-load trie nodes for the final root hash
|
if err != nil {
|
||||||
if byzantium {
|
fails.Add(1)
|
||||||
statedb.IntermediateRoot(true)
|
return nil
|
||||||
|
}
|
||||||
|
reader.Account(sender)
|
||||||
|
|
||||||
|
if tx.To() != nil {
|
||||||
|
account, _ := reader.Account(*tx.To())
|
||||||
|
|
||||||
|
// Preload the contract code if the destination has non-empty code
|
||||||
|
if account != nil && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||||
|
reader.Code(*tx.To(), common.BytesToHash(account.CodeHash))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, list := range tx.AccessList() {
|
||||||
|
reader.Account(list.Address)
|
||||||
|
if len(list.StorageKeys) > 0 {
|
||||||
|
for _, slot := range list.StorageKeys {
|
||||||
|
reader.Storage(list.Address, slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Execute the message to preload the implicit touched states
|
||||||
|
evm := vm.NewEVM(NewEVMBlockContext(header, p.chain, nil), stateCpy, p.config, cfg)
|
||||||
|
|
||||||
|
// Convert the transaction into an executable message and pre-cache its sender
|
||||||
|
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||||
|
if err != nil {
|
||||||
|
fails.Add(1)
|
||||||
|
return nil // Also invalid block, bail out
|
||||||
|
}
|
||||||
|
// Disable the nonce check
|
||||||
|
msg.SkipNonceChecks = true
|
||||||
|
|
||||||
|
stateCpy.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
|
// We attempt to apply a transaction. The goal is not to execute
|
||||||
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
|
if _, err := ApplyMessage(evm, msg, new(GasPool).AddGas(block.GasLimit())); err != nil {
|
||||||
|
fails.Add(1)
|
||||||
|
return nil // Ugh, something went horribly wrong, bail out
|
||||||
|
}
|
||||||
|
// Pre-load trie nodes for the intermediate root.
|
||||||
|
//
|
||||||
|
// This operation incurs significant memory allocations due to
|
||||||
|
// trie hashing and node decoding. TODO(rjl493456442): investigate
|
||||||
|
// ways to mitigate this overhead.
|
||||||
|
stateCpy.IntermediateRoot(true)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
workers.Wait()
|
||||||
|
|
||||||
|
blockPrefetchTxsValidMeter.Mark(int64(len(block.Transactions())) - fails.Load())
|
||||||
|
blockPrefetchTxsInvalidMeter.Mark(fails.Load())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,9 @@ type Message struct {
|
||||||
|
|
||||||
// When SkipNonceChecks is true, the message nonce is not checked against the
|
// When SkipNonceChecks is true, the message nonce is not checked against the
|
||||||
// account nonce in state.
|
// account nonce in state.
|
||||||
// This field will be set to true for operations like RPC eth_call.
|
//
|
||||||
|
// This field will be set to true for operations like RPC eth_call
|
||||||
|
// or the state prefetching.
|
||||||
SkipNonceChecks bool
|
SkipNonceChecks bool
|
||||||
|
|
||||||
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
// When SkipFromEOACheck is true, the message sender is not checked to be an EOA.
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,13 @@ type Account struct {
|
||||||
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
|
||||||
Balance *big.Int `json:"balance" gencodec:"required"`
|
Balance *big.Int `json:"balance" gencodec:"required"`
|
||||||
Nonce uint64 `json:"nonce,omitempty"`
|
Nonce uint64 `json:"nonce,omitempty"`
|
||||||
|
|
||||||
// used in tests
|
|
||||||
PrivateKey []byte `json:"secretKey,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type accountMarshaling struct {
|
type accountMarshaling struct {
|
||||||
Code hexutil.Bytes
|
Code hexutil.Bytes
|
||||||
Balance *math.HexOrDecimal256
|
Balance *math.HexOrDecimal256
|
||||||
Nonce math.HexOrDecimal64
|
Nonce math.HexOrDecimal64
|
||||||
Storage map[storageJSON]storageJSON
|
Storage map[storageJSON]storageJSON
|
||||||
PrivateKey hexutil.Bytes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
|
// storageJSON represents a 256 bit byte array, but allows less than 256 bits when
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,10 @@ var _ = (*accountMarshaling)(nil)
|
||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (a Account) MarshalJSON() ([]byte, error) {
|
func (a Account) MarshalJSON() ([]byte, error) {
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Code hexutil.Bytes `json:"code,omitempty"`
|
Code hexutil.Bytes `json:"code,omitempty"`
|
||||||
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
||||||
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
||||||
Nonce math.HexOrDecimal64 `json:"nonce,omitempty"`
|
Nonce math.HexOrDecimal64 `json:"nonce,omitempty"`
|
||||||
PrivateKey hexutil.Bytes `json:"secretKey,omitempty"`
|
|
||||||
}
|
}
|
||||||
var enc Account
|
var enc Account
|
||||||
enc.Code = a.Code
|
enc.Code = a.Code
|
||||||
|
|
@ -33,18 +32,16 @@ func (a Account) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
enc.Balance = (*math.HexOrDecimal256)(a.Balance)
|
enc.Balance = (*math.HexOrDecimal256)(a.Balance)
|
||||||
enc.Nonce = math.HexOrDecimal64(a.Nonce)
|
enc.Nonce = math.HexOrDecimal64(a.Nonce)
|
||||||
enc.PrivateKey = a.PrivateKey
|
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (a *Account) UnmarshalJSON(input []byte) error {
|
func (a *Account) UnmarshalJSON(input []byte) error {
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Code *hexutil.Bytes `json:"code,omitempty"`
|
Code *hexutil.Bytes `json:"code,omitempty"`
|
||||||
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
Storage map[storageJSON]storageJSON `json:"storage,omitempty"`
|
||||||
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
Balance *math.HexOrDecimal256 `json:"balance" gencodec:"required"`
|
||||||
Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"`
|
Nonce *math.HexOrDecimal64 `json:"nonce,omitempty"`
|
||||||
PrivateKey *hexutil.Bytes `json:"secretKey,omitempty"`
|
|
||||||
}
|
}
|
||||||
var dec Account
|
var dec Account
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -66,8 +63,5 @@ func (a *Account) UnmarshalJSON(input []byte) error {
|
||||||
if dec.Nonce != nil {
|
if dec.Nonce != nil {
|
||||||
a.Nonce = uint64(*dec.Nonce)
|
a.Nonce = uint64(*dec.Nonce)
|
||||||
}
|
}
|
||||||
if dec.PrivateKey != nil {
|
|
||||||
a.PrivateKey = *dec.PrivateKey
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasherPool holds LegacyKeccak256 hashers for rlpHash.
|
// hasherPool holds LegacyKeccak256 hashers for rlpHash.
|
||||||
var hasherPool = sync.Pool{
|
var hasherPool = sync.Pool{
|
||||||
New: func() interface{} { return sha3.NewLegacyKeccak256() },
|
New: func() interface{} { return crypto.NewKeccakState() },
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
|
// encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
|
||||||
|
|
|
||||||
|
|
@ -355,28 +355,31 @@ func (tx *Transaction) GasTipCapIntCmp(other *big.Int) int {
|
||||||
// Note: if the effective gasTipCap is negative, this method returns both error
|
// Note: if the effective gasTipCap is negative, this method returns both error
|
||||||
// the actual negative value, _and_ ErrGasFeeCapTooLow
|
// the actual negative value, _and_ ErrGasFeeCapTooLow
|
||||||
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
|
func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
|
||||||
|
dst := new(big.Int)
|
||||||
|
err := tx.calcEffectiveGasTip(dst, baseFee)
|
||||||
|
return dst, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// calcEffectiveGasTip calculates the effective gas tip of the transaction and
|
||||||
|
// saves the result to dst.
|
||||||
|
func (tx *Transaction) calcEffectiveGasTip(dst *big.Int, baseFee *big.Int) error {
|
||||||
if baseFee == nil {
|
if baseFee == nil {
|
||||||
return tx.GasTipCap(), nil
|
dst.Set(tx.inner.gasTipCap())
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
gasFeeCap := tx.GasFeeCap()
|
gasFeeCap := tx.inner.gasFeeCap()
|
||||||
if gasFeeCap.Cmp(baseFee) < 0 {
|
if gasFeeCap.Cmp(baseFee) < 0 {
|
||||||
err = ErrGasFeeCapTooLow
|
err = ErrGasFeeCapTooLow
|
||||||
}
|
}
|
||||||
gasFeeCap = gasFeeCap.Sub(gasFeeCap, baseFee)
|
|
||||||
|
|
||||||
gasTipCap := tx.GasTipCap()
|
dst.Sub(gasFeeCap, baseFee)
|
||||||
if gasTipCap.Cmp(gasFeeCap) < 0 {
|
gasTipCap := tx.inner.gasTipCap()
|
||||||
return gasTipCap, err
|
if gasTipCap.Cmp(dst) < 0 {
|
||||||
|
dst.Set(gasTipCap)
|
||||||
}
|
}
|
||||||
return gasFeeCap, err
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
// EffectiveGasTipValue is identical to EffectiveGasTip, but does not return an
|
|
||||||
// error in case the effective gasTipCap is negative
|
|
||||||
func (tx *Transaction) EffectiveGasTipValue(baseFee *big.Int) *big.Int {
|
|
||||||
effectiveTip, _ := tx.EffectiveGasTip(baseFee)
|
|
||||||
return effectiveTip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
|
// EffectiveGasTipCmp compares the effective gasTipCap of two transactions assuming the given base fee.
|
||||||
|
|
@ -384,7 +387,11 @@ func (tx *Transaction) EffectiveGasTipCmp(other *Transaction, baseFee *big.Int)
|
||||||
if baseFee == nil {
|
if baseFee == nil {
|
||||||
return tx.GasTipCapCmp(other)
|
return tx.GasTipCapCmp(other)
|
||||||
}
|
}
|
||||||
return tx.EffectiveGasTipValue(baseFee).Cmp(other.EffectiveGasTipValue(baseFee))
|
// Use more efficient internal method.
|
||||||
|
txTip, otherTip := new(big.Int), new(big.Int)
|
||||||
|
tx.calcEffectiveGasTip(txTip, baseFee)
|
||||||
|
other.calcEffectiveGasTip(otherTip, baseFee)
|
||||||
|
return txTip.Cmp(otherTip)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
|
// EffectiveGasTipIntCmp compares the effective gasTipCap of a transaction to the given gasTipCap.
|
||||||
|
|
@ -392,7 +399,9 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i
|
||||||
if baseFee == nil {
|
if baseFee == nil {
|
||||||
return tx.GasTipCapIntCmp(other)
|
return tx.GasTipCapIntCmp(other)
|
||||||
}
|
}
|
||||||
return tx.EffectiveGasTipValue(baseFee).Cmp(other)
|
txTip := new(big.Int)
|
||||||
|
tx.calcEffectiveGasTip(txTip, baseFee)
|
||||||
|
return txTip.Cmp(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise.
|
// BlobGas returns the blob gas limit of the transaction for blob transactions, 0 otherwise.
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -593,3 +594,101 @@ func BenchmarkHash(b *testing.B) {
|
||||||
signer.Hash(tx)
|
signer.Hash(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkEffectiveGasTip(b *testing.B) {
|
||||||
|
signer := LatestSigner(params.TestChainConfig)
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
txdata := &DynamicFeeTx{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
Nonce: 0,
|
||||||
|
GasTipCap: big.NewInt(2000000000),
|
||||||
|
GasFeeCap: big.NewInt(3000000000),
|
||||||
|
Gas: 21000,
|
||||||
|
To: &common.Address{},
|
||||||
|
Value: big.NewInt(0),
|
||||||
|
Data: nil,
|
||||||
|
}
|
||||||
|
tx, _ := SignNewTx(key, signer, txdata)
|
||||||
|
baseFee := big.NewInt(1000000000) // 1 gwei
|
||||||
|
|
||||||
|
b.Run("Original", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, err := tx.EffectiveGasTip(baseFee)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("IntoMethod", func(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
dst := new(big.Int)
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := tx.calcEffectiveGasTip(dst, baseFee)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEffectiveGasTipInto(t *testing.T) {
|
||||||
|
signer := LatestSigner(params.TestChainConfig)
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
tipCap int64
|
||||||
|
feeCap int64
|
||||||
|
baseFee *int64
|
||||||
|
}{
|
||||||
|
{tipCap: 1, feeCap: 100, baseFee: intPtr(50)},
|
||||||
|
{tipCap: 10, feeCap: 100, baseFee: intPtr(50)},
|
||||||
|
{tipCap: 50, feeCap: 100, baseFee: intPtr(50)},
|
||||||
|
{tipCap: 100, feeCap: 100, baseFee: intPtr(50)},
|
||||||
|
{tipCap: 1, feeCap: 50, baseFee: intPtr(50)},
|
||||||
|
{tipCap: 1, feeCap: 20, baseFee: intPtr(50)}, // Base fee higher than fee cap
|
||||||
|
{tipCap: 50, feeCap: 100, baseFee: intPtr(0)},
|
||||||
|
{tipCap: 50, feeCap: 100, baseFee: nil}, // nil base fee
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
txdata := &DynamicFeeTx{
|
||||||
|
ChainID: big.NewInt(1),
|
||||||
|
Nonce: 0,
|
||||||
|
GasTipCap: big.NewInt(tc.tipCap),
|
||||||
|
GasFeeCap: big.NewInt(tc.feeCap),
|
||||||
|
Gas: 21000,
|
||||||
|
To: &common.Address{},
|
||||||
|
Value: big.NewInt(0),
|
||||||
|
Data: nil,
|
||||||
|
}
|
||||||
|
tx, _ := SignNewTx(key, signer, txdata)
|
||||||
|
|
||||||
|
var baseFee *big.Int
|
||||||
|
if tc.baseFee != nil {
|
||||||
|
baseFee = big.NewInt(*tc.baseFee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get result from original method
|
||||||
|
orig, origErr := tx.EffectiveGasTip(baseFee)
|
||||||
|
|
||||||
|
// Get result from new method
|
||||||
|
dst := new(big.Int)
|
||||||
|
newErr := tx.calcEffectiveGasTip(dst, baseFee)
|
||||||
|
|
||||||
|
// Compare results
|
||||||
|
if (origErr != nil) != (newErr != nil) {
|
||||||
|
t.Fatalf("case %d: error mismatch: orig %v, new %v", i, origErr, newErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if orig.Cmp(dst) != 0 {
|
||||||
|
t.Fatalf("case %d: result mismatch: orig %v, new %v", i, orig, dst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create integer pointer
|
||||||
|
func intPtr(i int64) *int64 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -555,7 +555,8 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
||||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||||
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||||
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), crypto.Keccak256(code))
|
inithash := crypto.HashData(evm.interpreter.hasher, code)
|
||||||
|
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
|
||||||
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
|
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
@ -234,11 +233,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
offset, size := scope.Stack.pop(), scope.Stack.peek()
|
offset, size := scope.Stack.pop(), scope.Stack.peek()
|
||||||
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
|
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
|
||||||
|
|
||||||
if interpreter.hasher == nil {
|
interpreter.hasher.Reset()
|
||||||
interpreter.hasher = crypto.NewKeccakState()
|
|
||||||
} else {
|
|
||||||
interpreter.hasher.Reset()
|
|
||||||
}
|
|
||||||
interpreter.hasher.Write(data)
|
interpreter.hasher.Write(data)
|
||||||
interpreter.hasher.Read(interpreter.hasherBuf[:])
|
interpreter.hasher.Read(interpreter.hasherBuf[:])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ type StateDB interface {
|
||||||
SelfDestruct6780(common.Address) (uint256.Int, bool)
|
SelfDestruct6780(common.Address) (uint256.Int, bool)
|
||||||
|
|
||||||
// Exist reports whether the given account exists in state.
|
// Exist reports whether the given account exists in state.
|
||||||
// Notably this should also return true for self-destructed accounts.
|
// Notably this also returns true for self-destructed accounts within the current transaction.
|
||||||
Exist(common.Address) bool
|
Exist(common.Address) bool
|
||||||
// Empty returns whether the given account is empty. Empty
|
// Empty returns whether the given account is empty. Empty
|
||||||
// is defined according to EIP161 (balance = nonce = code = 0).
|
// is defined according to EIP161 (balance = nonce = code = 0).
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evm.Config.ExtraEips = extraEips
|
evm.Config.ExtraEips = extraEips
|
||||||
return &EVMInterpreter{evm: evm, table: table}
|
return &EVMInterpreter{evm: evm, table: table, hasher: crypto.NewKeccakState()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run loops and evaluates the contract's code with the given input data and returns
|
// Run loops and evaluates the contract's code with the given input data and returns
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
|
@ -73,6 +74,12 @@ func NewKeccakState() KeccakState {
|
||||||
return sha3.NewLegacyKeccak256().(KeccakState)
|
return sha3.NewLegacyKeccak256().(KeccakState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasherPool = sync.Pool{
|
||||||
|
New: func() any {
|
||||||
|
return sha3.NewLegacyKeccak256().(KeccakState)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// HashData hashes the provided data using the KeccakState and returns a 32 byte hash
|
// HashData hashes the provided data using the KeccakState and returns a 32 byte hash
|
||||||
func HashData(kh KeccakState, data []byte) (h common.Hash) {
|
func HashData(kh KeccakState, data []byte) (h common.Hash) {
|
||||||
kh.Reset()
|
kh.Reset()
|
||||||
|
|
@ -84,22 +91,26 @@ func HashData(kh KeccakState, data []byte) (h common.Hash) {
|
||||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||||
func Keccak256(data ...[]byte) []byte {
|
func Keccak256(data ...[]byte) []byte {
|
||||||
b := make([]byte, 32)
|
b := make([]byte, 32)
|
||||||
d := NewKeccakState()
|
d := hasherPool.Get().(KeccakState)
|
||||||
|
d.Reset()
|
||||||
for _, b := range data {
|
for _, b := range data {
|
||||||
d.Write(b)
|
d.Write(b)
|
||||||
}
|
}
|
||||||
d.Read(b)
|
d.Read(b)
|
||||||
|
hasherPool.Put(d)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
|
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
|
||||||
// converting it to an internal Hash data structure.
|
// converting it to an internal Hash data structure.
|
||||||
func Keccak256Hash(data ...[]byte) (h common.Hash) {
|
func Keccak256Hash(data ...[]byte) (h common.Hash) {
|
||||||
d := NewKeccakState()
|
d := hasherPool.Get().(KeccakState)
|
||||||
|
d.Reset()
|
||||||
for _, b := range data {
|
for _, b := range data {
|
||||||
d.Write(b)
|
d.Write(b)
|
||||||
}
|
}
|
||||||
d.Read(h[:])
|
d.Read(h[:])
|
||||||
|
hasherPool.Put(d)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
|
||||||
gokzg4844 "github.com/crate-crypto/go-kzg-4844"
|
gokzg4844 "github.com/crate-crypto/go-eth-kzg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func randFieldElement() [32]byte {
|
func randFieldElement() [32]byte {
|
||||||
|
|
|
||||||
|
|
@ -134,13 +134,17 @@ func TestSendTx(t *testing.T) {
|
||||||
func testSendTx(t *testing.T, withLocal bool) {
|
func testSendTx(t *testing.T, withLocal bool) {
|
||||||
b := initBackend(withLocal)
|
b := initBackend(withLocal)
|
||||||
|
|
||||||
txA := pricedSetCodeTx(0, 250000, uint256.NewInt(params.GWei), uint256.NewInt(params.GWei), key, []unsignedAuth{
|
txA := pricedSetCodeTx(0, 250000, uint256.NewInt(params.GWei), uint256.NewInt(params.GWei), key, []unsignedAuth{{nonce: 0, key: key}})
|
||||||
{
|
if err := b.SendTx(context.Background(), txA); err != nil {
|
||||||
nonce: 0,
|
t.Fatalf("Failed to submit tx: %v", err)
|
||||||
key: key,
|
}
|
||||||
},
|
for {
|
||||||
})
|
pending, _ := b.TxPool().ContentFrom(address)
|
||||||
b.SendTx(context.Background(), txA)
|
if len(pending) == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
txB := makeTx(1, nil, nil, key)
|
txB := makeTx(1, nil, nil, key)
|
||||||
err := b.SendTx(context.Background(), txB)
|
err := b.SendTx(context.Background(), txB)
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,13 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe
|
||||||
return eth.pathState(block)
|
return eth.pathState(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
// stateAtTransaction returns the execution environment of a certain
|
||||||
|
// transaction.
|
||||||
|
//
|
||||||
|
// Note: when a block is empty and the state for tx index 0 is requested, this
|
||||||
|
// function will return the state of block after the pre-block operations have
|
||||||
|
// been completed (e.g. updating system contracts), but before post-block
|
||||||
|
// operations are completed (e.g. processing withdrawals).
|
||||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
|
|
@ -245,7 +251,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||||
return nil, vm.BlockContext{}, statedb, release, nil
|
return nil, context, statedb, release, nil
|
||||||
}
|
}
|
||||||
// Recompute transactions up to the target index.
|
// Recompute transactions up to the target index.
|
||||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
|
signer := types.MakeSigner(eth.blockchain.Config(), block.Number(), block.Time())
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,8 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
|
||||||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||||
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
|
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
|
||||||
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
|
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
|
||||||
gasPriceBig, err := t.toBig(t.vm, tx.EffectiveGasTipValue(env.BaseFee).String())
|
gasTip, _ := tx.EffectiveGasTip(env.BaseFee)
|
||||||
|
gasPriceBig, err := t.toBig(t.vm, gasTip.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.err = err
|
t.err = err
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -55,24 +56,35 @@ const (
|
||||||
// Apart from basic data storage functionality it also supports batch writes and
|
// Apart from basic data storage functionality it also supports batch writes and
|
||||||
// iterating over the keyspace in binary-alphabetical order.
|
// iterating over the keyspace in binary-alphabetical order.
|
||||||
type Database struct {
|
type Database struct {
|
||||||
fn string // filename for reporting
|
fn string // filename for reporting
|
||||||
db *pebble.DB // Underlying pebble storage engine
|
db *pebble.DB // Underlying pebble storage engine
|
||||||
|
namespace string // Namespace for metrics
|
||||||
|
|
||||||
compTimeMeter *metrics.Meter // Meter for measuring the total time spent in database compaction
|
compTimeMeter *metrics.Meter // Meter for measuring the total time spent in database compaction
|
||||||
compReadMeter *metrics.Meter // Meter for measuring the data read during compaction
|
compReadMeter *metrics.Meter // Meter for measuring the data read during compaction
|
||||||
compWriteMeter *metrics.Meter // Meter for measuring the data written during compaction
|
compWriteMeter *metrics.Meter // Meter for measuring the data written during compaction
|
||||||
writeDelayNMeter *metrics.Meter // Meter for measuring the write delay number due to database compaction
|
writeDelayNMeter *metrics.Meter // Meter for measuring the write delay number due to database compaction
|
||||||
writeDelayMeter *metrics.Meter // Meter for measuring the write delay duration due to database compaction
|
writeDelayMeter *metrics.Meter // Meter for measuring the write delay duration due to database compaction
|
||||||
diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database
|
diskSizeGauge *metrics.Gauge // Gauge for tracking the size of all the levels in the database
|
||||||
diskReadMeter *metrics.Meter // Meter for measuring the effective amount of data read
|
diskReadMeter *metrics.Meter // Meter for measuring the effective amount of data read
|
||||||
diskWriteMeter *metrics.Meter // Meter for measuring the effective amount of data written
|
diskWriteMeter *metrics.Meter // Meter for measuring the effective amount of data written
|
||||||
memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction
|
memCompGauge *metrics.Gauge // Gauge for tracking the number of memory compaction
|
||||||
level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0
|
level0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in level0
|
||||||
nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
|
nonlevel0CompGauge *metrics.Gauge // Gauge for tracking the number of table compaction in non0 level
|
||||||
seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
|
seekCompGauge *metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
|
||||||
manualMemAllocGauge *metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
|
manualMemAllocGauge *metrics.Gauge // Gauge for tracking amount of non-managed memory currently allocated
|
||||||
|
liveMemTablesGauge *metrics.Gauge // Gauge for tracking the number of live memory tables
|
||||||
levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels
|
zombieMemTablesGauge *metrics.Gauge // Gauge for tracking the number of zombie memory tables
|
||||||
|
blockCacheHitGauge *metrics.Gauge // Gauge for tracking the number of total hit in the block cache
|
||||||
|
blockCacheMissGauge *metrics.Gauge // Gauge for tracking the number of total miss in the block cache
|
||||||
|
tableCacheHitGauge *metrics.Gauge // Gauge for tracking the number of total hit in the table cache
|
||||||
|
tableCacheMissGauge *metrics.Gauge // Gauge for tracking the number of total miss in the table cache
|
||||||
|
filterHitGauge *metrics.Gauge // Gauge for tracking the number of total hit in bloom filter
|
||||||
|
filterMissGauge *metrics.Gauge // Gauge for tracking the number of total miss in bloom filter
|
||||||
|
estimatedCompDebtGauge *metrics.Gauge // Gauge for tracking the number of bytes that need to be compacted
|
||||||
|
liveCompGauge *metrics.Gauge // Gauge for tracking the number of in-progress compactions
|
||||||
|
liveCompSizeGauge *metrics.Gauge // Gauge for tracking the size of in-progress compactions
|
||||||
|
levelsGauge []*metrics.Gauge // Gauge for tracking the number of tables in levels
|
||||||
|
|
||||||
quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
|
quitLock sync.RWMutex // Mutex protecting the quit channel and the closed flag
|
||||||
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
|
||||||
|
|
@ -88,6 +100,7 @@ type Database struct {
|
||||||
|
|
||||||
writeStalled atomic.Bool // Flag whether the write is stalled
|
writeStalled atomic.Bool // Flag whether the write is stalled
|
||||||
writeDelayStartTime time.Time // The start time of the latest write stall
|
writeDelayStartTime time.Time // The start time of the latest write stall
|
||||||
|
writeDelayReason string // The reason of the latest write stall
|
||||||
writeDelayCount atomic.Int64 // Total number of write stall counts
|
writeDelayCount atomic.Int64 // Total number of write stall counts
|
||||||
writeDelayTime atomic.Int64 // Total time spent in write stalls
|
writeDelayTime atomic.Int64 // Total time spent in write stalls
|
||||||
|
|
||||||
|
|
@ -120,11 +133,30 @@ func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) {
|
||||||
d.writeDelayStartTime = time.Now()
|
d.writeDelayStartTime = time.Now()
|
||||||
d.writeDelayCount.Add(1)
|
d.writeDelayCount.Add(1)
|
||||||
d.writeStalled.Store(true)
|
d.writeStalled.Store(true)
|
||||||
|
|
||||||
|
// Take just the first word of the reason. These are two potential
|
||||||
|
// reasons for the write stall:
|
||||||
|
// - memtable count limit reached
|
||||||
|
// - L0 file count limit exceeded
|
||||||
|
reason := b.Reason
|
||||||
|
if i := strings.IndexByte(reason, ' '); i != -1 {
|
||||||
|
reason = reason[:i]
|
||||||
|
}
|
||||||
|
if reason == "L0" || reason == "memtable" {
|
||||||
|
d.writeDelayReason = reason
|
||||||
|
metrics.GetOrRegisterGauge(d.namespace+"stall/count/"+reason, nil).Inc(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) onWriteStallEnd() {
|
func (d *Database) onWriteStallEnd() {
|
||||||
d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime)))
|
d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime)))
|
||||||
d.writeStalled.Store(false)
|
d.writeStalled.Store(false)
|
||||||
|
|
||||||
|
if d.writeDelayReason != "" {
|
||||||
|
metrics.GetOrRegisterResettingTimer(d.namespace+"stall/time/"+d.writeDelayReason, nil).UpdateSince(d.writeDelayStartTime)
|
||||||
|
d.writeDelayReason = ""
|
||||||
|
}
|
||||||
|
d.writeDelayStartTime = time.Time{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// panicLogger is just a noop logger to disable Pebble's internal logger.
|
// panicLogger is just a noop logger to disable Pebble's internal logger.
|
||||||
|
|
@ -270,6 +302,17 @@ func New(file string, cache int, handles int, namespace string, readonly bool) (
|
||||||
db.nonlevel0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/nonlevel0", nil)
|
db.nonlevel0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/nonlevel0", nil)
|
||||||
db.seekCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/seek", nil)
|
db.seekCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/seek", nil)
|
||||||
db.manualMemAllocGauge = metrics.GetOrRegisterGauge(namespace+"memory/manualalloc", nil)
|
db.manualMemAllocGauge = metrics.GetOrRegisterGauge(namespace+"memory/manualalloc", nil)
|
||||||
|
db.liveMemTablesGauge = metrics.GetOrRegisterGauge(namespace+"table/live", nil)
|
||||||
|
db.zombieMemTablesGauge = metrics.GetOrRegisterGauge(namespace+"table/zombie", nil)
|
||||||
|
db.blockCacheHitGauge = metrics.GetOrRegisterGauge(namespace+"cache/block/hit", nil)
|
||||||
|
db.blockCacheMissGauge = metrics.GetOrRegisterGauge(namespace+"cache/block/miss", nil)
|
||||||
|
db.tableCacheHitGauge = metrics.GetOrRegisterGauge(namespace+"cache/table/hit", nil)
|
||||||
|
db.tableCacheMissGauge = metrics.GetOrRegisterGauge(namespace+"cache/table/miss", nil)
|
||||||
|
db.filterHitGauge = metrics.GetOrRegisterGauge(namespace+"filter/hit", nil)
|
||||||
|
db.filterMissGauge = metrics.GetOrRegisterGauge(namespace+"filter/miss", nil)
|
||||||
|
db.estimatedCompDebtGauge = metrics.GetOrRegisterGauge(namespace+"compact/estimateDebt", nil)
|
||||||
|
db.liveCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/live/count", nil)
|
||||||
|
db.liveCompSizeGauge = metrics.GetOrRegisterGauge(namespace+"compact/live/size", nil)
|
||||||
|
|
||||||
// Start up the metrics gathering and return
|
// Start up the metrics gathering and return
|
||||||
go db.meter(metricsGatheringInterval, namespace)
|
go db.meter(metricsGatheringInterval, namespace)
|
||||||
|
|
@ -517,6 +560,18 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
||||||
d.nonlevel0CompGauge.Update(nonLevel0CompCount)
|
d.nonlevel0CompGauge.Update(nonLevel0CompCount)
|
||||||
d.level0CompGauge.Update(level0CompCount)
|
d.level0CompGauge.Update(level0CompCount)
|
||||||
d.seekCompGauge.Update(stats.Compact.ReadCount)
|
d.seekCompGauge.Update(stats.Compact.ReadCount)
|
||||||
|
d.liveCompGauge.Update(stats.Compact.NumInProgress)
|
||||||
|
d.liveCompSizeGauge.Update(stats.Compact.InProgressBytes)
|
||||||
|
|
||||||
|
d.liveMemTablesGauge.Update(stats.MemTable.Count)
|
||||||
|
d.zombieMemTablesGauge.Update(stats.MemTable.ZombieCount)
|
||||||
|
d.estimatedCompDebtGauge.Update(int64(stats.Compact.EstimatedDebt))
|
||||||
|
d.tableCacheHitGauge.Update(stats.TableCache.Hits)
|
||||||
|
d.tableCacheMissGauge.Update(stats.TableCache.Misses)
|
||||||
|
d.blockCacheHitGauge.Update(stats.BlockCache.Hits)
|
||||||
|
d.blockCacheMissGauge.Update(stats.BlockCache.Misses)
|
||||||
|
d.filterHitGauge.Update(stats.Filter.Hits)
|
||||||
|
d.filterMissGauge.Update(stats.Filter.Misses)
|
||||||
|
|
||||||
for i, level := range stats.Levels {
|
for i, level := range stats.Levels {
|
||||||
// Append metrics for additional layers
|
// Append metrics for additional layers
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -16,7 +16,6 @@ require (
|
||||||
github.com/consensys/gnark-crypto v0.16.0
|
github.com/consensys/gnark-crypto v0.16.0
|
||||||
github.com/crate-crypto/go-eth-kzg v1.3.0
|
github.com/crate-crypto/go-eth-kzg v1.3.0
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.1.0
|
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set/v2 v2.6.0
|
github.com/deckarep/golang-set/v2 v2.6.0
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -84,8 +84,6 @@ github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg
|
||||||
github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
|
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ func (tt *TestCmd) Kill() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt *TestCmd) withKillTimeout(fn func()) {
|
func (tt *TestCmd) withKillTimeout(fn func()) {
|
||||||
timeout := time.AfterFunc(30*time.Second, func() {
|
timeout := time.AfterFunc(2*time.Minute, func() {
|
||||||
tt.Log("killing the child process (timeout)")
|
tt.Log("killing the child process (timeout)")
|
||||||
tt.Kill()
|
tt.Kill()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type hasher struct {
|
||||||
|
|
||||||
// hasherPool holds pureHashers
|
// hasherPool holds pureHashers
|
||||||
var hasherPool = sync.Pool{
|
var hasherPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() any {
|
||||||
return &hasher{
|
return &hasher{
|
||||||
tmp: make([]byte, 0, 550), // cap is as large as a full fullNode.
|
tmp: make([]byte, 0, 550), // cap is as large as a full fullNode.
|
||||||
sha: crypto.NewKeccakState(),
|
sha: crypto.NewKeccakState(),
|
||||||
|
|
|
||||||
24
trie/sync.go
24
trie/sync.go
|
|
@ -729,9 +729,7 @@ func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists
|
||||||
} else {
|
} else {
|
||||||
blob = rawdb.ReadStorageTrieNode(s.database, owner, path)
|
blob = rawdb.ReadStorageTrieNode(s.database, owner, path)
|
||||||
}
|
}
|
||||||
h := newBlobHasher()
|
exists = hash == crypto.Keccak256Hash(blob)
|
||||||
defer h.release()
|
|
||||||
exists = hash == h.hash(blob)
|
|
||||||
inconsistent = !exists && len(blob) != 0
|
inconsistent = !exists && len(blob) != 0
|
||||||
return exists, inconsistent
|
return exists, inconsistent
|
||||||
}
|
}
|
||||||
|
|
@ -746,23 +744,3 @@ func ResolvePath(path []byte) (common.Hash, []byte) {
|
||||||
}
|
}
|
||||||
return owner, path
|
return owner, path
|
||||||
}
|
}
|
||||||
|
|
||||||
// blobHasher is used to compute the sha256 hash of the provided data.
|
|
||||||
type blobHasher struct{ state crypto.KeccakState }
|
|
||||||
|
|
||||||
// blobHasherPool is the pool for reusing pre-allocated hash state.
|
|
||||||
var blobHasherPool = sync.Pool{
|
|
||||||
New: func() interface{} { return &blobHasher{state: crypto.NewKeccakState()} },
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBlobHasher() *blobHasher {
|
|
||||||
return blobHasherPool.Get().(*blobHasher)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *blobHasher) hash(data []byte) common.Hash {
|
|
||||||
return crypto.HashData(h.state, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *blobHasher) release() {
|
|
||||||
blobHasherPool.Put(h)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,12 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
|
||||||
dirtyNodeMissMeter.Mark(1)
|
dirtyNodeMissMeter.Mark(1)
|
||||||
|
|
||||||
// Try to retrieve the trie node from the clean memory cache
|
// Try to retrieve the trie node from the clean memory cache
|
||||||
h := newHasher()
|
|
||||||
defer h.release()
|
|
||||||
|
|
||||||
key := nodeCacheKey(owner, path)
|
key := nodeCacheKey(owner, path)
|
||||||
if dl.nodes != nil {
|
if dl.nodes != nil {
|
||||||
if blob := dl.nodes.Get(nil, key); len(blob) > 0 {
|
if blob := dl.nodes.Get(nil, key); len(blob) > 0 {
|
||||||
cleanNodeHitMeter.Mark(1)
|
cleanNodeHitMeter.Mark(1)
|
||||||
cleanNodeReadMeter.Mark(int64(len(blob)))
|
cleanNodeReadMeter.Mark(int64(len(blob)))
|
||||||
return blob, h.hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil
|
return blob, crypto.Keccak256Hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil
|
||||||
}
|
}
|
||||||
cleanNodeMissMeter.Mark(1)
|
cleanNodeMissMeter.Mark(1)
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +135,7 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
|
||||||
dl.nodes.Set(key, blob)
|
dl.nodes.Set(key, blob)
|
||||||
cleanNodeWriteMeter.Mark(int64(len(blob)))
|
cleanNodeWriteMeter.Mark(int64(len(blob)))
|
||||||
}
|
}
|
||||||
return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil
|
return blob, crypto.Keccak256Hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// account directly retrieves the account RLP associated with a particular
|
// account directly retrieves the account RLP associated with a particular
|
||||||
|
|
@ -231,6 +228,8 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
|
||||||
oldest uint64
|
oldest uint64
|
||||||
)
|
)
|
||||||
if dl.db.freezer != nil {
|
if dl.db.freezer != nil {
|
||||||
|
// Bail out with an error if writing the state history fails.
|
||||||
|
// This can happen, for example, if the device is full.
|
||||||
err := writeHistory(dl.db.freezer, bottom)
|
err := writeHistory(dl.db.freezer, bottom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -357,22 +356,3 @@ func (dl *diskLayer) resetCache() {
|
||||||
dl.nodes.Reset()
|
dl.nodes.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasher is used to compute the sha256 hash of the provided data.
|
|
||||||
type hasher struct{ sha crypto.KeccakState }
|
|
||||||
|
|
||||||
var hasherPool = sync.Pool{
|
|
||||||
New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} },
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHasher() *hasher {
|
|
||||||
return hasherPool.Get().(*hasher)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hasher) hash(data []byte) common.Hash {
|
|
||||||
return crypto.HashData(h.sha, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hasher) release() {
|
|
||||||
hasherPool.Put(h)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
|
@ -85,10 +86,9 @@ func apply(db database.NodeDatabase, prevRoot common.Hash, postRoot common.Hash,
|
||||||
func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) error {
|
func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) error {
|
||||||
// The account was present in prev-state, decode it from the
|
// The account was present in prev-state, decode it from the
|
||||||
// 'slim-rlp' format bytes.
|
// 'slim-rlp' format bytes.
|
||||||
h := newHasher()
|
h := crypto.NewKeccakState()
|
||||||
defer h.release()
|
|
||||||
|
|
||||||
addrHash := h.hash(addr.Bytes())
|
addrHash := crypto.HashData(h, addr.Bytes())
|
||||||
prev, err := types.FullAccount(ctx.accounts[addr])
|
prev, err := types.FullAccount(ctx.accounts[addr])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -113,7 +113,7 @@ func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address)
|
||||||
for key, val := range ctx.storages[addr] {
|
for key, val := range ctx.storages[addr] {
|
||||||
tkey := key
|
tkey := key
|
||||||
if ctx.rawStorageKey {
|
if ctx.rawStorageKey {
|
||||||
tkey = h.hash(key.Bytes())
|
tkey = crypto.HashData(h, key.Bytes())
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if len(val) == 0 {
|
if len(val) == 0 {
|
||||||
|
|
@ -149,10 +149,9 @@ func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address)
|
||||||
// account and storage is wiped out correctly.
|
// account and storage is wiped out correctly.
|
||||||
func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address) error {
|
func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address) error {
|
||||||
// The account must be existent in post-state, load the account.
|
// The account must be existent in post-state, load the account.
|
||||||
h := newHasher()
|
h := crypto.NewKeccakState()
|
||||||
defer h.release()
|
|
||||||
|
|
||||||
addrHash := h.hash(addr.Bytes())
|
addrHash := crypto.HashData(h, addr.Bytes())
|
||||||
blob, err := ctx.accountTrie.Get(addrHash.Bytes())
|
blob, err := ctx.accountTrie.Get(addrHash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -174,7 +173,7 @@ func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address)
|
||||||
}
|
}
|
||||||
tkey := key
|
tkey := key
|
||||||
if ctx.rawStorageKey {
|
if ctx.rawStorageKey {
|
||||||
tkey = h.hash(key.Bytes())
|
tkey = crypto.HashData(h, key.Bytes())
|
||||||
}
|
}
|
||||||
if err := st.Delete(tkey.Bytes()); err != nil {
|
if err := st.Delete(tkey.Bytes()); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -542,8 +542,9 @@ func writeHistory(writer ethdb.AncientWriter, dl *diffLayer) error {
|
||||||
indexSize := common.StorageSize(len(accountIndex) + len(storageIndex))
|
indexSize := common.StorageSize(len(accountIndex) + len(storageIndex))
|
||||||
|
|
||||||
// Write history data into five freezer table respectively.
|
// Write history data into five freezer table respectively.
|
||||||
rawdb.WriteStateHistory(writer, dl.stateID(), history.meta.encode(), accountIndex, storageIndex, accountData, storageData)
|
if err := rawdb.WriteStateHistory(writer, dl.stateID(), history.meta.encode(), accountIndex, storageIndex, accountData, storageData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
historyDataBytesMeter.Mark(int64(dataSize))
|
historyDataBytesMeter.Mark(int64(dataSize))
|
||||||
historyIndexBytesMeter.Mark(int64(indexSize))
|
historyIndexBytesMeter.Mark(int64(indexSize))
|
||||||
historyBuildTimeMeter.UpdateSince(start)
|
historyBuildTimeMeter.UpdateSince(start)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ var (
|
||||||
nodeDiskFalseMeter = metrics.NewRegisteredMeter("pathdb/disk/false", nil)
|
nodeDiskFalseMeter = metrics.NewRegisteredMeter("pathdb/disk/false", nil)
|
||||||
nodeDiffFalseMeter = metrics.NewRegisteredMeter("pathdb/diff/false", nil)
|
nodeDiffFalseMeter = metrics.NewRegisteredMeter("pathdb/diff/false", nil)
|
||||||
|
|
||||||
commitTimeTimer = metrics.NewRegisteredTimer("pathdb/commit/time", nil)
|
commitTimeTimer = metrics.NewRegisteredResettingTimer("pathdb/commit/time", nil)
|
||||||
commitNodesMeter = metrics.NewRegisteredMeter("pathdb/commit/nodes", nil)
|
commitNodesMeter = metrics.NewRegisteredMeter("pathdb/commit/nodes", nil)
|
||||||
commitBytesMeter = metrics.NewRegisteredMeter("pathdb/commit/bytes", nil)
|
commitBytesMeter = metrics.NewRegisteredMeter("pathdb/commit/bytes", nil)
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ var (
|
||||||
gcStorageMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/count", nil)
|
gcStorageMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/count", nil)
|
||||||
gcStorageBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/bytes", nil)
|
gcStorageBytesMeter = metrics.NewRegisteredMeter("pathdb/gc/storage/bytes", nil)
|
||||||
|
|
||||||
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
|
historyBuildTimeMeter = metrics.NewRegisteredResettingTimer("pathdb/history/time", nil)
|
||||||
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
|
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
|
||||||
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
|
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue