Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fda04a5
Include state root calculation time in metering
niran Oct 28, 2025
fe163b4
Update tips-core and expose state root time in RPC response
niran Oct 28, 2025
305a2ce
Add tests for state root time metrics
niran Oct 28, 2025
ad9586d
Simplify state root calculation by removing unnecessary ExecutionOutc…
niran Oct 28, 2025
d741e03
Use pending flashblocks state for bundle metering
niran Oct 29, 2025
8929514
Cache flashblock trie nodes to optimize bundle metering
niran Oct 30, 2025
2c8699f
linter fixes
niran Oct 30, 2025
afe211a
Rename total_execution_time to total_time for clarity
niran Nov 9, 2025
76c6c0e
Refactor flashblock trie data handling to reduce code duplication
niran Nov 10, 2025
62bd1c3
Add chain-state metering tests and flashblock harness support
niran Nov 11, 2025
8749989
Fix chain-state metering tests with L1 deposit
niran Nov 11, 2025
5aacb8a
Restore beacon root for successful metering tests
niran Nov 11, 2025
e55c43a
Have storage persistence test meter the next block
niran Nov 11, 2025
a41a001
Rename metering tests for clarity
niran Nov 11, 2025
3572284
Drop redundant beacon-root RPC test
niran Nov 11, 2025
eb37396
Document why flashblock trie caching isolates bundle I/O
niran Nov 17, 2025
82b03cb
Move build_single_flashblock from metering to test-utils
niran Nov 17, 2025
4211c10
tweak comments
niran Nov 17, 2025
5b05bb2
Update tips-core and fix metering harness/tests
niran Nov 25, 2025
9d07837
Silence the global executor errors
niran Nov 26, 2025
d8c7184
Add TODO for state_root_time
niran Nov 26, 2025
9752d0a
Add metrics for bundle state clone cost
niran Nov 26, 2025
1942db8
Add database layering tests to flashblocks-rpc
niran Nov 26, 2025
5fbc033
Add tests for flashblock state visibility
niran Nov 27, 2025
4d324f5
just fix
niran Nov 27, 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
31 changes: 25 additions & 6 deletions Cargo.lock

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

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

# base/tips
# Note: default-features = false avoids version conflicts with reth's alloy/op-alloy dependencies
tips-core = { git = "https://github.com/base/tips", rev = "a21ee492dede17f31eea108c12c669a8190f31aa", default-features = false }
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 All @@ -74,10 +74,12 @@ reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-rpc-layer = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-ipc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" }
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-primitives = { version = "1.4.1", default-features = false, features = [
Expand All @@ -89,6 +91,7 @@ alloy-rpc-types = { version = "1.0.41", default-features = false }
alloy-rpc-types-engine = { version = "1.0.41", default-features = false }
alloy-rpc-types-eth = { version = "1.0.41" }
alloy-consensus = { version = "1.0.41" }
alloy-sol-types = { version = "1.4.1" }
alloy-trie = { version = "0.9.1", default-features = false }
alloy-provider = { version = "1.0.41" }
alloy-hardforks = "0.4.4"
Expand Down
4 changes: 4 additions & 0 deletions crates/flashblocks-rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-exex.workspace = true

# revm
revm-database.workspace = true

# alloy
alloy-primitives.workspace = true
alloy-eips.workspace = true
Expand Down Expand Up @@ -76,6 +79,7 @@ arc-swap.workspace = true
[dev-dependencies]
base-reth-test-utils.workspace = true
rand.workspace = true
revm.workspace = true
reth-db.workspace = true
reth-testing-utils.workspace = true
reth-db-common.workspace = true
Expand Down
6 changes: 6 additions & 0 deletions crates/flashblocks-rpc/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,10 @@ pub struct Metrics {

#[metric(describe = "Total number of WebSocket reconnection attempts")]
pub reconnect_attempts: Counter,

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

#[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-rpc/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 @@ -13,11 +13,14 @@ use arc_swap::Guard;
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::{rpc::PendingBlocksAPI, subscription::Flashblock};
use crate::{metrics::Metrics, rpc::PendingBlocksAPI, subscription::Flashblock};

pub struct PendingBlocksBuilder {
flashblocks: Vec<Flashblock>,
Expand All @@ -33,6 +36,7 @@ pub struct PendingBlocksBuilder {
state_overrides: Option<StateOverride>,

db_cache: Cache,
bundle_state: BundleState,
}

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

Expand Down Expand Up @@ -116,6 +121,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 @@ -137,6 +148,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 @@ -156,6 +168,7 @@ pub struct PendingBlocks {
state_overrides: Option<StateOverride>,

db_cache: Cache,
bundle_state: BundleState,
}

impl PendingBlocks {
Expand Down Expand Up @@ -195,6 +208,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
}

pub fn get_transactions_for_block(&self, block_number: BlockNumber) -> Vec<Transaction> {
self.transactions
.iter()
Expand Down
25 changes: 21 additions & 4 deletions crates/flashblocks-rpc/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,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::{self, Sender},
Expand Down Expand Up @@ -375,12 +376,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 = match &prev_pending_blocks {
Expand Down Expand Up @@ -620,7 +635,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