mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-06 03:15:03 +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{
|
||||
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 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.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name) || ctx.Bool(VMWitnessStatsFlag.Name)
|
||||
options.EnableWitnessStats = ctx.Bool(VMWitnessStatsFlag.Name)
|
||||
|
||||
chain, err := core.NewBlockChain(chainDb, gspec, engine, options)
|
||||
if err != nil {
|
||||
Fatalf("Can't create BlockChain: %v", err)
|
||||
|
|
|
|||
|
|
@ -219,6 +219,10 @@ type BlockChainConfig struct {
|
|||
// detailed statistics will be logged. Negative value means disabled (default),
|
||||
// zero logs all blocks, positive value filters blocks by execution time.
|
||||
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.
|
||||
|
|
@ -1990,7 +1994,15 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, setHe
|
|||
}
|
||||
// The traced section of block import.
|
||||
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 {
|
||||
return nil, it.index, err
|
||||
}
|
||||
|
|
@ -2073,9 +2085,36 @@ func (bpr *blockProcessingResult) Stats() *ExecuteStats {
|
|||
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
|
||||
// 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 (
|
||||
err error
|
||||
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
|
||||
// only block being inserted. A bit crude, but witnesses are huge,
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bc.cfg.VmConfig.EnableWitnessStats {
|
||||
if config.EnableWitnessStats {
|
||||
witnessStats = stateless.NewWitnessStats()
|
||||
}
|
||||
}
|
||||
|
|
@ -2151,17 +2190,20 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
|||
defer statedb.StopPrefetcher()
|
||||
}
|
||||
|
||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||
bc.logger.OnBlockStart(tracing.BlockEvent{
|
||||
Block: block,
|
||||
Finalized: bc.CurrentFinalBlock(),
|
||||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
}
|
||||
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
|
||||
defer func() {
|
||||
bc.logger.OnBlockEnd(blockEndErr)
|
||||
}()
|
||||
// Instrument the blockchain tracing
|
||||
if config.EnableTracer {
|
||||
if bc.logger != nil && bc.logger.OnBlockStart != nil {
|
||||
bc.logger.OnBlockStart(tracing.BlockEvent{
|
||||
Block: block,
|
||||
Finalized: bc.CurrentFinalBlock(),
|
||||
Safe: bc.CurrentSafeBlock(),
|
||||
})
|
||||
}
|
||||
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
|
||||
defer func() {
|
||||
bc.logger.OnBlockEnd(blockEndErr)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// various invalid chain states/behaviors being contained in those tests.
|
||||
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())
|
||||
|
||||
// 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
|
||||
|
||||
// Write the block to the chain and get the status.
|
||||
var (
|
||||
wstart = time.Now()
|
||||
status WriteStatus
|
||||
)
|
||||
if !setHead {
|
||||
// Don't set the head, only insert the block
|
||||
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var status WriteStatus
|
||||
if config.WriteState {
|
||||
wstart := time.Now()
|
||||
if !config.WriteHead {
|
||||
// Don't set the head, only insert the block
|
||||
err = bc.writeBlockWithState(block, res.Receipts, statedb)
|
||||
} else {
|
||||
status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, false)
|
||||
}
|
||||
if err != nil {
|
||||
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
|
||||
if witnessStats != nil {
|
||||
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
|
||||
stats.TotalTime = elapsed
|
||||
stats.MgasPerSecond = float64(res.GasUsed) * 1000 / float64(elapsed)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,11 @@ import (
|
|||
|
||||
// Config are the configuration options for the Interpreter
|
||||
type Config struct {
|
||||
Tracer *tracing.Hooks
|
||||
Tracer *tracing.Hooks
|
||||
|
||||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
|
|
@ -493,34 +494,22 @@ func (api *DebugAPI) StateSize(blockHashOrNumber *rpc.BlockNumberOrHash) (interf
|
|||
}, 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
|
||||
block, err := api.eth.APIBackend.BlockByNumber(context.Background(), bn)
|
||||
block, err := api.eth.APIBackend.BlockByNumberOrHash(context.Background(), bn)
|
||||
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)
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Witness().ToExtWitness(), nil
|
||||
}
|
||||
|
||||
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)
|
||||
config := core.ExecuteConfig{
|
||||
WriteState: false,
|
||||
EnableTracer: false,
|
||||
MakeWitness: true,
|
||||
}
|
||||
result, err := bc.ProcessBlock(context.Background(), parent.Root, block, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,8 +237,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
TxLookupLimit: int64(min(config.TransactionHistory, math.MaxInt64)),
|
||||
VmConfig: vm.Config{
|
||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||
EnableWitnessStats: config.EnableWitnessStats,
|
||||
StatelessSelfValidation: config.StatelessSelfValidation,
|
||||
},
|
||||
// Enables file journaling for the trie database. The journal files will be stored
|
||||
// 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"),
|
||||
StateSizeTracking: config.EnableStateSizeTracking,
|
||||
SlowBlockThreshold: config.SlowBlockThreshold,
|
||||
|
||||
StatelessSelfValidation: config.StatelessSelfValidation,
|
||||
EnableWitnessStats: config.EnableWitnessStats,
|
||||
}
|
||||
)
|
||||
if config.VMTrace != "" {
|
||||
|
|
|
|||
|
|
@ -427,11 +427,6 @@ web3._extend({
|
|||
params: 2,
|
||||
inputFormatter:[null, null],
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'freezeClient',
|
||||
call: 'debug_freezeClient',
|
||||
params: 1,
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'getAccessibleState',
|
||||
call: 'debug_getAccessibleState',
|
||||
|
|
@ -474,6 +469,12 @@ web3._extend({
|
|||
params: 1,
|
||||
inputFormatter: [null],
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'executionWitness',
|
||||
call: 'debug_executionWitness',
|
||||
params: 1,
|
||||
inputFormatter: [null],
|
||||
}),
|
||||
],
|
||||
properties: []
|
||||
});
|
||||
|
|
|
|||
|
|
@ -161,9 +161,9 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *t
|
|||
Preimages: true,
|
||||
TxLookupLimit: -1, // disable tx indexing
|
||||
VmConfig: vm.Config{
|
||||
Tracer: tracer,
|
||||
StatelessSelfValidation: witness,
|
||||
Tracer: tracer,
|
||||
},
|
||||
StatelessSelfValidation: witness,
|
||||
}
|
||||
if snapshotter {
|
||||
options.SnapshotLimit = 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue