Skip to content

Commit 4e3fb84

Browse files
authored
changes (#333)
1 parent 29c41f1 commit 4e3fb84

File tree

5 files changed

+90
-3
lines changed

5 files changed

+90
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ serde_json = "1.0.96"
1414
metrics = "0.24.0"
1515
tokio = { version = "1", features = ["full"] }
1616
eyre = "0.6.12"
17+
sha2 = { version = "0.10", default-features = false }
1718

1819
# Alloy libraries
1920
alloy-rpc-types-engine = "1.0.5"

crates/rollup-boost/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ serde_json.workspace = true
1515
metrics.workspace = true
1616
tokio.workspace = true
1717
eyre.workspace = true
18+
sha2.workspace = true
1819

1920
op-alloy-rpc-types-engine.workspace = true
2021
alloy-rpc-types-engine.workspace = true

crates/rollup-boost/src/flashblocks/service.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::RpcClientError;
66
use crate::flashblocks::metrics::FlashblocksServiceMetrics;
77
use crate::{
88
ClientResult, EngineApiExt, NewPayload, OpExecutionPayloadEnvelope, PayloadVersion, RpcClient,
9+
payload_id_optimism,
910
};
1011
use alloy_primitives::U256;
1112
use alloy_rpc_types_engine::{
@@ -296,14 +297,28 @@ impl EngineApiExt for FlashblocksService {
296297
fork_choice_state: ForkchoiceState,
297298
payload_attributes: Option<OpPayloadAttributes>,
298299
) -> ClientResult<ForkchoiceUpdated> {
300+
// Calculate and set expected payload_id
301+
if let Some(attr) = &payload_attributes {
302+
let payload_id = payload_id_optimism(&fork_choice_state.head_block_hash, attr, 3);
303+
self.set_current_payload_id(payload_id).await;
304+
}
299305
let result = self
300306
.client
301307
.fork_choice_updated_v3(fork_choice_state, payload_attributes)
302308
.await?;
303309

304310
if let Some(payload_id) = result.payload_id {
305-
tracing::debug!(message = "Forkchoice updated", payload_id = %payload_id);
306-
self.set_current_payload_id(payload_id).await;
311+
let current_payload = *self.current_payload_id.read().await;
312+
if current_payload != payload_id {
313+
tracing::error!(
314+
message = "Payload id returned by builder differs from calculated. Using builder payload id",
315+
builder_payload_id = %payload_id,
316+
calculated_payload_id = %current_payload,
317+
);
318+
self.set_current_payload_id(payload_id).await;
319+
} else {
320+
tracing::debug!(message = "Forkchoice updated", payload_id = %payload_id);
321+
}
307322
} else {
308323
tracing::debug!(message = "Forkchoice updated with no payload ID");
309324
}

crates/rollup-boost/src/payload.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
use alloy_primitives::{B256, Bytes};
1+
use alloy_primitives::private::alloy_rlp::Encodable;
2+
use alloy_primitives::{B256, Bytes, keccak256};
23
use futures::{StreamExt as _, stream};
34
use moka::future::Cache;
45

56
use alloy_rpc_types_engine::{ExecutionPayload, ExecutionPayloadV3, PayloadId};
67
use op_alloy_rpc_types_engine::{
78
OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpExecutionPayloadV4,
9+
OpPayloadAttributes,
810
};
911

1012
const CACHE_SIZE: u64 = 100;
@@ -266,3 +268,70 @@ impl PayloadTraceContext {
266268
}
267269
}
268270
}
271+
272+
/// Generates the payload id for the configured payload from the [`OpPayloadAttributes`].
273+
///
274+
/// Returns an 8-byte identifier by hashing the payload components with sha256 hash.
275+
pub(crate) fn payload_id_optimism(
276+
parent: &B256,
277+
attributes: &OpPayloadAttributes,
278+
payload_version: u8,
279+
) -> PayloadId {
280+
use sha2::Digest;
281+
let mut hasher = sha2::Sha256::new();
282+
hasher.update(parent.as_slice());
283+
hasher.update(&attributes.payload_attributes.timestamp.to_be_bytes()[..]);
284+
hasher.update(attributes.payload_attributes.prev_randao.as_slice());
285+
hasher.update(
286+
attributes
287+
.payload_attributes
288+
.suggested_fee_recipient
289+
.as_slice(),
290+
);
291+
if let Some(withdrawals) = &attributes.payload_attributes.withdrawals {
292+
let mut buf = Vec::new();
293+
withdrawals.encode(&mut buf);
294+
hasher.update(buf);
295+
}
296+
297+
if let Some(parent_beacon_block) = attributes.payload_attributes.parent_beacon_block_root {
298+
hasher.update(parent_beacon_block);
299+
}
300+
301+
let no_tx_pool = attributes.no_tx_pool.unwrap_or_default();
302+
if no_tx_pool
303+
|| attributes
304+
.transactions
305+
.as_ref()
306+
.is_some_and(|txs| !txs.is_empty())
307+
{
308+
hasher.update([no_tx_pool as u8]);
309+
let txs_len = attributes
310+
.transactions
311+
.as_ref()
312+
.map(|txs| txs.len())
313+
.unwrap_or_default();
314+
hasher.update(&txs_len.to_be_bytes()[..]);
315+
if let Some(txs) = &attributes.transactions {
316+
for tx in txs {
317+
// we have to just hash the bytes here because otherwise we would need to decode
318+
// the transactions here which really isn't ideal
319+
let tx_hash = keccak256(tx);
320+
// maybe we can try just taking the hash and not decoding
321+
hasher.update(tx_hash)
322+
}
323+
}
324+
}
325+
326+
if let Some(gas_limit) = attributes.gas_limit {
327+
hasher.update(gas_limit.to_be_bytes());
328+
}
329+
330+
if let Some(eip_1559_params) = attributes.eip_1559_params {
331+
hasher.update(eip_1559_params.as_slice());
332+
}
333+
334+
let mut out = hasher.finalize();
335+
out[0] = payload_version;
336+
PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
337+
}

0 commit comments

Comments
 (0)