diff --git a/crates/eips/src/eip7002.rs b/crates/eips/src/eip7002.rs index 43a11df5c06..fb3780337fe 100644 --- a/crates/eips/src/eip7002.rs +++ b/crates/eips/src/eip7002.rs @@ -25,6 +25,7 @@ pub const WITHDRAWAL_REQUEST_TYPE: u8 = 0x01; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RlpEncodable, RlpDecodable, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] +#[cfg_attr(feature = "ssz", derive(ssz_derive::Encode, ssz_derive::Decode))] #[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))] pub struct WithdrawalRequest { /// Address of the source of the exit. diff --git a/crates/rpc-types-beacon/src/relay.rs b/crates/rpc-types-beacon/src/relay.rs index d15feb8e3a8..5b1b056843b 100644 --- a/crates/rpc-types-beacon/src/relay.rs +++ b/crates/rpc-types-beacon/src/relay.rs @@ -6,6 +6,7 @@ use crate::{BlsPublicKey, BlsSignature}; use alloy_primitives::{Address, B256, U256}; use alloy_rpc_types_engine::{ BlobsBundleV1, ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3, + ExecutionPayloadV4, }; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; @@ -139,6 +140,22 @@ pub struct SignedBidSubmissionV3 { pub signature: BlsSignature, } +/// Submission for the `/relay/v1/builder/blocks` endpoint (Electra). +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +#[cfg_attr(feature = "ssz", derive(ssz_derive::Decode, ssz_derive::Encode))] +pub struct SignedBidSubmissionV4 { + /// The [`BidTrace`] message associated with the submission. + pub message: BidTrace, + /// The execution payload for the submission. + #[serde(with = "crate::payload::beacon_payload_v4")] + pub execution_payload: ExecutionPayloadV4, + /// The Electra block bundle for this bid. + pub blobs_bundle: BlobsBundleV1, + /// The signature associated with the submission. + pub signature: BlsSignature, +} + /// SubmitBlockRequest is the request from the builder to submit a block. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SubmitBlockRequest { diff --git a/crates/rpc-types-engine/src/payload.rs b/crates/rpc-types-engine/src/payload.rs index 1d35a261594..93e37fb0291 100644 --- a/crates/rpc-types-engine/src/payload.rs +++ b/crates/rpc-types-engine/src/payload.rs @@ -476,6 +476,118 @@ impl ExecutionPayloadV4 { } } +#[cfg(feature = "ssz")] +impl ssz::Decode for ExecutionPayloadV4 { + fn is_ssz_fixed_len() -> bool { + false + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let mut builder = ssz::SszDecoderBuilder::new(bytes); + + builder.register_type::()?; + builder.register_type::
()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::>()?; + builder.register_type::>()?; + builder.register_type::()?; + builder.register_type::()?; + builder.register_type::>()?; + builder.register_type::>()?; + builder.register_type::>()?; + + let mut decoder = builder.build()?; + + Ok(Self { + payload_inner: ExecutionPayloadV3 { + payload_inner: ExecutionPayloadV2 { + payload_inner: ExecutionPayloadV1 { + parent_hash: decoder.decode_next()?, + fee_recipient: decoder.decode_next()?, + state_root: decoder.decode_next()?, + receipts_root: decoder.decode_next()?, + logs_bloom: decoder.decode_next()?, + prev_randao: decoder.decode_next()?, + block_number: decoder.decode_next()?, + gas_limit: decoder.decode_next()?, + gas_used: decoder.decode_next()?, + timestamp: decoder.decode_next()?, + extra_data: decoder.decode_next()?, + base_fee_per_gas: decoder.decode_next()?, + block_hash: decoder.decode_next()?, + transactions: decoder.decode_next()?, + }, + withdrawals: decoder.decode_next()?, + }, + blob_gas_used: decoder.decode_next()?, + excess_blob_gas: decoder.decode_next()?, + }, + deposit_requests: decoder.decode_next()?, + withdrawal_requests: decoder.decode_next()?, + consolidation_requests: decoder.decode_next()?, + }) + } +} + +#[cfg(feature = "ssz")] +impl ssz::Encode for ExecutionPayloadV4 { + fn is_ssz_fixed_len() -> bool { + false + } + + fn ssz_append(&self, buf: &mut Vec) { + let offset = ::ssz_fixed_len() * 5 + +
::ssz_fixed_len() + + ::ssz_fixed_len() + + ::ssz_fixed_len() * 6 + + ::ssz_fixed_len() + + ssz::BYTES_PER_LENGTH_OFFSET * 6; + + let mut encoder = ssz::SszEncoder::container(buf, offset); + + encoder.append(&self.payload_inner.payload_inner.payload_inner.parent_hash); + encoder.append(&self.payload_inner.payload_inner.payload_inner.fee_recipient); + encoder.append(&self.payload_inner.payload_inner.payload_inner.state_root); + encoder.append(&self.payload_inner.payload_inner.payload_inner.receipts_root); + encoder.append(&self.payload_inner.payload_inner.payload_inner.logs_bloom); + encoder.append(&self.payload_inner.payload_inner.payload_inner.prev_randao); + encoder.append(&self.payload_inner.payload_inner.payload_inner.block_number); + encoder.append(&self.payload_inner.payload_inner.payload_inner.gas_limit); + encoder.append(&self.payload_inner.payload_inner.payload_inner.gas_used); + encoder.append(&self.payload_inner.payload_inner.payload_inner.timestamp); + encoder.append(&self.payload_inner.payload_inner.payload_inner.extra_data); + encoder.append(&self.payload_inner.payload_inner.payload_inner.base_fee_per_gas); + encoder.append(&self.payload_inner.payload_inner.payload_inner.block_hash); + encoder.append(&self.payload_inner.payload_inner.payload_inner.transactions); + encoder.append(&self.payload_inner.payload_inner.withdrawals); + encoder.append(&self.payload_inner.blob_gas_used); + encoder.append(&self.payload_inner.excess_blob_gas); + encoder.append(&self.deposit_requests); + encoder.append(&self.withdrawal_requests); + encoder.append(&self.consolidation_requests); + + encoder.finalize(); + } + + fn ssz_bytes_len(&self) -> usize { + ::ssz_bytes_len(&self.payload_inner) + + ssz::BYTES_PER_LENGTH_OFFSET * 3 + + self.deposit_requests.ssz_bytes_len() + + self.withdrawal_requests.ssz_bytes_len() + + self.consolidation_requests.ssz_bytes_len() + } +} + /// This includes all bundled blob related data of an executed payload. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]