mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-21 15:29:27 +00:00
cmd, core, eth, tests: prevent state flushing in RPC (#33931)
Fixes https://github.com/ethereum/go-ethereum/issues/33572
This commit is contained in:
parent
fe3a74e610
commit
6d99759f01
7 changed files with 103 additions and 73 deletions
|
|
@ -2475,8 +2475,6 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
}
|
}
|
||||||
vmcfg := vm.Config{
|
vmcfg := vm.Config{
|
||||||
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
||||||
EnableWitnessStats: ctx.Bool(VMWitnessStatsFlag.Name),
|
|
||||||
StatelessSelfValidation: ctx.Bool(VMStatelessSelfValidationFlag.Name) || ctx.Bool(VMWitnessStatsFlag.Name),
|
|
||||||
}
|
}
|
||||||
if ctx.IsSet(VMTraceFlag.Name) {
|
if ctx.IsSet(VMTraceFlag.Name) {
|
||||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||||
|
|
@ -2490,6 +2488,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
}
|
}
|
||||||
options.VmConfig = vmcfg
|
options.VmConfig = vmcfg
|
||||||
|
|
||||||
|
options.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name) || ctx.Bool(VMWitnessStatsFlag.Name)
|
||||||
|
options.EnableWitnessStats = ctx.Bool(VMWitnessStatsFlag.Name)
|
||||||
|
|
||||||
chain, err := core.NewBlockChain(chainDb, gspec, engine, options)
|
chain, err := core.NewBlockChain(chainDb, gspec, engine, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,10 @@ type BlockChainConfig struct {
|
||||||
// detailed statistics will be logged. Negative value means disabled (default),
|
// detailed statistics will be logged. Negative value means disabled (default),
|
||||||
// zero logs all blocks, positive value filters blocks by execution time.
|
// zero logs all blocks, positive value filters blocks by execution time.
|
||||||
SlowBlockThreshold time.Duration
|
SlowBlockThreshold time.Duration
|
||||||
|
|
||||||
|
// Execution configs
|
||||||
|
StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose)
|
||||||
|
EnableWitnessStats bool // Whether trie access statistics collection is enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConfig returns the default config.
|
// DefaultConfig returns the default config.
|
||||||
|
|
@ -1990,7 +1994,15 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, setHe
|
||||||
}
|
}
|
||||||
// The traced section of block import.
|
// The traced section of block import.
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
res, err := bc.ProcessBlock(ctx, parent.Root, block, setHead, makeWitness && len(chain) == 1)
|
config := ExecuteConfig{
|
||||||
|
WriteState: true,
|
||||||
|
WriteHead: setHead,
|
||||||
|
EnableTracer: true,
|
||||||
|
MakeWitness: makeWitness && len(chain) == 1,
|
||||||
|
StatelessSelfValidation: bc.cfg.StatelessSelfValidation,
|
||||||
|
EnableWitnessStats: bc.cfg.EnableWitnessStats,
|
||||||
|
}
|
||||||
|
res, err := bc.ProcessBlock(ctx, parent.Root, block, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, it.index, err
|
return nil, it.index, err
|
||||||
}
|
}
|
||||||
|
|
@ -2073,9 +2085,36 @@ func (bpr *blockProcessingResult) Stats() *ExecuteStats {
|
||||||
return bpr.stats
|
return bpr.stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecuteConfig defines optional behaviors during execution.
|
||||||
|
type ExecuteConfig struct {
|
||||||
|
// WriteState controls whether the computed state changes are persisted to
|
||||||
|
// the underlying storage. If false, execution is performed in-memory only.
|
||||||
|
WriteState bool
|
||||||
|
|
||||||
|
// WriteHead indicates whether the execution result should update the canonical
|
||||||
|
// chain head. It's only relevant with WriteState == True.
|
||||||
|
WriteHead bool
|
||||||
|
|
||||||
|
// EnableTracer enables execution tracing. This is typically used for debugging
|
||||||
|
// or analysis and may significantly impact performance.
|
||||||
|
EnableTracer bool
|
||||||
|
|
||||||
|
// MakeWitness indicates whether to generate execution witness data during
|
||||||
|
// execution. Enabling this may introduce additional memory and CPU overhead.
|
||||||
|
MakeWitness bool
|
||||||
|
|
||||||
|
// StatelessSelfValidation indicates whether the execution witnesses generation
|
||||||
|
// and self-validation (testing purpose) is enabled.
|
||||||
|
StatelessSelfValidation bool
|
||||||
|
|
||||||
|
// EnableWitnessStats indicates whether to enable collection of witness trie
|
||||||
|
// access statistics
|
||||||
|
EnableWitnessStats bool
|
||||||
|
}
|
||||||
|
|
||||||
// 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(ctx context.Context, parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (result *blockProcessingResult, blockEndErr error) {
|
func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash, block *types.Block, config ExecuteConfig) (result *blockProcessingResult, blockEndErr error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
|
|
@ -2138,12 +2177,12 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
// Generate witnesses either if we're self-testing, or if it's the
|
// Generate witnesses either if we're self-testing, or if it's the
|
||||||
// only block being inserted. A bit crude, but witnesses are huge,
|
// only block being inserted. A bit crude, but witnesses are huge,
|
||||||
// so we refuse to make an entire chain of them.
|
// so we refuse to make an entire chain of them.
|
||||||
if bc.cfg.VmConfig.StatelessSelfValidation || makeWitness {
|
if config.StatelessSelfValidation || config.MakeWitness {
|
||||||
witness, err = stateless.NewWitness(block.Header(), bc)
|
witness, err = stateless.NewWitness(block.Header(), bc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if bc.cfg.VmConfig.EnableWitnessStats {
|
if config.EnableWitnessStats {
|
||||||
witnessStats = stateless.NewWitnessStats()
|
witnessStats = stateless.NewWitnessStats()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2151,17 +2190,20 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
defer statedb.StopPrefetcher()
|
defer statedb.StopPrefetcher()
|
||||||
}
|
}
|
||||||
|
|
||||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
// Instrument the blockchain tracing
|
||||||
bc.logger.OnBlockStart(tracing.BlockEvent{
|
if config.EnableTracer {
|
||||||
Block: block,
|
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||||
Finalized: bc.CurrentFinalBlock(),
|
bc.logger.OnBlockStart(tracing.BlockEvent{
|
||||||
Safe: bc.CurrentSafeBlock(),
|
Block: block,
|
||||||
})
|
Finalized: bc.CurrentFinalBlock(),
|
||||||
}
|
Safe: bc.CurrentSafeBlock(),
|
||||||
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
|
})
|
||||||
defer func() {
|
}
|
||||||
bc.logger.OnBlockEnd(blockEndErr)
|
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
|
||||||
}()
|
defer func() {
|
||||||
|
bc.logger.OnBlockEnd(blockEndErr)
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process block using the parent state as reference point
|
// Process block using the parent state as reference point
|
||||||
|
|
@ -2191,7 +2233,7 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
// witness builder/runner, which would otherwise be impossible due to the
|
// witness builder/runner, which would otherwise be impossible due to the
|
||||||
// various invalid chain states/behaviors being contained in those tests.
|
// various invalid chain states/behaviors being contained in those tests.
|
||||||
xvstart := time.Now()
|
xvstart := time.Now()
|
||||||
if witness := statedb.Witness(); witness != nil && bc.cfg.VmConfig.StatelessSelfValidation {
|
if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation {
|
||||||
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
||||||
|
|
||||||
// Remove critical computed fields from the block to force true recalculation
|
// Remove critical computed fields from the block to force true recalculation
|
||||||
|
|
@ -2244,31 +2286,29 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
||||||
stats.CrossValidation = xvtime // The time spent on stateless cross validation
|
stats.CrossValidation = xvtime // The time spent on stateless cross validation
|
||||||
|
|
||||||
// Write the block to the chain and get the status.
|
// Write the block to the chain and get the status.
|
||||||
var (
|
var status WriteStatus
|
||||||
wstart = time.Now()
|
if config.WriteState {
|
||||||
status WriteStatus
|
wstart := time.Now()
|
||||||
)
|
if !config.WriteHead {
|
||||||
if !setHead {
|
// Don't set the head, only insert the block
|
||||||
// Don't set the head, only insert the block
|
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
||||||
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
} else {
|
||||||
} else {
|
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||||
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
}
|
||||||
}
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
|
// Update the metrics touched during block commit
|
||||||
|
stats.AccountCommits = statedb.AccountCommits // Account commits are complete, we can mark them
|
||||||
|
stats.StorageCommits = statedb.StorageCommits // Storage commits are complete, we can mark them
|
||||||
|
stats.SnapshotCommit = statedb.SnapshotCommits // Snapshot commits are complete, we can mark them
|
||||||
|
stats.TrieDBCommit = statedb.TrieDBCommits // Trie database commits are complete, we can mark them
|
||||||
|
stats.BlockWrite = time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits
|
||||||
}
|
}
|
||||||
// Report the collected witness statistics
|
// Report the collected witness statistics
|
||||||
if witnessStats != nil {
|
if witnessStats != nil {
|
||||||
witnessStats.ReportMetrics(block.NumberU64())
|
witnessStats.ReportMetrics(block.NumberU64())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the metrics touched during block commit
|
|
||||||
stats.AccountCommits = statedb.AccountCommits // Account commits are complete, we can mark them
|
|
||||||
stats.StorageCommits = statedb.StorageCommits // Storage commits are complete, we can mark them
|
|
||||||
stats.SnapshotCommit = statedb.SnapshotCommits // Snapshot commits are complete, we can mark them
|
|
||||||
stats.TrieDBCommit = statedb.TrieDBCommits // Trie database commits are complete, we can mark them
|
|
||||||
stats.BlockWrite = time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits
|
|
||||||
|
|
||||||
elapsed := time.Since(startTime) + 1 // prevent zero division
|
elapsed := time.Since(startTime) + 1 // prevent zero division
|
||||||
stats.TotalTime = elapsed
|
stats.TotalTime = elapsed
|
||||||
stats.MgasPerSecond = float64(res.GasUsed) * 1000 / float64(elapsed)
|
stats.MgasPerSecond = float64(res.GasUsed) * 1000 / float64(elapsed)
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,11 @@ import (
|
||||||
|
|
||||||
// Config are the configuration options for the Interpreter
|
// Config are the configuration options for the Interpreter
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Tracer *tracing.Hooks
|
Tracer *tracing.Hooks
|
||||||
|
|
||||||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||||
ExtraEips []int // Additional EIPS that are to be enabled
|
ExtraEips []int // Additional EIPS that are to be enabled
|
||||||
|
|
||||||
StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose)
|
|
||||||
EnableWitnessStats bool // Whether trie access statistics collection is enabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScopeContext contains the things that are per-call, such as stack and memory,
|
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/stateless"
|
"github.com/ethereum/go-ethereum/core/stateless"
|
||||||
|
|
@ -493,34 +494,22 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumber) (*stateless.ExtWitness, error) {
|
func (api *DebugAPI) ExecutionWitness(bn rpc.BlockNumberOrHash) (*stateless.ExtWitness, error) {
|
||||||
bc := api.eth.blockchain
|
bc := api.eth.blockchain
|
||||||
block, err := api.eth.APIBackend.BlockByNumber(context.Background(), bn)
|
block, err := api.eth.APIBackend.BlockByNumberOrHash(context.Background(), bn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %v not found", bn)
|
return &stateless.ExtWitness{}, fmt.Errorf("block %v not found", bn)
|
||||||
}
|
}
|
||||||
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %v found, but parent missing", bn)
|
return &stateless.ExtWitness{}, fmt.Errorf("block %v found, but parent missing", bn)
|
||||||
}
|
}
|
||||||
result, err := bc.ProcessBlock(context.Background(), parent.Root, block, false, true)
|
config := core.ExecuteConfig{
|
||||||
if err != nil {
|
WriteState: false,
|
||||||
return nil, err
|
EnableTracer: false,
|
||||||
}
|
MakeWitness: true,
|
||||||
return result.Witness().ToExtWitness(), nil
|
}
|
||||||
}
|
result, err := bc.ProcessBlock(context.Background(), parent.Root, block, config)
|
||||||
|
|
||||||
func (api *DebugAPI) ExecutionWitnessByHash(hash common.Hash) (*stateless.ExtWitness, error) {
|
|
||||||
bc := api.eth.blockchain
|
|
||||||
block := bc.GetBlockByHash(hash)
|
|
||||||
if block == nil {
|
|
||||||
return &stateless.ExtWitness{}, fmt.Errorf("block hash %x not found", hash)
|
|
||||||
}
|
|
||||||
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
|
||||||
if parent == nil {
|
|
||||||
return &stateless.ExtWitness{}, fmt.Errorf("block number %x found, but parent missing", hash)
|
|
||||||
}
|
|
||||||
result, err := bc.ProcessBlock(context.Background(), parent.Root, block, false, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)),
|
TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)),
|
||||||
VmConfig: vm.Config{
|
VmConfig: vm.Config{
|
||||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||||
EnableWitnessStats: config.EnableWitnessStats,
|
|
||||||
StatelessSelfValidation: config.StatelessSelfValidation,
|
|
||||||
},
|
},
|
||||||
// Enables file journaling for the trie database. The journal files will be stored
|
// Enables file journaling for the trie database. The journal files will be stored
|
||||||
// within the data directory. The corresponding paths will be either:
|
// within the data directory. The corresponding paths will be either:
|
||||||
|
|
@ -247,6 +245,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
TrieJournalDirectory: stack.ResolvePath("triedb"),
|
TrieJournalDirectory: stack.ResolvePath("triedb"),
|
||||||
StateSizeTracking: config.EnableStateSizeTracking,
|
StateSizeTracking: config.EnableStateSizeTracking,
|
||||||
SlowBlockThreshold: config.SlowBlockThreshold,
|
SlowBlockThreshold: config.SlowBlockThreshold,
|
||||||
|
|
||||||
|
StatelessSelfValidation: config.StatelessSelfValidation,
|
||||||
|
EnableWitnessStats: config.EnableWitnessStats,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if config.VMTrace != "" {
|
if config.VMTrace != "" {
|
||||||
|
|
|
||||||
|
|
@ -427,11 +427,6 @@ web3._extend({
|
||||||
params: 2,
|
params: 2,
|
||||||
inputFormatter:[null, null],
|
inputFormatter:[null, null],
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'freezeClient',
|
|
||||||
call: 'debug_freezeClient',
|
|
||||||
params: 1,
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'getAccessibleState',
|
name: 'getAccessibleState',
|
||||||
call: 'debug_getAccessibleState',
|
call: 'debug_getAccessibleState',
|
||||||
|
|
@ -474,6 +469,12 @@ web3._extend({
|
||||||
params: 1,
|
params: 1,
|
||||||
inputFormatter: [null],
|
inputFormatter: [null],
|
||||||
}),
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'executionWitness',
|
||||||
|
call: 'debug_executionWitness',
|
||||||
|
params: 1,
|
||||||
|
inputFormatter: [null],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
properties: []
|
properties: []
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -161,9 +161,9 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
|
||||||
Preimages: true,
|
Preimages: true,
|
||||||
TxLookupLimit: -1, // disable tx indexing
|
TxLookupLimit: -1, // disable tx indexing
|
||||||
VmConfig: vm.Config{
|
VmConfig: vm.Config{
|
||||||
Tracer: tracer,
|
Tracer: tracer,
|
||||||
StatelessSelfValidation: witness,
|
|
||||||
},
|
},
|
||||||
|
StatelessSelfValidation: witness,
|
||||||
}
|
}
|
||||||
if snapshotter {
|
if snapshotter {
|
||||||
options.SnapshotLimit = 1
|
options.SnapshotLimit = 1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue