Skip to content

Commit

Permalink
Merge branch 'main' into emhane/bump-rust-version
Browse files Browse the repository at this point in the history
  • Loading branch information
emhane committed Feb 26, 2025
2 parents 4d7897a + bcb53a2 commit f8cddcf
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 29 deletions.
52 changes: 49 additions & 3 deletions crates/rpc-types-engine/src/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
//! This module uses the `snappy` compression algorithm to decompress the payload.
//! The license for snappy can be found in the `SNAPPY-LICENSE` at the root of the repository.
use crate::{OpExecutionPayload, OpExecutionPayloadSidecar};
use crate::{OpExecutionPayload, OpExecutionPayloadSidecar, OpExecutionPayloadV4};
use alloc::vec::Vec;
use alloy_eips::eip4895::Withdrawal;
use alloy_eips::{eip4895::Withdrawal, eip7685::Requests};
use alloy_primitives::{keccak256, PrimitiveSignature as Signature, B256};
use alloy_rpc_types_engine::ExecutionPayload;
use alloy_rpc_types_engine::{
CancunPayloadFields, ExecutionPayload, ExecutionPayloadInputV2, ExecutionPayloadV3,
PraguePayloadFields,
};

/// Struct aggregating [`OpExecutionPayload`] and [`OpExecutionPayloadSidecar`] and encapsulating
/// complete payload supplied for execution.
Expand All @@ -26,6 +29,48 @@ impl OpExecutionData {
Self { payload, sidecar }
}

/// Creates a new instance from args to engine API method `newPayloadV2`.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv2>
pub fn v2(payload: ExecutionPayloadInputV2) -> Self {
Self::new(OpExecutionPayload::v2(payload), OpExecutionPayloadSidecar::default())
}

/// Creates a new instance from args to engine API method `newPayloadV3`.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv3>
pub fn v3(
payload: ExecutionPayloadV3,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
) -> Self {
Self::new(
OpExecutionPayload::v3(payload),
OpExecutionPayloadSidecar::v3(CancunPayloadFields::new(
parent_beacon_block_root,
versioned_hashes,
)),
)
}

/// Creates a new instance from args to engine API method `newPayloadV4`.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv4>
pub fn v4(
payload: OpExecutionPayloadV4,
versioned_hashes: Vec<B256>,
parent_beacon_block_root: B256,
execution_requests: Requests,
) -> Self {
Self::new(
OpExecutionPayload::v4(payload),
OpExecutionPayloadSidecar::v4(
CancunPayloadFields::new(parent_beacon_block_root, versioned_hashes),
PraguePayloadFields::new(execution_requests),
),
)
}

/// Returns the parent beacon block root, if any.
pub fn parent_beacon_block_root(&self) -> Option<B256> {
self.sidecar.parent_beacon_block_root()
Expand All @@ -34,6 +79,7 @@ impl OpExecutionData {
/// Return the withdrawals for the payload or attributes.
pub const fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
match &self.payload {
OpExecutionPayload::V1(_) => None,
OpExecutionPayload::V2(execution_payload_v2) => Some(&execution_payload_v2.withdrawals),
OpExecutionPayload::V3(execution_payload_v3) => {
Some(execution_payload_v3.withdrawals())
Expand Down
108 changes: 87 additions & 21 deletions crates/rpc-types-engine/src/payload/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use crate::{OpExecutionPayloadSidecar, OpExecutionPayloadV4};
use alloy_consensus::{Block, EMPTY_ROOT_HASH};
use alloy_eips::{Decodable2718, Typed2718};
use alloy_primitives::B256;
use alloy_rpc_types_engine::{ExecutionPayloadV2, ExecutionPayloadV3};
use alloy_rpc_types_engine::{
ExecutionPayload, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV2,
ExecutionPayloadV3,
};
use error::OpPayloadError;

/// An execution payload, which can be either [`ExecutionPayloadV2`], [`ExecutionPayloadV3`], or
Expand All @@ -17,6 +20,8 @@ use error::OpPayloadError;
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(untagged))]
pub enum OpExecutionPayload {
/// V1 payload
V1(ExecutionPayloadV1),
/// V2 payload
V2(ExecutionPayloadV2),
/// V3 payload
Expand Down Expand Up @@ -286,61 +291,119 @@ impl<'de> serde::Deserialize<'de> for OpExecutionPayload {
}

impl OpExecutionPayload {
/// Creates a new instance from `newPayloadV2` payload, i.e. [`V1`](Self::V1) or
/// [`V2`](Self::V2) variant.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv2>
pub fn v2(payload: ExecutionPayloadInputV2) -> Self {
match payload.into_payload() {
ExecutionPayload::V1(payload) => Self::V1(payload),
ExecutionPayload::V2(payload) => Self::V2(payload),
_ => unreachable!(),
}
}

/// Creates a new instance from `newPayloadV3` payload, i.e. [`V3`](Self::V3) variant.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv3>
pub const fn v3(payload: ExecutionPayloadV3) -> Self {
Self::V3(payload)
}

/// Creates a new instance from `newPayloadV4` payload, i.e. [`V4`](Self::V4) variant.
///
/// Spec: <https://specs.optimism.io/protocol/exec-engine.html#engine_newpayloadv4>
pub const fn v4(payload: OpExecutionPayloadV4) -> Self {
Self::V4(payload)
}

/// Returns a reference to the V1 payload.
pub const fn as_v1(&self) -> &ExecutionPayloadV1 {
match self {
Self::V1(payload) => payload,
Self::V2(payload) => &payload.payload_inner,
Self::V3(payload) => &payload.payload_inner.payload_inner,
Self::V4(payload) => &payload.payload_inner.payload_inner.payload_inner,
}
}

/// Returns a mutable reference to the V1 payload.
pub fn as_v1_mut(&mut self) -> &mut ExecutionPayloadV1 {
match self {
Self::V1(payload) => payload,
Self::V2(payload) => &mut payload.payload_inner,
Self::V3(payload) => &mut payload.payload_inner.payload_inner,
Self::V4(payload) => &mut payload.payload_inner.payload_inner.payload_inner,
}
}

/// Returns a reference to the V2 payload, if any.
pub const fn as_v2(&self) -> &ExecutionPayloadV2 {
pub const fn as_v2(&self) -> Option<&ExecutionPayloadV2> {
match self {
Self::V2(payload) => payload,
Self::V3(payload) => &payload.payload_inner,
Self::V4(payload) => &payload.payload_inner.payload_inner,
Self::V1(_) => None,
Self::V2(payload) => Some(payload),
Self::V3(payload) => Some(&payload.payload_inner),
Self::V4(payload) => Some(&payload.payload_inner.payload_inner),
}
}

/// Returns a mutable reference to the V2 payload, if any.
pub const fn as_v2_mut(&mut self) -> &ExecutionPayloadV2 {
pub const fn as_v2_mut(&mut self) -> Option<&mut ExecutionPayloadV2> {
match self {
Self::V2(payload) => payload,
Self::V3(payload) => &mut payload.payload_inner,
Self::V4(payload) => &payload.payload_inner.payload_inner,
Self::V1(_) => None,
Self::V2(payload) => Some(payload),
Self::V3(payload) => Some(&mut payload.payload_inner),
Self::V4(payload) => Some(&mut payload.payload_inner.payload_inner),
}
}

/// Returns a reference to the V3 payload, if any.
pub const fn as_v3(&self) -> Option<&ExecutionPayloadV3> {
match self {
Self::V2(_) => None,
Self::V1(_) | Self::V2(_) => None,
Self::V3(payload) => Some(payload),
Self::V4(payload) => Some(&payload.payload_inner),
}
}

/// Returns a mutable reference to the V3 payload, if any.
pub const fn as_v3_mut(&mut self) -> Option<&ExecutionPayloadV3> {
pub const fn as_v3_mut(&mut self) -> Option<&mut ExecutionPayloadV3> {
match self {
Self::V2(_) => None,
Self::V1(_) | Self::V2(_) => None,
Self::V3(payload) => Some(payload),
Self::V4(payload) => Some(&payload.payload_inner),
Self::V4(payload) => Some(&mut payload.payload_inner),
}
}

/// Returns a reference to the V4 payload, if any.
pub const fn as_v4(&self) -> Option<&OpExecutionPayloadV4> {
match self {
Self::V2(_) | Self::V3(_) => None,
Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
Self::V4(payload) => Some(payload),
}
}

/// Returns a mutable reference to the V4 payload, if any.
pub const fn as_v4_mut(&mut self) -> Option<&mut OpExecutionPayloadV4> {
match self {
Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
Self::V4(payload) => Some(payload),
}
}

/// Returns the parent hash for the payload.
pub const fn parent_hash(&self) -> B256 {
self.as_v2().payload_inner.parent_hash
self.as_v1().parent_hash
}

/// Returns the block hash for the payload.
pub const fn block_hash(&self) -> B256 {
self.as_v2().payload_inner.block_hash
self.as_v1().block_hash
}

/// Returns the block number for this payload.
pub const fn block_number(&self) -> u64 {
self.as_v2().payload_inner.block_number
self.as_v1().block_number
}

#[allow(rustdoc::broken_intra_doc_links)]
Expand All @@ -356,11 +419,14 @@ impl OpExecutionPayload {
///
/// See also: [`OpExecutionPayload::try_into_block_with_sidecar`]
pub fn try_into_block<T: Decodable2718 + Typed2718>(self) -> Result<Block<T>, OpPayloadError> {
if !self.as_v2().withdrawals.is_empty() {
return Err(OpPayloadError::NonEmptyL1Withdrawals);
if let Some(payload) = self.as_v2() {
if !payload.withdrawals.is_empty() {
return Err(OpPayloadError::NonEmptyL1Withdrawals);
}
}
let block = match self {
Self::V2(payload) => payload.try_into_block()?,
Self::V1(payload) => return Ok(payload.try_into_block()?),
Self::V2(payload) => return Ok(payload.try_into_block()?),
Self::V3(payload) => payload.try_into_block()?,
Self::V4(payload) => payload.try_into_block()?,
};
Expand Down Expand Up @@ -442,7 +508,7 @@ mod tests {
assert_eq!(serde_json::to_string(&payload).unwrap(), response_v2);

let payload_v2: ExecutionPayloadV2 = serde_json::from_str(response_v2).unwrap();
assert_eq!(payload.as_v2(), &payload_v2);
assert_eq!(payload.as_v2(), Some(&payload_v2));
}

#[test]
Expand Down
13 changes: 8 additions & 5 deletions crates/rpc-types/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,14 @@ mod tx_serde {
// error
let from = if let Some(from) = other.from {
from
} else { match &inner { OpTxEnvelope::Deposit(tx) => {
tx.from
} _ => {
return Err(serde_json::Error::custom("missing `from` field"));
}}};
} else {
match &inner {
OpTxEnvelope::Deposit(tx) => tx.from,
_ => {
return Err(serde_json::Error::custom("missing `from` field"));
}
}
};

// Only serialize deposit_nonce if inner transaction is deposit to avoid duplicated keys
let deposit_nonce = other.deposit_nonce.filter(|_| inner.is_deposit());
Expand Down

0 comments on commit f8cddcf

Please sign in to comment.