Skip to content

Commit fed74d1

Browse files
authored
flag to determine if calculating state root (#241)
* calculate state root * fix tests * add no state root test * check no tx pool instead * comments * optimize * fix lint * use no tx pool * add condition
1 parent 5640d8c commit fed74d1

File tree

4 files changed

+117
-32
lines changed

4 files changed

+117
-32
lines changed

crates/op-rbuilder/src/args/op.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ pub struct FlashblocksArgs {
147147
env = "FLASHBLOCK_LEEWAY_TIME"
148148
)]
149149
pub flashblocks_leeway_time: u64,
150+
151+
/// Should we calculate state root for each flashblock
152+
#[arg(
153+
long = "flashblocks.calculate-state-root",
154+
default_value = "true",
155+
env = "FLASHBLOCKS_CALCULATE_STATE_ROOT"
156+
)]
157+
pub flashblocks_calculate_state_root: bool,
150158
}
151159

152160
impl Default for FlashblocksArgs {

crates/op-rbuilder/src/builders/flashblocks/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub struct FlashblocksConfig {
2828

2929
/// Disables dynamic flashblocks number adjustment based on FCU arrival time
3030
pub fixed: bool,
31+
32+
/// Should we calculate state root for each flashblock
33+
pub calculate_state_root: bool,
3134
}
3235

3336
impl Default for FlashblocksConfig {
@@ -37,6 +40,7 @@ impl Default for FlashblocksConfig {
3740
interval: Duration::from_millis(250),
3841
leeway_time: Duration::from_millis(50),
3942
fixed: false,
43+
calculate_state_root: true,
4044
}
4145
}
4246
}
@@ -56,11 +60,14 @@ impl TryFrom<OpRbuilderArgs> for FlashblocksConfig {
5660

5761
let fixed = args.flashblocks.flashblocks_fixed;
5862

63+
let calculate_state_root = args.flashblocks.flashblocks_calculate_state_root;
64+
5965
Ok(Self {
6066
ws_addr,
6167
interval,
6268
leeway_time,
6369
fixed,
70+
calculate_state_root,
6471
})
6572
}
6673
}

crates/op-rbuilder/src/builders/flashblocks/payload.rs

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use reth_provider::{
3737
use reth_revm::{
3838
State, database::StateProviderDatabase, db::states::bundle_state::BundleRetention,
3939
};
40+
use reth_trie::{HashedPostState, updates::TrieUpdates};
4041
use revm::Database;
4142
use rollup_boost::{
4243
ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, FlashblocksPayloadV1,
@@ -222,6 +223,7 @@ where
222223

223224
let chain_spec = self.client.chain_spec();
224225
let timestamp = config.attributes.timestamp();
226+
let calculate_state_root = self.config.specific.calculate_state_root;
225227
let block_env_attributes = OpNextBlockEnvAttributes {
226228
timestamp,
227229
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
@@ -299,18 +301,25 @@ where
299301
ctx.add_builder_tx(&mut info, &mut state, builder_tx_gas, message.clone());
300302
}
301303

302-
let (payload, fb_payload) = build_block(&mut state, &ctx, &mut info)?;
304+
let (payload, fb_payload) = build_block(
305+
&mut state,
306+
&ctx,
307+
&mut info,
308+
calculate_state_root || ctx.attributes().no_tx_pool, // need to calculate state root for CL sync
309+
)?;
303310

304311
best_payload.set(payload.clone());
305312
self.send_payload_to_engine(payload);
306-
307-
let flashblock_byte_size = self
308-
.ws_pub
309-
.publish(&fb_payload)
310-
.map_err(PayloadBuilderError::other)?;
311-
ctx.metrics
312-
.flashblock_byte_size_histogram
313-
.record(flashblock_byte_size as f64);
313+
// not emitting flashblock if no_tx_pool in FCU, it's just syncing
314+
if !ctx.attributes().no_tx_pool {
315+
let flashblock_byte_size = self
316+
.ws_pub
317+
.publish(&fb_payload)
318+
.map_err(PayloadBuilderError::other)?;
319+
ctx.metrics
320+
.flashblock_byte_size_histogram
321+
.record(flashblock_byte_size as f64);
322+
}
314323

315324
info!(
316325
target: "payload_builder",
@@ -513,7 +522,8 @@ where
513522
};
514523

515524
let total_block_built_duration = Instant::now();
516-
let build_result = build_block(&mut state, &ctx, &mut info);
525+
let build_result =
526+
build_block(&mut state, &ctx, &mut info, calculate_state_root);
517527
let total_block_built_duration = total_block_built_duration.elapsed();
518528
ctx.metrics
519529
.total_block_built_duration
@@ -823,6 +833,7 @@ fn build_block<DB, P, ExtraCtx>(
823833
state: &mut State<DB>,
824834
ctx: &OpPayloadBuilderCtx<ExtraCtx>,
825835
info: &mut ExecutionInfo<ExtraExecutionInfo>,
836+
calculate_state_root: bool,
826837
) -> Result<(OpBuiltPayload, FlashblocksPayloadV1), PayloadBuilderError>
827838
where
828839
DB: Database<Error = ProviderError> + AsRef<P>,
@@ -867,28 +878,34 @@ where
867878
// TODO: maybe recreate state with bundle in here
868879
// // calculate the state root
869880
let state_root_start_time = Instant::now();
870-
let state_provider = state.database.as_ref();
871-
let hashed_state = state_provider.hashed_post_state(execution_outcome.state());
872-
let (state_root, trie_output) = {
873-
state
874-
.database
875-
.as_ref()
876-
.state_root_with_updates(hashed_state.clone())
877-
.inspect_err(|err| {
878-
warn!(target: "payload_builder",
879-
parent_header=%ctx.parent().hash(),
880-
%err,
881-
"failed to calculate state root for payload"
882-
);
883-
})?
884-
};
885-
let state_root_calculation_time = state_root_start_time.elapsed();
886-
ctx.metrics
887-
.state_root_calculation_duration
888-
.record(state_root_calculation_time);
889-
ctx.metrics
890-
.state_root_calculation_gauge
891-
.set(state_root_calculation_time);
881+
let mut state_root = B256::ZERO;
882+
let mut trie_output = TrieUpdates::default();
883+
let mut hashed_state = HashedPostState::default();
884+
885+
if calculate_state_root {
886+
let state_provider = state.database.as_ref();
887+
hashed_state = state_provider.hashed_post_state(execution_outcome.state());
888+
(state_root, trie_output) = {
889+
state
890+
.database
891+
.as_ref()
892+
.state_root_with_updates(hashed_state.clone())
893+
.inspect_err(|err| {
894+
warn!(target: "payload_builder",
895+
parent_header=%ctx.parent().hash(),
896+
%err,
897+
"failed to calculate state root for payload"
898+
);
899+
})?
900+
};
901+
let state_root_calculation_time = state_root_start_time.elapsed();
902+
ctx.metrics
903+
.state_root_calculation_duration
904+
.record(state_root_calculation_time);
905+
ctx.metrics
906+
.state_root_calculation_gauge
907+
.set(state_root_calculation_time);
908+
}
892909

893910
let mut requests_hash = None;
894911
let withdrawals_root = if ctx

crates/op-rbuilder/src/tests/flashblocks.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
flashblocks_block_time: 200,
1717
flashblocks_leeway_time: 100,
1818
flashblocks_fixed: false,
19+
flashblocks_calculate_state_root: true,
1920
},
2021
..Default::default()
2122
})]
@@ -53,6 +54,7 @@ async fn smoke_dynamic_base(rbuilder: LocalInstance) -> eyre::Result<()> {
5354
flashblocks_block_time: 200,
5455
flashblocks_leeway_time: 100,
5556
flashblocks_fixed: false,
57+
flashblocks_calculate_state_root: true,
5658
},
5759
..Default::default()
5860
})]
@@ -90,6 +92,7 @@ async fn smoke_dynamic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> {
9092
flashblocks_block_time: 200,
9193
flashblocks_leeway_time: 50,
9294
flashblocks_fixed: true,
95+
flashblocks_calculate_state_root: true,
9396
},
9497
..Default::default()
9598
})]
@@ -127,6 +130,7 @@ async fn smoke_classic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> {
127130
flashblocks_block_time: 200,
128131
flashblocks_leeway_time: 50,
129132
flashblocks_fixed: true,
133+
flashblocks_calculate_state_root: true,
130134
},
131135
..Default::default()
132136
})]
@@ -164,6 +168,7 @@ async fn smoke_classic_base(rbuilder: LocalInstance) -> eyre::Result<()> {
164168
flashblocks_block_time: 200,
165169
flashblocks_leeway_time: 100,
166170
flashblocks_fixed: false,
171+
flashblocks_calculate_state_root: true,
167172
},
168173
..Default::default()
169174
})]
@@ -203,6 +208,7 @@ async fn unichain_dynamic_with_lag(rbuilder: LocalInstance) -> eyre::Result<()>
203208
flashblocks_block_time: 200,
204209
flashblocks_leeway_time: 0,
205210
flashblocks_fixed: false,
211+
flashblocks_calculate_state_root: true,
206212
},
207213
..Default::default()
208214
})]
@@ -240,6 +246,7 @@ async fn dynamic_with_full_block_lag(rbuilder: LocalInstance) -> eyre::Result<()
240246
flashblocks_block_time: 200,
241247
flashblocks_leeway_time: 100,
242248
flashblocks_fixed: false,
249+
flashblocks_calculate_state_root: true,
243250
},
244251
..Default::default()
245252
})]
@@ -299,6 +306,7 @@ async fn test_flashblock_min_filtering(rbuilder: LocalInstance) -> eyre::Result<
299306
flashblocks_block_time: 200,
300307
flashblocks_leeway_time: 100,
301308
flashblocks_fixed: false,
309+
flashblocks_calculate_state_root: true,
302310
},
303311
..Default::default()
304312
})]
@@ -354,6 +362,7 @@ async fn test_flashblock_max_filtering(rbuilder: LocalInstance) -> eyre::Result<
354362
flashblocks_block_time: 200,
355363
flashblocks_leeway_time: 100,
356364
flashblocks_fixed: false,
365+
flashblocks_calculate_state_root: true,
357366
},
358367
..Default::default()
359368
})]
@@ -388,3 +397,47 @@ async fn test_flashblock_min_max_filtering(rbuilder: LocalInstance) -> eyre::Res
388397

389398
flashblocks_listener.stop().await
390399
}
400+
401+
#[rb_test(flashblocks, args = OpRbuilderArgs {
402+
chain_block_time: 1000,
403+
flashblocks: FlashblocksArgs {
404+
enabled: true,
405+
flashblocks_port: 1239,
406+
flashblocks_addr: "127.0.0.1".into(),
407+
flashblocks_block_time: 200,
408+
flashblocks_leeway_time: 100,
409+
flashblocks_fixed: false,
410+
flashblocks_calculate_state_root: false,
411+
},
412+
..Default::default()
413+
})]
414+
async fn test_flashblocks_no_state_root_calculation(rbuilder: LocalInstance) -> eyre::Result<()> {
415+
use alloy_primitives::B256;
416+
417+
let driver = rbuilder.driver().await?;
418+
419+
// Send a transaction to ensure block has some activity
420+
let _tx = driver
421+
.create_transaction()
422+
.random_valid_transfer()
423+
.send()
424+
.await?;
425+
426+
// Build a block with current timestamp (not historical) and calculate_state_root: false
427+
let block = driver.build_new_block_with_current_timestamp(None).await?;
428+
429+
// Verify that flashblocks are still produced (block should have transactions)
430+
assert!(
431+
block.transactions.len() > 2,
432+
"Block should contain transactions"
433+
); // deposit + builder tx + user tx
434+
435+
// Verify that state root is not calculated (should be zero)
436+
assert_eq!(
437+
block.header.state_root,
438+
B256::ZERO,
439+
"State root should be zero when calculate_state_root is false"
440+
);
441+
442+
Ok(())
443+
}

0 commit comments

Comments
 (0)