From fb8b28fcedf0bc1c45f784934b9adac367e72dc4 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 14 Nov 2025 12:27:09 +0100 Subject: [PATCH] feat: add --skip-invalid-blocks (#19750) --- crates/cli/commands/src/re_execute.rs | 59 +++++++++++++++++--- docs/vocs/docs/pages/cli/reth/re-execute.mdx | 3 + 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/crates/cli/commands/src/re_execute.rs b/crates/cli/commands/src/re_execute.rs index 3fda706913..eda3c0f0b5 100644 --- a/crates/cli/commands/src/re_execute.rs +++ b/crates/cli/commands/src/re_execute.rs @@ -44,6 +44,10 @@ pub struct Command { /// Number of tasks to run in parallel #[arg(long, default_value = "10")] num_tasks: u64, + + /// Continues with execution when an invalid block is encountered and collects these blocks. + #[arg(long)] + skip_invalid_blocks: bool, } impl Command { @@ -95,7 +99,9 @@ impl } }; + let skip_invalid_blocks = self.skip_invalid_blocks; let (stats_tx, mut stats_rx) = mpsc::unbounded_channel(); + let (info_tx, mut info_rx) = mpsc::unbounded_channel(); let mut tasks = JoinSet::new(); for i in 0..self.num_tasks { @@ -109,20 +115,34 @@ impl let consensus = components.consensus().clone(); let db_at = db_at.clone(); let stats_tx = stats_tx.clone(); + let info_tx = info_tx.clone(); tasks.spawn_blocking(move || { let mut executor = evm_config.batch_executor(db_at(start_block - 1)); let mut executor_created = Instant::now(); let executor_lifetime = Duration::from_secs(120); - for block in start_block..end_block { + 'blocks: for block in start_block..end_block { let block = provider_factory .recovered_block(block.into(), TransactionVariant::NoHash)? .unwrap(); - let result = executor.execute_one(&block)?; + + let result = match executor.execute_one(&block) { + Ok(result) => result, + Err(err) => { + if skip_invalid_blocks { + executor = evm_config.batch_executor(db_at(block.number())); + let _ = info_tx.send((block, eyre::Report::new(err))); + continue + } + return Err(err.into()) + } + }; if let Err(err) = consensus .validate_block_post_execution(&block, &result) - .wrap_err_with(|| format!("Failed to validate block {}", block.number())) + .wrap_err_with(|| { + format!("Failed to validate block {} {}", block.number(), block.hash()) + }) { let correct_receipts = provider_factory.receipts_by_block(block.number().into())?.unwrap(); @@ -158,6 +178,11 @@ impl }; error!(number=?block.number(), ?mismatch, "Gas usage mismatch"); + if skip_invalid_blocks { + executor = evm_config.batch_executor(db_at(block.number())); + let _ = info_tx.send((block, err)); + continue 'blocks; + } return Err(err); } } else { @@ -189,6 +214,7 @@ impl let mut last_logged_gas = 0; let mut last_logged_blocks = 0; let mut last_logged_time = Instant::now(); + let mut invalid_blocks = Vec::new(); let mut interval = tokio::time::interval(Duration::from_secs(10)); @@ -199,6 +225,10 @@ impl total_executed_blocks += 1; total_executed_gas += gas_used; } + Some((block, err)) = info_rx.recv() => { + error!(?err, block=?block.num_hash(), "Invalid block"); + invalid_blocks.push(block.num_hash()); + } result = tasks.join_next() => { if let Some(result) = result { if matches!(result, Err(_) | Ok(Err(_))) { @@ -229,12 +259,23 @@ impl } } - info!( - start_block = min_block, - end_block = max_block, - throughput=?format_gas_throughput(total_executed_gas, instant.elapsed()), - "Re-executed successfully" - ); + if invalid_blocks.is_empty() { + info!( + start_block = min_block, + end_block = max_block, + throughput=?format_gas_throughput(total_executed_gas, instant.elapsed()), + "Re-executed successfully" + ); + } else { + info!( + start_block = min_block, + end_block = max_block, + invalid_block_count = invalid_blocks.len(), + ?invalid_blocks, + throughput=?format_gas_throughput(total_executed_gas, instant.elapsed()), + "Re-executed with invalid blocks" + ); + } Ok(()) } diff --git a/docs/vocs/docs/pages/cli/reth/re-execute.mdx b/docs/vocs/docs/pages/cli/reth/re-execute.mdx index d178a7f4c1..b51a66c7ac 100644 --- a/docs/vocs/docs/pages/cli/reth/re-execute.mdx +++ b/docs/vocs/docs/pages/cli/reth/re-execute.mdx @@ -116,6 +116,9 @@ Static Files: [default: 10] + --skip-invalid-blocks + Continues with execution when an invalid block is encountered and collects these blocks + Logging: --log.stdout.format The format to use for logs written to stdout