Skip to content

Commit

Permalink
feat(isthmus): define IsthmusPayloadFields (#410)
Browse files Browse the repository at this point in the history
Closes #407
  • Loading branch information
emhane authored Feb 4, 2025
1 parent 2d52eea commit 33b4d77
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
6 changes: 6 additions & 0 deletions crates/rpc-types-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ op-alloy-consensus.workspace = true
alloy-primitives.workspace = true
alloy-eips.workspace = true
alloy-rpc-types-engine.workspace = true
alloy-consensus.workspace = true

# Encoding
snap = { workspace = true, optional = true }
Expand All @@ -34,6 +35,11 @@ alloy-serde = { workspace = true, optional = true }
# misc
thiserror.workspace = true
arbitrary = { workspace = true, features = ["derive"], optional = true }
derive_more = { workspace = true, default-features = false, features = [
"constructor",
"from",
"into",
]}

[dev-dependencies]
arbtest.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions crates/rpc-types-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ pub use payload_v3::OpExecutionPayloadEnvelopeV3;

mod payload_v4;
pub use payload_v4::OpExecutionPayloadEnvelopeV4;

mod sidecar;
pub use sidecar::{IsthmusPayloadFields, MaybeIsthmusPayloadFields, OpExecutionPayloadSidecar};
107 changes: 107 additions & 0 deletions crates/rpc-types-engine/src/sidecar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use alloy_consensus::{Block, BlockHeader, Transaction, EMPTY_ROOT_HASH};
use alloy_primitives::B256;
use alloy_rpc_types_engine::{CancunPayloadFields, MaybeCancunPayloadFields};
use derive_more::{Constructor, From, Into};

/// Container type for all available additional `newPayload` request parameters that are not present
/// in the [`ExecutionPayload`](alloy_rpc_types_engine::ExecutionPayload) object itself.
///
/// Default is equivalent to pre-canyon, payloads v1 and v2.
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OpExecutionPayloadSidecar {
/// Canyon request params, inherited from Cancun, introduced in `engine_newPayloadV3` that are
/// not present in the [`ExecutionPayload`](alloy_rpc_types_engine::ExecutionPayload).
canyon: MaybeCancunPayloadFields,
/// Storage root of `L2ToL1MessagePasser.sol`, aka l2 withdrawals root, requires state to
/// compute, hence root is passed in sidecar.
///
/// <https://specs.optimism.io/protocol/isthmus/exec-engine.html#update-to-executabledata>
isthmus: MaybeIsthmusPayloadFields,
}

impl OpExecutionPayloadSidecar {
/// Extracts the [`OpExecutionPayloadSidecar`] from the given [`Block`].
///
/// Returns `OpExecutionPayloadSidecar::default` if the block does not contain any sidecar
/// fields (pre-canyon).
pub fn from_block<T, H>(block: &Block<T, H>) -> Self
where
T: Transaction,
H: BlockHeader,
{
let canyon =
block.parent_beacon_block_root().map(|parent_beacon_block_root| CancunPayloadFields {
parent_beacon_block_root,
versioned_hashes: block.body.blob_versioned_hashes_iter().copied().collect(),
});

let isthmus = block
.withdrawals_root()
.filter(|root| *root != EMPTY_ROOT_HASH)
.map(IsthmusPayloadFields::new);

match (canyon, isthmus) {
(Some(canyon), Some(isthmus)) => Self::v4(canyon, isthmus),
(Some(canyon), None) => Self::v3(canyon),
_ => Self::default(),
}
}

/// Creates a new instance for canyon with the canyon fields for `engine_newPayloadV3`
pub fn v3(canyon: CancunPayloadFields) -> Self {
Self { canyon: canyon.into(), ..Default::default() }
}

/// Creates a new instance post prague for `engine_newPayloadV4`
pub fn v4(canyon: CancunPayloadFields, isthmus: IsthmusPayloadFields) -> Self {
Self { canyon: canyon.into(), isthmus: isthmus.into() }
}

/// Returns a reference to the [`CancunPayloadFields`].
pub const fn canyon(&self) -> Option<&CancunPayloadFields> {
self.canyon.as_ref()
}

/// Consumes the type and returns the [`CancunPayloadFields`]
pub fn into_canyon(self) -> Option<CancunPayloadFields> {
self.canyon.into_inner()
}

/// Returns a reference to the [`IsthmusPayloadFields`].
pub const fn isthmus(&self) -> Option<&IsthmusPayloadFields> {
self.isthmus.fields.as_ref()
}

/// Consumes the type and returns the [`IsthmusPayloadFields`].
pub fn into_isthmus(self) -> Option<IsthmusPayloadFields> {
self.isthmus.into()
}

/// Returns the parent beacon block root, if any.
pub fn parent_beacon_block_root(&self) -> Option<B256> {
self.canyon.parent_beacon_block_root()
}

/// Returns the withdrawals root, if any.
pub fn withdrawals_root(&self) -> Option<&B256> {
self.isthmus().map(|fields| &fields.withdrawals_root)
}
}

/// Fields introduced in `engine_newPayloadV4` that are not present in the
/// [`ExecutionPayload`](alloy_rpc_types_engine::ExecutionPayload) RPC object.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Constructor)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IsthmusPayloadFields {
/// EIP-7685 requests.
pub withdrawals_root: B256,
}

/// A container type for [`IsthmusPayloadFields`] that may or may not be present.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, From, Into)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[from(IsthmusPayloadFields)]
pub struct MaybeIsthmusPayloadFields {
fields: Option<IsthmusPayloadFields>,
}

0 comments on commit 33b4d77

Please sign in to comment.