Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions crates/optimism/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ struct Args {
value_parser = humantime::parse_duration
)]
pub proofs_history_prune_interval: Duration,
/// Verification interval: perform full block execution every N blocks for data integrity.
/// - 0: Disabled (Default) (always use fast path with pre-computed data from notifications)
/// - 1: Always verify (always execute blocks, slowest)
/// - N: Verify every Nth block (e.g., 100 = every 100 blocks)
///
/// Periodic verification helps catch data corruption or consensus bugs while maintaining
/// good performance.
///
/// CLI: `--proofs-history.verification-interval 100`
#[arg(
long = "proofs-history.verification-interval",
value_name = "PROOFS_HISTORY_VERIFICATION_INTERVAL",
default_value_t = 0
)]
pub proofs_history_verification_interval: u64,
}

/// Single entry that handles:
Expand All @@ -91,6 +106,7 @@ async fn launch_node(
let rollup_args = args.rollup_args.clone();
let proofs_history_window = args.proofs_history_window;
let proofs_history_prune_interval = args.proofs_history_prune_interval;
let proofs_history_verification_interval = args.proofs_history_verification_interval;

// Start from a plain OpNode builder
let mut node_builder = builder.node(OpNode::new(rollup_args));
Expand Down Expand Up @@ -125,6 +141,7 @@ async fn launch_node(
storage_exec,
proofs_history_window,
proofs_history_prune_interval,
proofs_history_verification_interval,
)
.run()
.boxed())
Expand Down
1 change: 0 additions & 1 deletion crates/optimism/exex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ alloy-eips.workspace = true
# misc
eyre.workspace = true
futures-util.workspace = true
derive_more.workspace = true
tracing.workspace = true

[dev-dependencies]
Expand Down
72 changes: 58 additions & 14 deletions crates/optimism/exex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

use alloy_consensus::BlockHeader;
use alloy_eips::eip1898::BlockWithParent;
use derive_more::Constructor;
use futures_util::TryStreamExt;
use reth_execution_types::Chain;
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
Expand Down Expand Up @@ -72,6 +71,10 @@ const MAX_PRUNE_BLOCKS_STARTUP: u64 = 1000;
/// let storage_exec = storage.clone();
/// let proofs_history_window = 1_296_000u64;
/// let proofs_history_prune_interval = Duration::from_secs(3600);
///
/// // Verification interval: perform full execution every N blocks
/// let verification_interval = 0; // 0 = disabled, 100 = verify every 100 blocks
///
/// // Can also use install_exex_if along with a boolean flag
/// // Set this based on your configuration or CLI args
/// let _builder = NodeBuilder::new(config)
Expand All @@ -84,14 +87,15 @@ const MAX_PRUNE_BLOCKS_STARTUP: u64 = 1000;
/// storage_exec,
/// proofs_history_window,
/// proofs_history_prune_interval,
/// verification_interval, // 0 = no verification, 100 = every 100 blocks
/// )
/// .run()
/// .boxed())
/// })
/// .on_node_started(|_full_node| Ok(()))
/// .check_launch();
/// ```
#[derive(Debug, Constructor)]
#[derive(Debug)]
pub struct OpProofsExEx<Node, Storage>
where
Node: FullNodeComponents,
Expand All @@ -106,6 +110,32 @@ where
proofs_history_window: u64,
/// Interval between proof-storage prune runs
proofs_history_prune_interval: Duration,
/// Verification interval: perform full block execution every N blocks for data integrity.
/// If 0, verification is disabled (always use fast path when available).
/// If 1, verification is always enabled (always execute blocks).
verification_interval: u64,
}

impl<Node, Storage> OpProofsExEx<Node, Storage>
where
Node: FullNodeComponents,
{
/// Create a new `OpProofsExEx` instance.
pub const fn new(
ctx: ExExContext<Node>,
storage: OpProofsStorage<Storage>,
proofs_history_window: u64,
proofs_history_prune_interval: Duration,
verification_interval: u64,
Comment on lines +127 to +129
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about making a new type OpProofsConfig

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will add any value as we will be using it only in this file.

) -> Self {
Self {
ctx,
storage,
proofs_history_window,
proofs_history_prune_interval,
verification_interval,
}
}
}

impl<Node, Storage, Primitives> OpProofsExEx<Node, Storage>
Expand Down Expand Up @@ -266,6 +296,10 @@ where
chain: &Chain<Primitives>,
collector: &LiveTrieCollector<'_, Node::Evm, Node::Provider, Storage>,
) -> eyre::Result<()> {
// Check if this block should be verified via full execution
let should_verify = self.verification_interval > 0 &&
block_number.is_multiple_of(self.verification_interval);

// Try to get block data from the chain first
// 1. Fast Path: Try to use pre-computed state from the notification
if let Some(block) = chain.blocks().get(&block_number) {
Expand All @@ -274,21 +308,31 @@ where
if let (Some(trie_updates), Some(hashed_state)) =
(chain.trie_updates_at(block_number), chain.hashed_state_at(block_number))
{
debug!(
// Use fast path only if we're not scheduled to verify this block
if !should_verify {
debug!(
target: "optimism::exex",
block_number,
"Using pre-computed state updates from notification"
);

collector
.store_block_updates(
block.block_with_parent(),
(**trie_updates).clone(),
(**hashed_state).clone(),
)
.await?;

return Ok(());
}

info!(
target: "optimism::exex",
block_number,
"Using pre-computed state updates from notification"
verification_interval = self.verification_interval,
"Periodic verification: performing full block execution"
);

collector
.store_block_updates(
block.block_with_parent(),
(**trie_updates).clone(),
(**hashed_state).clone(),
)
.await?;

return Ok(());
}

debug!(
Expand Down
9 changes: 9 additions & 0 deletions docs/vocs/docs/pages/cli/op-reth/node.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,15 @@ Rollup:

[default: 15s]

--proofs-history.verification-interval <PROOFS_HISTORY_VERIFICATION_INTERVAL>
Verification interval: perform full block execution every N blocks for data integrity. - 0: Disabled (Default) (always use fast path with pre-computed data from notifications) - 1: Always verify (always execute blocks, slowest) - N: Verify every Nth block (e.g., 100 = every 100 blocks)

Periodic verification helps catch data corruption or consensus bugs while maintaining good performance.

CLI: `--proofs-history.verification-interval 100`

[default: 0]

Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout
Expand Down
Loading