diff --git a/crates/rpc-types-beacon/Cargo.toml b/crates/rpc-types-beacon/Cargo.toml
index c9c06566033..21516cbfd84 100644
--- a/crates/rpc-types-beacon/Cargo.toml
+++ b/crates/rpc-types-beacon/Cargo.toml
@@ -22,6 +22,7 @@ workspace = true
alloy-eips = { workspace = true, features = ["serde"] }
alloy-rpc-types-engine.workspace = true
alloy-primitives.workspace = true
+alloy-consensus = { workspace = true, features = ["std"] }
# ssz
ethereum_ssz_derive = { workspace = true, optional = true }
diff --git a/crates/rpc-types-beacon/src/relay.rs b/crates/rpc-types-beacon/src/relay.rs
index dba211b29ee..4bd2d7dd3f6 100644
--- a/crates/rpc-types-beacon/src/relay.rs
+++ b/crates/rpc-types-beacon/src/relay.rs
@@ -3,7 +3,8 @@
//! See also
use crate::{BlsPublicKey, BlsSignature};
-use alloy_primitives::{Address, B256, U256};
+use alloy_eips::{eip4844::builder, eip4895::Withdrawal};
+use alloy_primitives::{Address, Bloom, Bytes, B256, U256};
use alloy_rpc_types_engine::{
BlobsBundleV1, ExecutionPayload, ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3,
};
@@ -96,7 +97,6 @@ pub struct SignedBidTrace {
/// Submission for the `/relay/v1/builder/blocks` endpoint (Bellatrix).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
-#[cfg_attr(feature = "ssz", derive(ssz_derive::Decode, ssz_derive::Encode))]
pub struct SignedBidSubmissionV1 {
/// The BidTrace message associated with the submission.
pub message: BidTrace,
@@ -107,10 +107,133 @@ pub struct SignedBidSubmissionV1 {
pub signature: BlsSignature,
}
+#[cfg(feature = "ssz")]
+impl ssz::Decode for SignedBidSubmissionV1 {
+ 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::()?;
+ builder.register_type::()?;
+ builder.register_type::()?;
+ builder.register_type::>()?;
+
+ builder.register_type::()?;
+
+ let mut decoder = builder.build()?;
+
+ Ok(Self {
+ message: BidTrace {
+ slot: decoder.decode_next()?,
+ parent_hash: decoder.decode_next()?,
+ block_hash: decoder.decode_next()?,
+ builder_pubkey: decoder.decode_next()?,
+ proposer_pubkey: decoder.decode_next()?,
+ proposer_fee_recipient: decoder.decode_next()?,
+ gas_limit: decoder.decode_next()?,
+ gas_used: decoder.decode_next()?,
+ value: decoder.decode_next()?,
+ },
+ execution_payload: 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()?,
+ },
+ signature: decoder.decode_next()?,
+ })
+ }
+}
+
+#[cfg(feature = "ssz")]
+impl ssz::Encode for SignedBidSubmissionV1 {
+ fn is_ssz_fixed_len() -> bool {
+ false
+ }
+
+ fn ssz_append(&self, buf: &mut Vec) {
+ let offset = ::ssz_fixed_len() * 7
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 7
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 2
+ + ssz::BYTES_PER_LENGTH_OFFSET * 2;
+
+ let mut encoder = ssz::SszEncoder::container(buf, offset);
+
+ encoder.append(&self.message.slot);
+ encoder.append(&self.message.parent_hash);
+ encoder.append(&self.message.block_hash);
+ encoder.append(&self.message.builder_pubkey);
+ encoder.append(&self.message.proposer_pubkey);
+ encoder.append(&self.message.proposer_fee_recipient);
+ encoder.append(&self.message.gas_limit);
+ encoder.append(&self.message.gas_used);
+ encoder.append(&self.message.value);
+ encoder.append(&self.execution_payload.parent_hash);
+ encoder.append(&self.execution_payload.fee_recipient);
+ encoder.append(&self.execution_payload.state_root);
+ encoder.append(&self.execution_payload.receipts_root);
+ encoder.append(&self.execution_payload.logs_bloom);
+ encoder.append(&self.execution_payload.prev_randao);
+ encoder.append(&self.execution_payload.block_number);
+ encoder.append(&self.execution_payload.gas_limit);
+ encoder.append(&self.execution_payload.gas_used);
+ encoder.append(&self.execution_payload.timestamp);
+ encoder.append(&self.execution_payload.extra_data);
+ encoder.append(&self.execution_payload.base_fee_per_gas);
+ encoder.append(&self.execution_payload.block_hash);
+ encoder.append(&self.execution_payload.transactions);
+ encoder.append(&self.signature);
+
+ encoder.finalize();
+ }
+
+ fn ssz_bytes_len(&self) -> usize {
+ ::ssz_bytes_len(&self.message)
+ + ::ssz_bytes_len(&self.execution_payload)
+ + ::ssz_bytes_len(&self.signature)
+ }
+}
+
/// Submission for the `/relay/v1/builder/blocks` endpoint (Capella).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
-#[cfg_attr(feature = "ssz", derive(ssz_derive::Decode, ssz_derive::Encode))]
pub struct SignedBidSubmissionV2 {
/// The BidTrace message associated with the submission.
pub message: BidTrace,
@@ -121,10 +244,138 @@ pub struct SignedBidSubmissionV2 {
pub signature: BlsSignature,
}
+#[cfg(feature = "ssz")]
+impl ssz::Decode for SignedBidSubmissionV2 {
+ 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::()?;
+ builder.register_type::()?;
+ builder.register_type::()?;
+ builder.register_type::>()?;
+ builder.register_type::>()?;
+
+ builder.register_type::()?;
+
+ let mut decoder = builder.build()?;
+
+ Ok(Self {
+ message: BidTrace {
+ slot: decoder.decode_next()?,
+ parent_hash: decoder.decode_next()?,
+ block_hash: decoder.decode_next()?,
+ builder_pubkey: decoder.decode_next()?,
+ proposer_pubkey: decoder.decode_next()?,
+ proposer_fee_recipient: decoder.decode_next()?,
+ gas_limit: decoder.decode_next()?,
+ gas_used: decoder.decode_next()?,
+ value: decoder.decode_next()?,
+ },
+ execution_payload: 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()?,
+ },
+ signature: decoder.decode_next()?,
+ })
+ }
+}
+
+#[cfg(feature = "ssz")]
+impl ssz::Encode for SignedBidSubmissionV2 {
+ fn is_ssz_fixed_len() -> bool {
+ false
+ }
+
+ fn ssz_append(&self, buf: &mut Vec) {
+ let offset = ::ssz_fixed_len() * 7
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 7
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 2
+ + ssz::BYTES_PER_LENGTH_OFFSET * 3;
+
+ let mut encoder = ssz::SszEncoder::container(buf, offset);
+
+ encoder.append(&self.message.slot);
+ encoder.append(&self.message.parent_hash);
+ encoder.append(&self.message.block_hash);
+ encoder.append(&self.message.builder_pubkey);
+ encoder.append(&self.message.proposer_pubkey);
+ encoder.append(&self.message.proposer_fee_recipient);
+ encoder.append(&self.message.gas_limit);
+ encoder.append(&self.message.gas_used);
+ encoder.append(&self.message.value);
+ encoder.append(&self.execution_payload.payload_inner.parent_hash);
+ encoder.append(&self.execution_payload.payload_inner.fee_recipient);
+ encoder.append(&self.execution_payload.payload_inner.state_root);
+ encoder.append(&self.execution_payload.payload_inner.receipts_root);
+ encoder.append(&self.execution_payload.payload_inner.logs_bloom);
+ encoder.append(&self.execution_payload.payload_inner.prev_randao);
+ encoder.append(&self.execution_payload.payload_inner.block_number);
+ encoder.append(&self.execution_payload.payload_inner.gas_limit);
+ encoder.append(&self.execution_payload.payload_inner.gas_used);
+ encoder.append(&self.execution_payload.payload_inner.timestamp);
+ encoder.append(&self.execution_payload.payload_inner.extra_data);
+ encoder.append(&self.execution_payload.payload_inner.base_fee_per_gas);
+ encoder.append(&self.execution_payload.payload_inner.block_hash);
+ encoder.append(&self.execution_payload.payload_inner.transactions);
+ encoder.append(&self.execution_payload.withdrawals);
+ encoder.append(&self.signature);
+
+ encoder.finalize();
+ }
+
+ fn ssz_bytes_len(&self) -> usize {
+ ::ssz_bytes_len(&self.message)
+ + ::ssz_bytes_len(&self.execution_payload)
+ + ::ssz_bytes_len(&self.signature)
+ }
+}
+
/// Submission for the `/relay/v1/builder/blocks` endpoint (Deneb).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
-#[cfg_attr(feature = "ssz", derive(ssz_derive::Decode, ssz_derive::Encode))]
pub struct SignedBidSubmissionV3 {
/// The BidTrace message associated with the submission.
pub message: BidTrace,
@@ -137,6 +388,156 @@ pub struct SignedBidSubmissionV3 {
pub signature: BlsSignature,
}
+#[cfg(feature = "ssz")]
+impl ssz::Decode for SignedBidSubmissionV3 {
+ 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::()?;
+ 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 {
+ message: BidTrace {
+ slot: decoder.decode_next()?,
+ parent_hash: decoder.decode_next()?,
+ block_hash: decoder.decode_next()?,
+ builder_pubkey: decoder.decode_next()?,
+ proposer_pubkey: decoder.decode_next()?,
+ proposer_fee_recipient: decoder.decode_next()?,
+ gas_limit: decoder.decode_next()?,
+ gas_used: decoder.decode_next()?,
+ value: decoder.decode_next()?,
+ },
+ execution_payload: 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()?,
+ },
+ blobs_bundle: BlobsBundleV1 {
+ commitments: decoder.decode_next()?,
+ proofs: decoder.decode_next()?,
+ blobs: decoder.decode_next()?,
+ },
+ signature: decoder.decode_next()?,
+ })
+ }
+}
+
+#[cfg(feature = "ssz")]
+impl ssz::Encode for SignedBidSubmissionV3 {
+ fn is_ssz_fixed_len() -> bool {
+ false
+ }
+
+ fn ssz_append(&self, buf: &mut Vec) {
+ let offset = ::ssz_fixed_len() * 7
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 9
+ + ::ssz_fixed_len() * 2
+ + ::ssz_fixed_len()
+ + ::ssz_fixed_len() * 2
+ + ssz::BYTES_PER_LENGTH_OFFSET * 6;
+
+ let mut encoder = ssz::SszEncoder::container(buf, offset);
+
+ encoder.append(&self.message.slot);
+ encoder.append(&self.message.parent_hash);
+ encoder.append(&self.message.block_hash);
+ encoder.append(&self.message.builder_pubkey);
+ encoder.append(&self.message.proposer_pubkey);
+ encoder.append(&self.message.proposer_fee_recipient);
+ encoder.append(&self.message.gas_limit);
+ encoder.append(&self.message.gas_used);
+ encoder.append(&self.message.value);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.parent_hash);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.fee_recipient);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.state_root);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.receipts_root);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.logs_bloom);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.prev_randao);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.block_number);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.gas_limit);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.gas_used);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.timestamp);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.extra_data);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.base_fee_per_gas);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.block_hash);
+ encoder.append(&self.execution_payload.payload_inner.payload_inner.transactions);
+ encoder.append(&self.execution_payload.payload_inner.withdrawals);
+ encoder.append(&self.execution_payload.blob_gas_used);
+ encoder.append(&self.execution_payload.excess_blob_gas);
+ encoder.append(&self.blobs_bundle.commitments);
+ encoder.append(&self.blobs_bundle.proofs);
+ encoder.append(&self.blobs_bundle.blobs);
+ encoder.append(&self.signature);
+
+ encoder.finalize();
+ }
+
+ fn ssz_bytes_len(&self) -> usize {
+ ::ssz_bytes_len(&self.message)
+ + ::ssz_bytes_len(&self.execution_payload)
+ + ::ssz_bytes_len(&self.blobs_bundle)
+ + ::ssz_bytes_len(&self.signature)
+ }
+}
+
/// SubmitBlockRequest is the request from the builder to submit a block.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SubmitBlockRequest {