Skip to content

Commit ba5ada0

Browse files
committed
Add state root calculation on payload resolve
1 parent c678f28 commit ba5ada0

File tree

1 file changed

+94
-6
lines changed
  • crates/op-rbuilder/src/builders/flashblocks

1 file changed

+94
-6
lines changed

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

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -366,12 +366,7 @@ where
366366
);
367367
};
368368

369-
let (payload, fb_payload) = build_block(
370-
&mut state,
371-
&ctx,
372-
&mut info,
373-
!disable_state_root || ctx.attributes().no_tx_pool, // need to calculate state root for CL sync
374-
)?;
369+
let (payload, fb_payload) = build_block(&mut state, &ctx, &mut info, true)?;
375370

376371
self.payload_tx
377372
.send(payload.clone())
@@ -581,6 +576,7 @@ where
581576
ctx = ctx.with_cancel(fb_cancel).with_extra_ctx(next_flashblocks_ctx);
582577
},
583578
_ = block_cancel.cancelled() => {
579+
self.resolve_best_payload(&mut state, &ctx, &mut info, &best_payload).await;
584580
self.record_flashblocks_metrics(
585581
&ctx,
586582
&info,
@@ -701,6 +697,8 @@ where
701697
// We got block cancelled, we won't need anything from the block at this point
702698
// Caution: this assume that block cancel token only cancelled when new FCU is received
703699
if block_cancel.is_cancelled() {
700+
self.resolve_best_payload(state, ctx, info, best_payload)
701+
.await;
704702
self.record_flashblocks_metrics(
705703
ctx,
706704
info,
@@ -824,6 +822,52 @@ where
824822
}
825823
}
826824

825+
async fn resolve_best_payload<
826+
DB: Database<Error = ProviderError> + std::fmt::Debug + AsRef<P>,
827+
P: StateRootProvider + HashedPostStateProvider + StorageRootProvider,
828+
>(
829+
&self,
830+
state: &mut State<DB>,
831+
ctx: &OpPayloadBuilderCtx<FlashblocksExtraCtx>,
832+
info: &mut ExecutionInfo<FlashblocksExecutionInfo>,
833+
best_payload: &BlockCell<OpBuiltPayload>,
834+
) {
835+
if let Some(payload) = best_payload.get()
836+
&& payload.block().header().state_root == B256::ZERO
837+
{
838+
// Calculate state root for best payload on resolve payload to prevent
839+
// cache misses for locally built payloads.
840+
if let Ok(state_root) = calculate_state_root_only(state, ctx, info) {
841+
use reth_payload_primitives::BuiltPayload as _;
842+
let payload_id = payload.id();
843+
let fees = payload.fees();
844+
let executed_block = payload.executed_block();
845+
846+
// Get the current sealed block and extract its components
847+
let block = payload.into_sealed_block().into_block();
848+
let (mut header, body) = block.split();
849+
header.state_root = state_root;
850+
851+
// Create a new sealed block with the updated header
852+
let updated_block =
853+
alloy_consensus::Block::<OpTransactionSigned>::new(header, body);
854+
let sealed_block = Arc::new(updated_block.seal_slow());
855+
856+
// Update the best payload with the calculated staet root
857+
let updated_payload =
858+
OpBuiltPayload::new(payload_id, sealed_block, fees, executed_block);
859+
self.payload_tx.send(updated_payload.clone()).await.ok(); // ignore error here
860+
best_payload.set(updated_payload);
861+
862+
debug!(
863+
target: "payload_builder",
864+
state_root = %state_root,
865+
"Updated payload with calculated state root"
866+
);
867+
}
868+
}
869+
}
870+
827871
/// Do some logging and metric recording when we stop build flashblocks
828872
fn record_flashblocks_metrics(
829873
&self,
@@ -1203,3 +1247,47 @@ where
12031247
fb_payload,
12041248
))
12051249
}
1250+
1251+
/// Calculates only the state root for an existing payload
1252+
fn calculate_state_root_only<DB, P, ExtraCtx>(
1253+
state: &mut State<DB>,
1254+
ctx: &OpPayloadBuilderCtx<ExtraCtx>,
1255+
info: &ExecutionInfo<FlashblocksExecutionInfo>,
1256+
) -> Result<B256, PayloadBuilderError>
1257+
where
1258+
DB: Database<Error = ProviderError> + AsRef<P>,
1259+
P: StateRootProvider + HashedPostStateProvider + StorageRootProvider,
1260+
ExtraCtx: std::fmt::Debug + Default,
1261+
{
1262+
let state_root_start_time = Instant::now();
1263+
state.merge_transitions(BundleRetention::Reverts);
1264+
let execution_outcome = ExecutionOutcome::new(
1265+
state.bundle_state.clone(),
1266+
vec![info.receipts.clone()],
1267+
ctx.block_number(),
1268+
vec![],
1269+
);
1270+
1271+
let state_provider = state.database.as_ref();
1272+
let hashed_state = state_provider.hashed_post_state(execution_outcome.state());
1273+
let (state_root, _trie_output) = state
1274+
.database
1275+
.as_ref()
1276+
.state_root_with_updates(hashed_state)
1277+
.inspect_err(|err| {
1278+
warn!(target: "payload_builder",
1279+
parent_header=%ctx.parent().hash(),
1280+
%err,
1281+
"failed to calculate state root for payload"
1282+
);
1283+
})?;
1284+
let state_root_calculation_time = state_root_start_time.elapsed();
1285+
ctx.metrics
1286+
.state_root_calculation_duration
1287+
.record(state_root_calculation_time);
1288+
ctx.metrics
1289+
.state_root_calculation_gauge
1290+
.set(state_root_calculation_time);
1291+
1292+
Ok(state_root)
1293+
}

0 commit comments

Comments
 (0)