Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
10d9ed5
Include state root calculation time in metering
niran Oct 28, 2025
1bedee4
Update tips-core and expose state root time in RPC response
niran Oct 28, 2025
b209cf4
Add tests for state root time metrics
niran Oct 28, 2025
d661038
Simplify state root calculation by removing unnecessary ExecutionOutc…
niran Oct 28, 2025
ff175a0
Use pending flashblocks state for bundle metering
niran Oct 29, 2025
2f4a2cd
Cache flashblock trie nodes to optimize bundle metering
niran Oct 30, 2025
b2554b9
linter fixes
niran Oct 30, 2025
9b0ec97
Rename total_execution_time to total_time for clarity
niran Nov 9, 2025
082e7d5
Refactor flashblock trie data handling to reduce code duplication
niran Nov 10, 2025
4b92ed6
Add chain-state metering tests and flashblock harness support
niran Nov 11, 2025
345819c
Fix chain-state metering tests with L1 deposit
niran Nov 11, 2025
b2898d6
Restore beacon root for successful metering tests
niran Nov 11, 2025
aff49c8
Have storage persistence test meter the next block
niran Nov 11, 2025
8e7a429
Rename metering tests for clarity
niran Nov 11, 2025
d0cadbd
Document why flashblock trie caching isolates bundle I/O
niran Nov 17, 2025
ec9cfff
Move build_single_flashblock from metering to test-utils
niran Nov 17, 2025
093f062
tweak comments
niran Nov 17, 2025
408c563
Update tips-core and fix metering harness/tests
niran Nov 25, 2025
fb21f0b
Silence the global executor errors
niran Nov 26, 2025
d82c612
Add TODO for state_root_time
niran Nov 26, 2025
00e05c1
Add metrics for bundle state clone cost
niran Nov 26, 2025
19045ba
Add database layering tests to flashblocks-rpc
niran Nov 26, 2025
d833760
Add tests for flashblock state visibility
niran Nov 27, 2025
906e492
just fix
niran Nov 27, 2025
8e88f61
Fix build issues after rebase
niran Dec 22, 2025
fa5ec8c
Fix clippy warnings and apply nightly fmt
niran Dec 22, 2025
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
531 changes: 271 additions & 260 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ base-reth-test-utils = { path = "crates/test-utils" }
base-reth-flashblocks = { path = "crates/flashblocks" }

# base/tips
tips-core = { git = "https://github.com/base/tips", rev = "b1dfde6a5c8f603f19f9309ca6dc015bad260b44" }
# Note: default-features = false avoids version conflicts with reth's alloy/op-alloy dependencies
tips-core = { git = "https://github.com/base/tips", rev = "c08eaa4fe10c26de8911609b41ddab4918698325", default-features = false }

# reth
reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
Expand Down Expand Up @@ -91,10 +92,12 @@ reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth", tag =
reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", features = [
"op",
] }
reth-trie-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }

# revm
revm = { version = "31.0.2", default-features = false }
revm-bytecode = { version = "7.1.1", default-features = false }
revm-database = { version = "9.0.6", default-features = false }

# alloy
alloy-trie = "0.9.1"
Expand Down
4 changes: 4 additions & 0 deletions crates/flashblocks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ reth-optimism-evm.workspace = true
reth-optimism-chainspec.workspace = true
reth-optimism-primitives.workspace = true

# revm
revm-database.workspace = true

# alloy
alloy-eips.workspace = true
alloy-provider.workspace = true
Expand Down Expand Up @@ -57,6 +60,7 @@ metrics-derive.workspace = true

[dev-dependencies]
rand.workspace = true
revm.workspace = true
reth-db.workspace = true
once_cell.workspace = true
reth-provider.workspace = true
Expand Down
8 changes: 8 additions & 0 deletions crates/flashblocks/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,12 @@ pub struct Metrics {
/// Total number of WebSocket reconnection attempts.
#[metric(describe = "Total number of WebSocket reconnection attempts")]
pub reconnect_attempts: Counter,

/// Time taken to clone bundle state.
#[metric(describe = "Time taken to clone bundle state")]
pub bundle_state_clone_duration: Histogram,

/// Size of bundle state being cloned (number of accounts).
#[metric(describe = "Size of bundle state being cloned (number of accounts)")]
pub bundle_state_clone_size: Histogram,
}
35 changes: 32 additions & 3 deletions crates/flashblocks/src/pending_blocks.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{sync::Arc, time::Instant};

use alloy_consensus::{Header, Sealed};
use alloy_eips::BlockNumberOrTag;
Expand All @@ -14,11 +14,14 @@ use base_flashtypes::Flashblock;
use eyre::eyre;
use op_alloy_network::Optimism;
use op_alloy_rpc_types::{OpTransactionReceipt, Transaction};
use reth::revm::{db::Cache, state::EvmState};
use reth::revm::{
db::{BundleState, Cache},
state::EvmState,
};
use reth_rpc_convert::RpcTransaction;
use reth_rpc_eth_api::{RpcBlock, RpcReceipt};

use crate::PendingBlocksAPI;
use crate::{Metrics, PendingBlocksAPI};

/// Builder for [`PendingBlocks`].
#[derive(Debug)]
Expand All @@ -36,6 +39,7 @@ pub struct PendingBlocksBuilder {
state_overrides: Option<StateOverride>,

db_cache: Cache,
bundle_state: BundleState,
}

impl PendingBlocksBuilder {
Expand All @@ -52,6 +56,7 @@ impl PendingBlocksBuilder {
transaction_senders: HashMap::new(),
state_overrides: None,
db_cache: Cache::default(),
bundle_state: BundleState::default(),
}
}

Expand Down Expand Up @@ -122,6 +127,12 @@ impl PendingBlocksBuilder {
self
}

#[inline]
pub(crate) fn with_bundle_state(&mut self, bundle_state: BundleState) -> &Self {
self.bundle_state = bundle_state;
self
}

pub(crate) fn build(self) -> eyre::Result<PendingBlocks> {
if self.headers.is_empty() {
return Err(eyre!("missing headers"));
Expand All @@ -143,6 +154,7 @@ impl PendingBlocksBuilder {
transaction_senders: self.transaction_senders,
state_overrides: self.state_overrides,
db_cache: self.db_cache,
bundle_state: self.bundle_state,
})
}
}
Expand All @@ -163,6 +175,7 @@ pub struct PendingBlocks {
state_overrides: Option<StateOverride>,

db_cache: Cache,
bundle_state: BundleState,
}

impl PendingBlocks {
Expand Down Expand Up @@ -211,6 +224,22 @@ impl PendingBlocks {
self.db_cache.clone()
}

/// Returns a clone of the bundle state.
///
/// NOTE: This clones the entire BundleState, which contains a HashMap of all touched
/// accounts and their storage slots. The cost scales with the number of accounts and
/// storage slots modified in the flashblock. Monitor `bundle_state_clone_duration` and
/// `bundle_state_clone_size` metrics to track if this becomes a bottleneck.
pub fn get_bundle_state(&self) -> BundleState {
let metrics = Metrics::default();
let size = self.bundle_state.state.len();
let start = Instant::now();
let cloned = self.bundle_state.clone();
metrics.bundle_state_clone_duration.record(start.elapsed());
metrics.bundle_state_clone_size.record(size as f64);
cloned
}

/// Returns all transactions for a specific block number.
pub fn get_transactions_for_block(&self, block_number: BlockNumber) -> Vec<Transaction> {
self.transactions
Expand Down
25 changes: 21 additions & 4 deletions crates/flashblocks/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use reth_optimism_primitives::{DepositReceipt, OpBlock, OpPrimitives};
use reth_optimism_rpc::OpReceiptBuilder;
use reth_primitives::RecoveredBlock;
use reth_rpc_convert::transaction::ConvertReceiptInput;
use revm_database::states::bundle_state::BundleRetention;
use tokio::sync::{Mutex, broadcast::Sender, mpsc::UnboundedReceiver};
use tracing::{debug, error, info, warn};

Expand Down Expand Up @@ -293,12 +294,26 @@ where
let state_provider =
self.client.state_by_block_number_or_tag(BlockNumberOrTag::Number(canonical_block))?;
let state_provider_db = StateProviderDatabase::new(state_provider);
let state = State::builder().with_database(state_provider_db).with_bundle_update().build();
let mut pending_blocks_builder = PendingBlocksBuilder::new();

// Cache reads across flashblocks, accumulating caches from previous
// pending blocks if available
let cache_db = match &prev_pending_blocks {
Some(pending_blocks) => {
CacheDB { cache: pending_blocks.get_db_cache(), db: state_provider_db }
}
None => CacheDB::new(state_provider_db),
};

// Track state changes across flashblocks, accumulating bundle state
// from previous pending blocks if available
let mut db = match &prev_pending_blocks {
Some(pending_blocks) => CacheDB { cache: pending_blocks.get_db_cache(), db: state },
None => CacheDB::new(state),
Some(pending_blocks) => State::builder()
.with_database(cache_db)
.with_bundle_update()
.with_bundle_prestate(pending_blocks.get_bundle_state())
.build(),
None => State::builder().with_database(cache_db).with_bundle_update().build(),
};

let mut state_overrides =
Expand Down Expand Up @@ -537,7 +552,9 @@ where
last_block_header = block.header.clone();
}

pending_blocks_builder.with_db_cache(db.cache);
db.merge_transitions(BundleRetention::Reverts);
pending_blocks_builder.with_bundle_state(db.take_bundle());
pending_blocks_builder.with_db_cache(db.database.cache);
pending_blocks_builder.with_state_overrides(state_overrides);
Ok(Some(Arc::new(pending_blocks_builder.build()?)))
}
Expand Down
Loading
Loading