|
18 | 18 | package core |
19 | 19 |
|
20 | 20 | import ( |
| 21 | + "context" |
21 | 22 | "errors" |
22 | 23 | "fmt" |
23 | 24 | "io" |
@@ -233,6 +234,15 @@ type BlockChainConfig struct { |
233 | 234 |
|
234 | 235 | // EnableBAL enables the block access list feature |
235 | 236 | EnableBAL bool |
| 237 | + |
| 238 | + // SlowBlockThreshold is the block execution time threshold beyond which |
| 239 | + // detailed statistics will be logged. Negative value means disabled (default), |
| 240 | + // zero logs all blocks, positive value filters blocks by execution time. |
| 241 | + SlowBlockThreshold time.Duration |
| 242 | + |
| 243 | + // Execution configs |
| 244 | + StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) |
| 245 | + EnableWitnessStats bool // Whether trie access statistics collection is enabled |
236 | 246 | } |
237 | 247 |
|
238 | 248 | // DefaultConfig returns the default config. |
@@ -2404,7 +2414,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness |
2404 | 2414 | bc.updateHighestVerifiedHeader(block.Header()) |
2405 | 2415 | // The traced section of block import. |
2406 | 2416 | start := time.Now() |
2407 | | - res, err := bc.ProcessBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1) |
| 2417 | + config := ExecuteConfig{ |
| 2418 | + WriteState: true, |
| 2419 | + WriteHead: setHead, |
| 2420 | + EnableTracer: true, |
| 2421 | + MakeWitness: makeWitness && len(chain) == 1, |
| 2422 | + StatelessSelfValidation: bc.cfg.StatelessSelfValidation, |
| 2423 | + EnableWitnessStats: bc.cfg.EnableWitnessStats, |
| 2424 | + } |
| 2425 | + res, err := bc.ProcessBlock(context.Background(), parent.Root, block, config) |
2408 | 2426 | if err != nil { |
2409 | 2427 | return nil, it.index, err |
2410 | 2428 | } |
@@ -2507,9 +2525,36 @@ func (bpr *blockProcessingResult) Witness() *stateless.Witness { |
2507 | 2525 | return bpr.witness |
2508 | 2526 | } |
2509 | 2527 |
|
| 2528 | +// ExecuteConfig defines optional behaviors during execution. |
| 2529 | +type ExecuteConfig struct { |
| 2530 | + // WriteState controls whether the computed state changes are persisted to |
| 2531 | + // the underlying storage. If false, execution is performed in-memory only. |
| 2532 | + WriteState bool |
| 2533 | + |
| 2534 | + // WriteHead indicates whether the execution result should update the canonical |
| 2535 | + // chain head. It's only relevant with WriteState == True. |
| 2536 | + WriteHead bool |
| 2537 | + |
| 2538 | + // EnableTracer enables execution tracing. This is typically used for debugging |
| 2539 | + // or analysis and may significantly impact performance. |
| 2540 | + EnableTracer bool |
| 2541 | + |
| 2542 | + // MakeWitness indicates whether to generate execution witness data during |
| 2543 | + // execution. Enabling this may introduce additional memory and CPU overhead. |
| 2544 | + MakeWitness bool |
| 2545 | + |
| 2546 | + // StatelessSelfValidation indicates whether the execution witnesses generation |
| 2547 | + // and self-validation (testing purpose) is enabled. |
| 2548 | + StatelessSelfValidation bool |
| 2549 | + |
| 2550 | + // EnableWitnessStats indicates whether to enable collection of witness trie |
| 2551 | + // access statistics |
| 2552 | + EnableWitnessStats bool |
| 2553 | +} |
| 2554 | + |
2510 | 2555 | // ProcessBlock executes and validates the given block. If there was no error |
2511 | 2556 | // it writes the block and associated state to database. |
2512 | | -func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) { |
| 2557 | +func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash, block *types.Block, config ExecuteConfig) (result *blockProcessingResult, blockEndErr error) { |
2513 | 2558 | var ( |
2514 | 2559 | err error |
2515 | 2560 | startTime = time.Now() |
@@ -2587,32 +2632,35 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s |
2587 | 2632 | // Generate witnesses either if we're self-testing, or if it's the |
2588 | 2633 | // only block being inserted. A bit crude, but witnesses are huge, |
2589 | 2634 | // so we refuse to make an entire chain of them. |
2590 | | - if bc.cfg.VmConfig.StatelessSelfValidation || makeWitness { |
| 2635 | + if config.StatelessSelfValidation || config.MakeWitness { |
2591 | 2636 | witness, err = stateless.NewWitness(block.Header(), bc) |
2592 | 2637 | if err != nil { |
2593 | 2638 | return nil, err |
2594 | 2639 | } |
2595 | | - if bc.cfg.VmConfig.EnableWitnessStats { |
| 2640 | + if config.EnableWitnessStats { |
2596 | 2641 | witnessStats = stateless.NewWitnessStats() |
2597 | 2642 | } |
2598 | 2643 | } |
2599 | 2644 | statedb.StartPrefetcher("chain", witness, witnessStats) |
2600 | 2645 | defer statedb.StopPrefetcher() |
2601 | 2646 | } |
2602 | 2647 |
|
2603 | | - if bc.logger != nil && bc.logger.OnBlockStart != nil { |
2604 | | - td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) |
2605 | | - bc.logger.OnBlockStart(tracing.BlockEvent{ |
2606 | | - Block: block, |
2607 | | - TD: td, |
2608 | | - Finalized: bc.CurrentFinalBlock(), |
2609 | | - Safe: bc.CurrentSafeBlock(), |
2610 | | - }) |
2611 | | - } |
2612 | | - if bc.logger != nil && bc.logger.OnBlockEnd != nil { |
2613 | | - defer func() { |
2614 | | - bc.logger.OnBlockEnd(blockEndErr) |
2615 | | - }() |
| 2648 | + // Instrument the blockchain tracing |
| 2649 | + if config.EnableTracer { |
| 2650 | + if bc.logger != nil && bc.logger.OnBlockStart != nil { |
| 2651 | + td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) |
| 2652 | + bc.logger.OnBlockStart(tracing.BlockEvent{ |
| 2653 | + Block: block, |
| 2654 | + TD: td, |
| 2655 | + Finalized: bc.CurrentFinalBlock(), |
| 2656 | + Safe: bc.CurrentSafeBlock(), |
| 2657 | + }) |
| 2658 | + } |
| 2659 | + if bc.logger != nil && bc.logger.OnBlockEnd != nil { |
| 2660 | + defer func() { |
| 2661 | + bc.logger.OnBlockEnd(blockEndErr) |
| 2662 | + }() |
| 2663 | + } |
2616 | 2664 | } |
2617 | 2665 |
|
2618 | 2666 | // Process block using the parent state as reference point |
@@ -2640,7 +2688,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s |
2640 | 2688 | // witness builder/runner, which would otherwise be impossible due to the |
2641 | 2689 | // various invalid chain states/behaviors being contained in those tests. |
2642 | 2690 | xvstart := time.Now() |
2643 | | - if witness := statedb.Witness(); witness != nil && bc.cfg.VmConfig.StatelessSelfValidation { |
| 2691 | + if witness := statedb.Witness(); witness != nil && config.StatelessSelfValidation { |
2644 | 2692 | log.Warn("Running stateless self-validation", "block", block.Number(), "hash", block.Hash()) |
2645 | 2693 |
|
2646 | 2694 | // Remove critical computed fields from the block to force true recalculation |
@@ -2685,30 +2733,29 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s |
2685 | 2733 | blockCrossValidationTimer.Update(xvtime) // The time spent on stateless cross validation |
2686 | 2734 |
|
2687 | 2735 | // Write the block to the chain and get the status. |
2688 | | - var ( |
2689 | | - wstart = time.Now() |
2690 | | - status WriteStatus |
2691 | | - ) |
2692 | | - if !setHead { |
2693 | | - // Don't set the head, only insert the block |
2694 | | - err = bc.writeBlockWithState(block, res.Receipts, statedb) |
2695 | | - } else { |
2696 | | - status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, nil) |
2697 | | - } |
2698 | | - if err != nil { |
2699 | | - return nil, err |
| 2736 | + var status WriteStatus |
| 2737 | + if config.WriteState { |
| 2738 | + wstart := time.Now() |
| 2739 | + if !config.WriteHead { |
| 2740 | + // Don't set the head, only insert the block |
| 2741 | + err = bc.writeBlockWithState(block, res.Receipts, statedb) |
| 2742 | + } else { |
| 2743 | + status, err = bc.writeBlockAndSetHead(block, res.Receipts, res.Logs, statedb, nil) |
| 2744 | + } |
| 2745 | + if err != nil { |
| 2746 | + return nil, err |
| 2747 | + } |
| 2748 | + // Update the metrics touched during block commit |
| 2749 | + accountCommitTimer.Update(statedb.AccountCommits) |
| 2750 | + storageCommitTimer.Update(statedb.StorageCommits) |
| 2751 | + snapshotCommitTimer.Update(statedb.SnapshotCommits) |
| 2752 | + triedbCommitTimer.Update(statedb.TrieDBCommits) |
| 2753 | + blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) |
2700 | 2754 | } |
2701 | 2755 | // Report the collected witness statistics |
2702 | 2756 | if witnessStats != nil { |
2703 | 2757 | witnessStats.ReportMetrics(block.NumberU64()) |
2704 | 2758 | } |
2705 | | - |
2706 | | - // Update the metrics touched during block commit |
2707 | | - accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them |
2708 | | - storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them |
2709 | | - snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them |
2710 | | - triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them |
2711 | | - blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits) |
2712 | 2759 | elapsed := time.Since(startTime) + 1 // prevent zero division |
2713 | 2760 | blockInsertTimer.Update(elapsed) |
2714 | 2761 | blockInsertTxSizeGauge.Update(int64(len(block.Transactions()))) |
|
0 commit comments