mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
core: fix cross validation
This commit is contained in:
parent
d57dca07b1
commit
a2496465f9
3 changed files with 45 additions and 44 deletions
|
|
@ -2225,38 +2225,9 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
|||
}
|
||||
vtime := time.Since(vstart)
|
||||
|
||||
// If witnesses was generated and stateless self-validation requested, do
|
||||
// that now. Self validation should *never* run in production, it's more of
|
||||
// a tight integration to enable running *all* consensus tests through the
|
||||
// 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 && 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
|
||||
context := block.Header()
|
||||
context.Root = common.Hash{}
|
||||
context.ReceiptHash = common.Hash{}
|
||||
|
||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
||||
|
||||
// Run the stateless self-cross-validation
|
||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, task, witness)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
||||
}
|
||||
if crossStateRoot != block.Root() {
|
||||
return nil, fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
|
||||
}
|
||||
if crossReceiptRoot != block.ReceiptHash() {
|
||||
return nil, fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
proctime = time.Since(startTime) // processing + validation + cross validation
|
||||
stats = NewExecuteStats(statedb, ptime, vtime, time.Since(xvstart))
|
||||
stats = NewExecuteStats(statedb, ptime, vtime)
|
||||
)
|
||||
// Write the block to the chain and get the status.
|
||||
var status WriteStatus
|
||||
|
|
@ -2284,6 +2255,9 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
|||
stats.TotalTime = elapsed
|
||||
stats.MgasPerSecond = float64(res.GasUsed) * 1000 / float64(elapsed)
|
||||
|
||||
if config.StatelessSelfValidation {
|
||||
bc.crossValidation(ctx, statedb, block)
|
||||
}
|
||||
return &blockProcessingResult{
|
||||
usedGas: res.GasUsed,
|
||||
procTime: proctime,
|
||||
|
|
@ -2293,6 +2267,39 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (bc *BlockChain) crossValidation(ctx context.Context, statedb *state.StateDB, block *types.Block) error {
|
||||
// If witnesses was generated and stateless self-validation requested, do
|
||||
// that now. Self validation should *never* run in production, it's more of
|
||||
// a tight integration to enable running *all* consensus tests through the
|
||||
// witness builder/runner, which would otherwise be impossible due to the
|
||||
// various invalid chain states/behaviors being contained in those tests.
|
||||
if witness := statedb.Witness(); witness != nil {
|
||||
xvstart := time.Now()
|
||||
log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash())
|
||||
|
||||
// Remove critical computed fields from the block to force true recalculation
|
||||
context := block.Header()
|
||||
context.Root = common.Hash{}
|
||||
context.ReceiptHash = common.Hash{}
|
||||
|
||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
||||
|
||||
// Run the stateless self-cross-validation
|
||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(ctx, bc.chainConfig, bc.cfg.VmConfig, task, witness)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stateless self-validation failed: %v", err)
|
||||
}
|
||||
if crossStateRoot != block.Root() {
|
||||
return fmt.Errorf("stateless self-validation root mismatch (cross: %x local: %x)", crossStateRoot, block.Root())
|
||||
}
|
||||
if crossReceiptRoot != block.ReceiptHash() {
|
||||
return fmt.Errorf("stateless self-validation receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, block.ReceiptHash())
|
||||
}
|
||||
blockCrossValidationTimer.UpdateSince(xvstart)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// insertSideChain is called when an import batch hits upon a pruned ancestor
|
||||
// error, which happens when a sidechain with a sufficiently old fork-block is
|
||||
// found.
|
||||
|
|
|
|||
|
|
@ -38,12 +38,9 @@ type ExecuteStats struct {
|
|||
AccountUpdates time.Duration // Time spent on the account trie update
|
||||
StorageUpdates time.Duration // Time spent on the storage trie update
|
||||
|
||||
// EVM execution time
|
||||
Execution time.Duration // Time spent on the EVM execution
|
||||
|
||||
// Validation times
|
||||
Validation time.Duration // Time spent on the block validation
|
||||
CrossValidation time.Duration // Optional, time spent on the block cross validation
|
||||
// EVM execution and validation time
|
||||
Execution time.Duration // Time spent on the EVM execution
|
||||
Validation time.Duration // Time spent on the block validation
|
||||
|
||||
// Commit times
|
||||
HasherCommit time.Duration // Time spent on trie commit
|
||||
|
|
@ -70,7 +67,7 @@ type ExecuteStats struct {
|
|||
StatePrefetchCacheStats state.ReaderStats
|
||||
}
|
||||
|
||||
func NewExecuteStats(stateDB *state.StateDB, process time.Duration, validation time.Duration, crossValidation time.Duration) *ExecuteStats {
|
||||
func NewExecuteStats(stateDB *state.StateDB, process time.Duration, validation time.Duration) *ExecuteStats {
|
||||
return &ExecuteStats{
|
||||
// State read times
|
||||
AccountReads: stateDB.AccountReads,
|
||||
|
|
@ -82,9 +79,8 @@ func NewExecuteStats(stateDB *state.StateDB, process time.Duration, validation t
|
|||
AccountUpdates: stateDB.AccountUpdates,
|
||||
StorageUpdates: stateDB.StorageUpdates,
|
||||
|
||||
Execution: process - stateDB.StateReadTime(),
|
||||
Validation: validation - stateDB.StateHashTime(),
|
||||
CrossValidation: crossValidation,
|
||||
Execution: process - stateDB.StateReadTime(),
|
||||
Validation: validation - stateDB.StateHashTime(),
|
||||
|
||||
AccountLoaded: stateDB.AccountLoaded,
|
||||
AccountUpdated: stateDB.AccountUpdated,
|
||||
|
|
@ -121,7 +117,6 @@ func (s *ExecuteStats) reportMetrics() {
|
|||
|
||||
blockExecutionTimer.Update(s.Execution) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(s.Validation) // The time spent on block validation
|
||||
blockCrossValidationTimer.Update(s.CrossValidation) // The time spent on stateless cross validation
|
||||
triedbCommitTimer.Update(s.DatabaseCommit) // Trie database commits are complete, we can mark them
|
||||
blockWriteTimer.Update(s.BlockWrite) // The time spent on block write
|
||||
blockInsertTimer.Update(s.TotalTime) // The total time spent on block execution
|
||||
|
|
|
|||
|
|
@ -1020,11 +1020,10 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorag
|
|||
}
|
||||
s.DatabaseCommits = time.Since(start)
|
||||
|
||||
// The reader update must be performed as the final step, otherwise,
|
||||
// the new state would not be visible before db.commit.
|
||||
// The reader/hasher update must be performed as the final step
|
||||
s.reader, _ = s.db.Reader(s.originalRoot)
|
||||
s.hasher, _ = s.db.Hasher(s.originalRoot)
|
||||
return ret, err
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Commit writes the state mutations into the configured data stores.
|
||||
|
|
|
|||
Loading…
Reference in a new issue