mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add more beacon API types (#5292)
This commit is contained in:
4
crates/rpc/rpc-types/src/beacon/constants.rs
Normal file
4
crates/rpc/rpc-types/src/beacon/constants.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub const BLS_DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
|
||||||
|
pub const BLS_PUBLIC_KEY_BYTES_LEN: usize = 48;
|
||||||
|
pub const BLS_SECRET_KEY_BYTES_LEN: usize = 32;
|
||||||
|
pub const BLS_SIGNATURE_BYTES_LEN: usize = 96;
|
||||||
@ -270,7 +270,7 @@ pub struct PayloadAttributesData {
|
|||||||
///
|
///
|
||||||
/// Note: this uses the beacon API format which uses snake-case and quoted decimals rather than
|
/// Note: this uses the beacon API format which uses snake-case and quoted decimals rather than
|
||||||
/// big-endian hex.
|
/// big-endian hex.
|
||||||
#[serde(with = "crate::eth::engine::payload::beacon_api_payload_attributes")]
|
#[serde(with = "crate::beacon::payload::beacon_api_payload_attributes")]
|
||||||
pub payload_attributes: PayloadAttributes,
|
pub payload_attributes: PayloadAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
17
crates/rpc/rpc-types/src/beacon/mod.rs
Normal file
17
crates/rpc/rpc-types/src/beacon/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
//! Types for the Ethereum 2.0 RPC protocol (beacon chain)
|
||||||
|
|
||||||
|
use alloy_primitives::FixedBytes;
|
||||||
|
use constants::{BLS_PUBLIC_KEY_BYTES_LEN, BLS_SIGNATURE_BYTES_LEN};
|
||||||
|
|
||||||
|
pub mod constants;
|
||||||
|
/// Beacon API events support.
|
||||||
|
pub mod events;
|
||||||
|
pub mod payload;
|
||||||
|
pub mod withdrawals;
|
||||||
|
|
||||||
|
/// BLS signature type
|
||||||
|
pub type BlsSignature = FixedBytes<BLS_SIGNATURE_BYTES_LEN>;
|
||||||
|
|
||||||
|
/// BLS public key type
|
||||||
|
pub type BlsPublicKey = FixedBytes<BLS_PUBLIC_KEY_BYTES_LEN>;
|
||||||
460
crates/rpc/rpc-types/src/beacon/payload.rs
Normal file
460
crates/rpc/rpc-types/src/beacon/payload.rs
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#![allow(missing_docs)]
|
||||||
|
//! Payload support for the beacon API.
|
||||||
|
//!
|
||||||
|
//! Internal helper module to deserialize/serialize the payload attributes for the beacon API, which
|
||||||
|
//! uses snake case and quoted decimals.
|
||||||
|
//!
|
||||||
|
//! This is necessary because we don't want to allow a mixture of both formats, hence `serde`
|
||||||
|
//! aliases are not an option.
|
||||||
|
//!
|
||||||
|
//! See also <https://github.com/ethereum/consensus-specs/blob/master/specs/deneb/beacon-chain.md#executionpayload>
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
beacon::withdrawals::BeaconWithdrawal, engine::ExecutionPayloadV3, ExecutionPayload,
|
||||||
|
ExecutionPayloadV1, ExecutionPayloadV2, Withdrawal,
|
||||||
|
};
|
||||||
|
use alloy_primitives::{Address, Bloom, Bytes, B256, U256, U64};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde_with::{serde_as, DeserializeAs, DisplayFromStr, SerializeAs};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct BeaconPayloadAttributes {
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
timestamp: u64,
|
||||||
|
prev_randao: B256,
|
||||||
|
suggested_fee_recipient: Address,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde_as(as = "Option<Vec<BeaconWithdrawal>>")]
|
||||||
|
withdrawals: Option<Vec<Withdrawal>>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
parent_beacon_block_root: Option<B256>,
|
||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
#[serde(flatten)]
|
||||||
|
optimism_payload_attributes: BeaconOptimismPayloadAttributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Optimism Payload Attributes
|
||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct BeaconOptimismPayloadAttributes {
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
transactions: Option<Vec<Bytes>>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
no_tx_pool: Option<bool>,
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||||
|
gas_limit: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper module for serializing and deserializing the payload attributes for the beacon API.
|
||||||
|
///
|
||||||
|
/// The beacon API encoded object has equivalent fields to the
|
||||||
|
/// [PayloadAttributes](crate::engine::PayloadAttributes) with two differences:
|
||||||
|
/// 1) `snake_case` identifiers must be used rather than `camelCase`;
|
||||||
|
/// 2) integers must be encoded as quoted decimals rather than big-endian hex.
|
||||||
|
pub mod beacon_api_payload_attributes {
|
||||||
|
use super::*;
|
||||||
|
use crate::engine::PayloadAttributes;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(
|
||||||
|
payload_attributes: &PayloadAttributes,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let beacon_api_payload_attributes = BeaconPayloadAttributes {
|
||||||
|
timestamp: payload_attributes.timestamp.to(),
|
||||||
|
prev_randao: payload_attributes.prev_randao,
|
||||||
|
suggested_fee_recipient: payload_attributes.suggested_fee_recipient,
|
||||||
|
withdrawals: payload_attributes.withdrawals.clone(),
|
||||||
|
parent_beacon_block_root: payload_attributes.parent_beacon_block_root,
|
||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
optimism_payload_attributes: BeaconOptimismPayloadAttributes {
|
||||||
|
transactions: payload_attributes.optimism_payload_attributes.transactions.clone(),
|
||||||
|
no_tx_pool: payload_attributes.optimism_payload_attributes.no_tx_pool,
|
||||||
|
gas_limit: payload_attributes.optimism_payload_attributes.gas_limit,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
beacon_api_payload_attributes.serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<PayloadAttributes, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let beacon_api_payload_attributes = BeaconPayloadAttributes::deserialize(deserializer)?;
|
||||||
|
Ok(PayloadAttributes {
|
||||||
|
timestamp: U64::from(beacon_api_payload_attributes.timestamp),
|
||||||
|
prev_randao: beacon_api_payload_attributes.prev_randao,
|
||||||
|
suggested_fee_recipient: beacon_api_payload_attributes.suggested_fee_recipient,
|
||||||
|
withdrawals: beacon_api_payload_attributes.withdrawals,
|
||||||
|
parent_beacon_block_root: beacon_api_payload_attributes.parent_beacon_block_root,
|
||||||
|
#[cfg(feature = "optimism")]
|
||||||
|
optimism_payload_attributes: crate::eth::engine::OptimismPayloadAttributes {
|
||||||
|
transactions: beacon_api_payload_attributes
|
||||||
|
.optimism_payload_attributes
|
||||||
|
.transactions,
|
||||||
|
no_tx_pool: beacon_api_payload_attributes.optimism_payload_attributes.no_tx_pool,
|
||||||
|
gas_limit: beacon_api_payload_attributes.optimism_payload_attributes.gas_limit,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct BeaconExecutionPayloadV1<'a> {
|
||||||
|
parent_hash: Cow<'a, B256>,
|
||||||
|
fee_recipient: Cow<'a, Address>,
|
||||||
|
state_root: Cow<'a, B256>,
|
||||||
|
receipts_root: Cow<'a, B256>,
|
||||||
|
logs_bloom: Cow<'a, Bloom>,
|
||||||
|
prev_randao: Cow<'a, B256>,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
block_number: u64,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
gas_limit: u64,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
gas_used: u64,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
timestamp: u64,
|
||||||
|
extra_data: Cow<'a, Bytes>,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
base_fee_per_gas: U256,
|
||||||
|
block_hash: Cow<'a, B256>,
|
||||||
|
transactions: Cow<'a, Vec<Bytes>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<BeaconExecutionPayloadV1<'a>> for ExecutionPayloadV1 {
|
||||||
|
fn from(payload: BeaconExecutionPayloadV1<'a>) -> Self {
|
||||||
|
let BeaconExecutionPayloadV1 {
|
||||||
|
parent_hash,
|
||||||
|
fee_recipient,
|
||||||
|
state_root,
|
||||||
|
receipts_root,
|
||||||
|
logs_bloom,
|
||||||
|
prev_randao,
|
||||||
|
block_number,
|
||||||
|
gas_limit,
|
||||||
|
gas_used,
|
||||||
|
timestamp,
|
||||||
|
extra_data,
|
||||||
|
base_fee_per_gas,
|
||||||
|
block_hash,
|
||||||
|
transactions,
|
||||||
|
} = payload;
|
||||||
|
ExecutionPayloadV1 {
|
||||||
|
parent_hash: parent_hash.into_owned(),
|
||||||
|
fee_recipient: fee_recipient.into_owned(),
|
||||||
|
state_root: state_root.into_owned(),
|
||||||
|
receipts_root: receipts_root.into_owned(),
|
||||||
|
logs_bloom: logs_bloom.into_owned(),
|
||||||
|
prev_randao: prev_randao.into_owned(),
|
||||||
|
block_number: U64::from(block_number),
|
||||||
|
gas_limit: U64::from(gas_limit),
|
||||||
|
gas_used: U64::from(gas_used),
|
||||||
|
timestamp: U64::from(timestamp),
|
||||||
|
extra_data: extra_data.into_owned(),
|
||||||
|
base_fee_per_gas,
|
||||||
|
block_hash: block_hash.into_owned(),
|
||||||
|
transactions: transactions.into_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ExecutionPayloadV1> for BeaconExecutionPayloadV1<'a> {
|
||||||
|
fn from(value: &'a ExecutionPayloadV1) -> Self {
|
||||||
|
let ExecutionPayloadV1 {
|
||||||
|
parent_hash,
|
||||||
|
fee_recipient,
|
||||||
|
state_root,
|
||||||
|
receipts_root,
|
||||||
|
logs_bloom,
|
||||||
|
prev_randao,
|
||||||
|
block_number,
|
||||||
|
gas_limit,
|
||||||
|
gas_used,
|
||||||
|
timestamp,
|
||||||
|
extra_data,
|
||||||
|
base_fee_per_gas,
|
||||||
|
block_hash,
|
||||||
|
transactions,
|
||||||
|
} = value;
|
||||||
|
|
||||||
|
BeaconExecutionPayloadV1 {
|
||||||
|
parent_hash: Cow::Borrowed(parent_hash),
|
||||||
|
fee_recipient: Cow::Borrowed(fee_recipient),
|
||||||
|
state_root: Cow::Borrowed(state_root),
|
||||||
|
receipts_root: Cow::Borrowed(receipts_root),
|
||||||
|
logs_bloom: Cow::Borrowed(logs_bloom),
|
||||||
|
prev_randao: Cow::Borrowed(prev_randao),
|
||||||
|
block_number: block_number.to(),
|
||||||
|
gas_limit: gas_limit.to(),
|
||||||
|
gas_used: gas_used.to(),
|
||||||
|
timestamp: timestamp.to(),
|
||||||
|
extra_data: Cow::Borrowed(extra_data),
|
||||||
|
base_fee_per_gas: *base_fee_per_gas,
|
||||||
|
block_hash: Cow::Borrowed(block_hash),
|
||||||
|
transactions: Cow::Borrowed(transactions),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper serde module to convert from/to the Beacon API which uses quoted decimals rather than
|
||||||
|
/// big-endian hex.
|
||||||
|
pub mod beacon_payload_v1 {
|
||||||
|
use super::*;
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(
|
||||||
|
payload_attributes: &ExecutionPayloadV1,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV1::from(payload_attributes).serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<ExecutionPayloadV1, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV1::deserialize(deserializer).map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct BeaconExecutionPayloadV2<'a> {
|
||||||
|
/// Inner V1 payload
|
||||||
|
#[serde(flatten)]
|
||||||
|
payload_inner: BeaconExecutionPayloadV1<'a>,
|
||||||
|
/// Array of [`Withdrawal`] enabled with V2
|
||||||
|
/// See <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/shanghai.md#executionpayloadv2>
|
||||||
|
#[serde_as(as = "Vec<BeaconWithdrawal>")]
|
||||||
|
withdrawals: Vec<Withdrawal>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<BeaconExecutionPayloadV2<'a>> for ExecutionPayloadV2 {
|
||||||
|
fn from(payload: BeaconExecutionPayloadV2<'a>) -> Self {
|
||||||
|
let BeaconExecutionPayloadV2 { payload_inner, withdrawals } = payload;
|
||||||
|
ExecutionPayloadV2 { payload_inner: payload_inner.into(), withdrawals }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ExecutionPayloadV2> for BeaconExecutionPayloadV2<'a> {
|
||||||
|
fn from(value: &'a ExecutionPayloadV2) -> Self {
|
||||||
|
let ExecutionPayloadV2 { payload_inner, withdrawals } = value;
|
||||||
|
BeaconExecutionPayloadV2 {
|
||||||
|
payload_inner: payload_inner.into(),
|
||||||
|
withdrawals: withdrawals.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper serde module to convert from/to the Beacon API which uses quoted decimals rather than
|
||||||
|
/// big-endian hex.
|
||||||
|
pub mod beacon_payload_v2 {
|
||||||
|
use super::*;
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(
|
||||||
|
payload_attributes: &ExecutionPayloadV2,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV2::from(payload_attributes).serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<ExecutionPayloadV2, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV2::deserialize(deserializer).map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct BeaconExecutionPayloadV3<'a> {
|
||||||
|
/// Inner V1 payload
|
||||||
|
#[serde(flatten)]
|
||||||
|
payload_inner: BeaconExecutionPayloadV2<'a>,
|
||||||
|
/// Array of [`U64`] representing blob gas used, enabled with V3
|
||||||
|
/// See <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#ExecutionPayloadV3>
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
blob_gas_used: u64,
|
||||||
|
/// Array of [`U64`] representing excess blob gas, enabled with V3
|
||||||
|
/// See <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#ExecutionPayloadV3>
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
excess_blob_gas: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<BeaconExecutionPayloadV3<'a>> for ExecutionPayloadV3 {
|
||||||
|
fn from(payload: BeaconExecutionPayloadV3<'a>) -> Self {
|
||||||
|
let BeaconExecutionPayloadV3 { payload_inner, blob_gas_used, excess_blob_gas } = payload;
|
||||||
|
ExecutionPayloadV3 {
|
||||||
|
payload_inner: payload_inner.into(),
|
||||||
|
blob_gas_used: U64::from(blob_gas_used),
|
||||||
|
excess_blob_gas: U64::from(excess_blob_gas),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ExecutionPayloadV3> for BeaconExecutionPayloadV3<'a> {
|
||||||
|
fn from(value: &'a ExecutionPayloadV3) -> Self {
|
||||||
|
let ExecutionPayloadV3 { payload_inner, blob_gas_used, excess_blob_gas } = value;
|
||||||
|
BeaconExecutionPayloadV3 {
|
||||||
|
payload_inner: payload_inner.into(),
|
||||||
|
blob_gas_used: blob_gas_used.to(),
|
||||||
|
excess_blob_gas: excess_blob_gas.to(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper serde module to convert from/to the Beacon API which uses quoted decimals rather than
|
||||||
|
/// big-endian hex.
|
||||||
|
pub mod beacon_payload_v3 {
|
||||||
|
use super::*;
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(
|
||||||
|
payload_attributes: &ExecutionPayloadV3,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV3::from(payload_attributes).serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<ExecutionPayloadV3, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayloadV3::deserialize(deserializer).map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents all possible payload versions.
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum BeaconExecutionPayload<'a> {
|
||||||
|
/// V1 payload
|
||||||
|
V1(BeaconExecutionPayloadV1<'a>),
|
||||||
|
/// V2 payload
|
||||||
|
V2(BeaconExecutionPayloadV2<'a>),
|
||||||
|
/// V3 payload
|
||||||
|
V3(BeaconExecutionPayloadV3<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserializes untagged ExecutionPayload by trying each variant in falling order
|
||||||
|
impl<'de> Deserialize<'de> for BeaconExecutionPayload<'de> {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum BeaconExecutionPayloadDesc<'a> {
|
||||||
|
V3(BeaconExecutionPayloadV3<'a>),
|
||||||
|
V2(BeaconExecutionPayloadV2<'a>),
|
||||||
|
V1(BeaconExecutionPayloadV1<'a>),
|
||||||
|
}
|
||||||
|
match BeaconExecutionPayloadDesc::deserialize(deserializer)? {
|
||||||
|
BeaconExecutionPayloadDesc::V3(payload) => Ok(Self::V3(payload)),
|
||||||
|
BeaconExecutionPayloadDesc::V2(payload) => Ok(Self::V2(payload)),
|
||||||
|
BeaconExecutionPayloadDesc::V1(payload) => Ok(Self::V1(payload)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<BeaconExecutionPayload<'a>> for ExecutionPayload {
|
||||||
|
fn from(payload: BeaconExecutionPayload<'a>) -> Self {
|
||||||
|
match payload {
|
||||||
|
BeaconExecutionPayload::V1(payload) => {
|
||||||
|
ExecutionPayload::V1(ExecutionPayloadV1::from(payload))
|
||||||
|
}
|
||||||
|
BeaconExecutionPayload::V2(payload) => {
|
||||||
|
ExecutionPayload::V2(ExecutionPayloadV2::from(payload))
|
||||||
|
}
|
||||||
|
BeaconExecutionPayload::V3(payload) => {
|
||||||
|
ExecutionPayload::V3(ExecutionPayloadV3::from(payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ExecutionPayload> for BeaconExecutionPayload<'a> {
|
||||||
|
fn from(value: &'a ExecutionPayload) -> Self {
|
||||||
|
match value {
|
||||||
|
ExecutionPayload::V1(payload) => {
|
||||||
|
BeaconExecutionPayload::V1(BeaconExecutionPayloadV1::from(payload))
|
||||||
|
}
|
||||||
|
ExecutionPayload::V2(payload) => {
|
||||||
|
BeaconExecutionPayload::V2(BeaconExecutionPayloadV2::from(payload))
|
||||||
|
}
|
||||||
|
ExecutionPayload::V3(payload) => {
|
||||||
|
BeaconExecutionPayload::V3(BeaconExecutionPayloadV3::from(payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SerializeAs<ExecutionPayload> for BeaconExecutionPayload<'a> {
|
||||||
|
fn serialize_as<S>(source: &ExecutionPayload, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
beacon_payload::serialize(source, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> DeserializeAs<'de, ExecutionPayload> for BeaconExecutionPayload<'de> {
|
||||||
|
fn deserialize_as<D>(deserializer: D) -> Result<ExecutionPayload, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
beacon_payload::deserialize(deserializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod beacon_payload {
|
||||||
|
use super::*;
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(
|
||||||
|
payload_attributes: &ExecutionPayload,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayload::from(payload_attributes).serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<ExecutionPayload, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
BeaconExecutionPayload::deserialize(deserializer).map(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
72
crates/rpc/rpc-types/src/beacon/withdrawals.rs
Normal file
72
crates/rpc/rpc-types/src/beacon/withdrawals.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use alloy_primitives::Address;
|
||||||
|
|
||||||
|
use crate::Withdrawal;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use serde_with::{serde_as, DeserializeAs, DisplayFromStr, SerializeAs};
|
||||||
|
|
||||||
|
/// Same as [Withdrawal] but respects the Beacon API format which uses snake-case and quoted
|
||||||
|
/// decimals.
|
||||||
|
#[serde_as]
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub(crate) struct BeaconWithdrawal {
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
index: u64,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
validator_index: u64,
|
||||||
|
address: Address,
|
||||||
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerializeAs<Withdrawal> for BeaconWithdrawal {
|
||||||
|
fn serialize_as<S>(source: &Withdrawal, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
beacon_withdrawals::serialize(source, serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> DeserializeAs<'de, Withdrawal> for BeaconWithdrawal {
|
||||||
|
fn deserialize_as<D>(deserializer: D) -> Result<Withdrawal, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
beacon_withdrawals::deserialize(deserializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper serde module to convert from/to the Beacon API which uses quoted decimals rather than
|
||||||
|
/// big-endian hex.
|
||||||
|
pub mod beacon_withdrawals {
|
||||||
|
use super::*;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Serialize the payload attributes for the beacon API.
|
||||||
|
pub fn serialize<S>(payload_attributes: &Withdrawal, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let withdrawal = BeaconWithdrawal {
|
||||||
|
index: payload_attributes.index,
|
||||||
|
validator_index: payload_attributes.validator_index,
|
||||||
|
address: payload_attributes.address,
|
||||||
|
amount: payload_attributes.amount,
|
||||||
|
};
|
||||||
|
withdrawal.serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deserialize the payload attributes for the beacon API.
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<Withdrawal, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let withdrawal = BeaconWithdrawal::deserialize(deserializer)?;
|
||||||
|
Ok(Withdrawal {
|
||||||
|
index: withdrawal.index,
|
||||||
|
validator_index: withdrawal.validator_index,
|
||||||
|
address: withdrawal.address,
|
||||||
|
amount: withdrawal.amount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +0,0 @@
|
|||||||
/// Beacon API events support.
|
|
||||||
pub mod events;
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
//! Engine API types: <https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md> and <https://eips.ethereum.org/EIPS/eip-3675> following the execution specs <https://github.com/ethereum/execution-apis/tree/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine>
|
|
||||||
|
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
//! Engine API types: <https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md> and <https://eips.ethereum.org/EIPS/eip-3675> following the execution specs <https://github.com/ethereum/execution-apis/tree/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine>
|
||||||
|
|
||||||
mod cancun;
|
mod cancun;
|
||||||
mod forkchoice;
|
mod forkchoice;
|
||||||
@ -8,9 +7,6 @@ pub mod payload;
|
|||||||
mod transition;
|
mod transition;
|
||||||
pub use self::{cancun::*, forkchoice::*, payload::*, transition::*};
|
pub use self::{cancun::*, forkchoice::*, payload::*, transition::*};
|
||||||
|
|
||||||
/// Beacon API types
|
|
||||||
pub mod beacon_api;
|
|
||||||
|
|
||||||
/// The list of all supported Engine capabilities available over the engine endpoint.
|
/// The list of all supported Engine capabilities available over the engine endpoint.
|
||||||
pub const CAPABILITIES: [&str; 12] = [
|
pub const CAPABILITIES: [&str; 12] = [
|
||||||
"engine_forkchoiceUpdatedV1",
|
"engine_forkchoiceUpdatedV1",
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
use crate::eth::{transaction::BlobTransactionSidecar, withdrawal::BeaconAPIWithdrawal};
|
use crate::eth::transaction::BlobTransactionSidecar;
|
||||||
pub use crate::Withdrawal;
|
pub use crate::Withdrawal;
|
||||||
use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256, U64};
|
use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256, U64};
|
||||||
use c_kzg::{Blob, Bytes48};
|
use c_kzg::{Blob, Bytes48};
|
||||||
use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
|
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_with::{serde_as, DisplayFromStr};
|
|
||||||
|
|
||||||
/// The execution payload body response that allows for `null` values.
|
/// The execution payload body response that allows for `null` values.
|
||||||
pub type ExecutionPayloadBodiesV1 = Vec<Option<ExecutionPayloadBodyV1>>;
|
pub type ExecutionPayloadBodiesV1 = Vec<Option<ExecutionPayloadBodyV1>>;
|
||||||
@ -229,7 +228,8 @@ impl BlobsBundleV1 {
|
|||||||
|
|
||||||
/// An execution payload, which can be either [ExecutionPayloadV1], [ExecutionPayloadV2], or
|
/// An execution payload, which can be either [ExecutionPayloadV1], [ExecutionPayloadV2], or
|
||||||
/// [ExecutionPayloadV3].
|
/// [ExecutionPayloadV3].
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub enum ExecutionPayload {
|
pub enum ExecutionPayload {
|
||||||
/// V1 payload
|
/// V1 payload
|
||||||
V1(ExecutionPayloadV1),
|
V1(ExecutionPayloadV1),
|
||||||
@ -304,6 +304,27 @@ impl From<ExecutionPayloadV3> for ExecutionPayload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deserializes untagged ExecutionPayload by trying each variant in falling order
|
||||||
|
impl<'de> Deserialize<'de> for ExecutionPayload {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum ExecutionPayloadDesc {
|
||||||
|
V3(ExecutionPayloadV3),
|
||||||
|
V2(ExecutionPayloadV2),
|
||||||
|
V1(ExecutionPayloadV1),
|
||||||
|
}
|
||||||
|
match ExecutionPayloadDesc::deserialize(deserializer)? {
|
||||||
|
ExecutionPayloadDesc::V3(payload) => Ok(Self::V3(payload)),
|
||||||
|
ExecutionPayloadDesc::V2(payload) => Ok(Self::V2(payload)),
|
||||||
|
ExecutionPayloadDesc::V1(payload) => Ok(Self::V1(payload)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Error that can occur when handling payloads.
|
/// Error that can occur when handling payloads.
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum PayloadError {
|
pub enum PayloadError {
|
||||||
@ -405,71 +426,6 @@ pub struct OptimismPayloadAttributes {
|
|||||||
pub gas_limit: Option<u64>,
|
pub gas_limit: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct BeaconAPIPayloadAttributes {
|
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
|
||||||
timestamp: u64,
|
|
||||||
prev_randao: B256,
|
|
||||||
suggested_fee_recipient: Address,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
#[serde_as(as = "Option<Vec<BeaconAPIWithdrawal>>")]
|
|
||||||
withdrawals: Option<Vec<Withdrawal>>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
parent_beacon_block_root: Option<B256>,
|
|
||||||
#[cfg(feature = "optimism")]
|
|
||||||
#[serde(flatten)]
|
|
||||||
optimism_payload_attributes: OptimismPayloadAttributes,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper module for serializing and deserializing the payload attributes for the beacon API.
|
|
||||||
///
|
|
||||||
/// The beacon API encoded object has equivalent fields to the [PayloadAttributes] with two
|
|
||||||
/// differences:
|
|
||||||
/// 1) `snake_case` identifiers must be used rather than `camelCase`;
|
|
||||||
/// 2) integers must be encoded as quoted decimals rather than big-endian hex.
|
|
||||||
pub mod beacon_api_payload_attributes {
|
|
||||||
use super::*;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
|
|
||||||
/// Serialize the payload attributes for the beacon API.
|
|
||||||
pub fn serialize<S>(
|
|
||||||
payload_attributes: &PayloadAttributes,
|
|
||||||
serializer: S,
|
|
||||||
) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let beacon_api_payload_attributes = BeaconAPIPayloadAttributes {
|
|
||||||
timestamp: payload_attributes.timestamp.to(),
|
|
||||||
prev_randao: payload_attributes.prev_randao,
|
|
||||||
suggested_fee_recipient: payload_attributes.suggested_fee_recipient,
|
|
||||||
withdrawals: payload_attributes.withdrawals.clone(),
|
|
||||||
parent_beacon_block_root: payload_attributes.parent_beacon_block_root,
|
|
||||||
#[cfg(feature = "optimism")]
|
|
||||||
optimism_payload_attributes: payload_attributes.optimism_payload_attributes.clone(),
|
|
||||||
};
|
|
||||||
beacon_api_payload_attributes.serialize(serializer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialize the payload attributes for the beacon API.
|
|
||||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<PayloadAttributes, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let beacon_api_payload_attributes = BeaconAPIPayloadAttributes::deserialize(deserializer)?;
|
|
||||||
Ok(PayloadAttributes {
|
|
||||||
timestamp: U64::from(beacon_api_payload_attributes.timestamp),
|
|
||||||
prev_randao: beacon_api_payload_attributes.prev_randao,
|
|
||||||
suggested_fee_recipient: beacon_api_payload_attributes.suggested_fee_recipient,
|
|
||||||
withdrawals: beacon_api_payload_attributes.withdrawals,
|
|
||||||
parent_beacon_block_root: beacon_api_payload_attributes.parent_beacon_block_root,
|
|
||||||
#[cfg(feature = "optimism")]
|
|
||||||
optimism_payload_attributes: beacon_api_payload_attributes.optimism_payload_attributes,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This structure contains the result of processing a payload or fork choice update.
|
/// This structure contains the result of processing a payload or fork choice update.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@ -715,6 +671,9 @@ mod tests {
|
|||||||
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x44bb4b98c59dbb726f96ffceb5ee028dcbe35b9bba4f9ffd56aeebf8d1e4db62","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0x5655011482546f16b2312ef18e9fad03d6a52b1be95401aea884b222477f9e64","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"]}"#;
|
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x44bb4b98c59dbb726f96ffceb5ee028dcbe35b9bba4f9ffd56aeebf8d1e4db62","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0x5655011482546f16b2312ef18e9fad03d6a52b1be95401aea884b222477f9e64","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"]}"#;
|
||||||
let payload: ExecutionPayloadV1 = serde_json::from_str(s).unwrap();
|
let payload: ExecutionPayloadV1 = serde_json::from_str(s).unwrap();
|
||||||
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
||||||
|
|
||||||
|
let any_payload: ExecutionPayload = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(any_payload, payload.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -723,6 +682,9 @@ mod tests {
|
|||||||
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x44bb4b98c59dbb726f96ffceb5ee028dcbe35b9bba4f9ffd56aeebf8d1e4db62","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0x5655011482546f16b2312ef18e9fad03d6a52b1be95401aea884b222477f9e64","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"],"withdrawals":[],"blobGasUsed":"0xb10b","excessBlobGas":"0xb10b"}"#;
|
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x44bb4b98c59dbb726f96ffceb5ee028dcbe35b9bba4f9ffd56aeebf8d1e4db62","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0x5655011482546f16b2312ef18e9fad03d6a52b1be95401aea884b222477f9e64","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"],"withdrawals":[],"blobGasUsed":"0xb10b","excessBlobGas":"0xb10b"}"#;
|
||||||
let payload: ExecutionPayloadV3 = serde_json::from_str(s).unwrap();
|
let payload: ExecutionPayloadV3 = serde_json::from_str(s).unwrap();
|
||||||
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
||||||
|
|
||||||
|
let any_payload: ExecutionPayload = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(any_payload, payload.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -731,6 +693,9 @@ mod tests {
|
|||||||
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x76a03cbcb7adce07fd284c61e4fa31e5e786175cefac54a29e46ec8efa28ea41","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x028111cb7d25918386a69656b3d17b2febe95fd0f11572c1a55c14f99fdfe3df","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0xa6f40ed042e61e88e76125dede8fff8026751ea14454b68fb534cea99f2b2a77","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"]}"#;
|
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x76a03cbcb7adce07fd284c61e4fa31e5e786175cefac54a29e46ec8efa28ea41","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x028111cb7d25918386a69656b3d17b2febe95fd0f11572c1a55c14f99fdfe3df","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0xa6f40ed042e61e88e76125dede8fff8026751ea14454b68fb534cea99f2b2a77","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"]}"#;
|
||||||
let payload: ExecutionPayloadV1 = serde_json::from_str(s).unwrap();
|
let payload: ExecutionPayloadV1 = serde_json::from_str(s).unwrap();
|
||||||
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
||||||
|
|
||||||
|
let any_payload: ExecutionPayload = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(any_payload, payload.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -739,6 +704,9 @@ mod tests {
|
|||||||
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x76a03cbcb7adce07fd284c61e4fa31e5e786175cefac54a29e46ec8efa28ea41","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x028111cb7d25918386a69656b3d17b2febe95fd0f11572c1a55c14f99fdfe3df","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0xa6f40ed042e61e88e76125dede8fff8026751ea14454b68fb534cea99f2b2a77","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"],"withdrawals":[],"blobGasUsed":"0xb10b","excessBlobGas":"0xb10b"}"#;
|
let s = r#"{"parentHash":"0x67ead97eb79b47a1638659942384143f36ed44275d4182799875ab5a87324055","feeRecipient":"0x0000000000000000000000000000000000000000","stateRoot":"0x76a03cbcb7adce07fd284c61e4fa31e5e786175cefac54a29e46ec8efa28ea41","receiptsRoot":"0x4e3c608a9f2e129fccb91a1dae7472e78013b8e654bccc8d224ce3d63ae17006","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","prevRandao":"0x028111cb7d25918386a69656b3d17b2febe95fd0f11572c1a55c14f99fdfe3df","blockNumber":"0x1","gasLimit":"0x2fefd8","gasUsed":"0xa860","timestamp":"0x1235","extraData":"0x8b726574682f76302e312e30","baseFeePerGas":"0x342770c0","blockHash":"0xa6f40ed042e61e88e76125dede8fff8026751ea14454b68fb534cea99f2b2a77","transactions":["0xf865808506fc23ac00830124f8940000000000000000000000000000000000000316018032a044b25a8b9b247d01586b3d59c71728ff49c9b84928d9e7fa3377ead3b5570b5da03ceac696601ff7ee6f5fe8864e2998db9babdf5eeba1a0cd5b4d44b3fcbd181b"],"withdrawals":[],"blobGasUsed":"0xb10b","excessBlobGas":"0xb10b"}"#;
|
||||||
let payload: ExecutionPayloadV3 = serde_json::from_str(s).unwrap();
|
let payload: ExecutionPayloadV3 = serde_json::from_str(s).unwrap();
|
||||||
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
assert_eq!(serde_json::to_string(&payload).unwrap(), s);
|
||||||
|
|
||||||
|
let any_payload: ExecutionPayload = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(any_payload, payload.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -927,7 +895,7 @@ mod tests {
|
|||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
struct Event {
|
struct Event {
|
||||||
#[serde(with = "beacon_api_payload_attributes")]
|
#[serde(with = "crate::beacon::payload::beacon_api_payload_attributes")]
|
||||||
payload: PayloadAttributes,
|
payload: PayloadAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ pub mod raw_log;
|
|||||||
pub mod state;
|
pub mod state;
|
||||||
mod syncing;
|
mod syncing;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
mod transaction;
|
pub mod transaction;
|
||||||
pub mod txpool;
|
pub mod txpool;
|
||||||
pub mod withdrawal;
|
pub mod withdrawal;
|
||||||
mod work;
|
mod work;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//! RPC types for transactions
|
||||||
|
|
||||||
pub use access_list::{AccessList, AccessListItem, AccessListWithGasUsed};
|
pub use access_list::{AccessList, AccessListItem, AccessListWithGasUsed};
|
||||||
use alloy_primitives::{Address, Bytes, B256, U128, U256, U64};
|
use alloy_primitives::{Address, Bytes, B256, U128, U256, U64};
|
||||||
pub use common::TransactionInfo;
|
pub use common::TransactionInfo;
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
//! Withdrawal type and serde helpers.
|
//! Withdrawal type and serde helpers.
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use crate::serde_helpers::u64_hex;
|
use crate::serde_helpers::u64_hex;
|
||||||
use alloy_primitives::{Address, U256};
|
use alloy_primitives::{Address, U256};
|
||||||
use alloy_rlp::{RlpDecodable, RlpEncodable};
|
use alloy_rlp::{RlpDecodable, RlpEncodable};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::{serde_as, DeserializeAs, DisplayFromStr, SerializeAs};
|
use std::mem;
|
||||||
|
|
||||||
/// Multiplier for converting gwei to wei.
|
/// Multiplier for converting gwei to wei.
|
||||||
pub const GWEI_TO_WEI: u64 = 1_000_000_000;
|
pub const GWEI_TO_WEI: u64 = 1_000_000_000;
|
||||||
@ -42,73 +40,6 @@ impl Withdrawal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [Withdrawal] but respects the Beacon API format which uses snake-case and quoted
|
|
||||||
/// decimals.
|
|
||||||
#[serde_as]
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub(crate) struct BeaconAPIWithdrawal {
|
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
|
||||||
index: u64,
|
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
|
||||||
validator_index: u64,
|
|
||||||
address: Address,
|
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
|
||||||
amount: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerializeAs<Withdrawal> for BeaconAPIWithdrawal {
|
|
||||||
fn serialize_as<S>(source: &Withdrawal, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
beacon_api_withdrawals::serialize(source, serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> DeserializeAs<'de, Withdrawal> for BeaconAPIWithdrawal {
|
|
||||||
fn deserialize_as<D>(deserializer: D) -> Result<Withdrawal, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
beacon_api_withdrawals::deserialize(deserializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper serde module to convert from/to the Beacon API which uses quoted decimals rather than
|
|
||||||
/// big-endian hex.
|
|
||||||
pub mod beacon_api_withdrawals {
|
|
||||||
use super::*;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
|
|
||||||
/// Serialize the payload attributes for the beacon API.
|
|
||||||
pub fn serialize<S>(payload_attributes: &Withdrawal, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let withdrawal = BeaconAPIWithdrawal {
|
|
||||||
index: payload_attributes.index,
|
|
||||||
validator_index: payload_attributes.validator_index,
|
|
||||||
address: payload_attributes.address,
|
|
||||||
amount: payload_attributes.amount,
|
|
||||||
};
|
|
||||||
withdrawal.serialize(serializer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialize the payload attributes for the beacon API.
|
|
||||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Withdrawal, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let withdrawal = BeaconAPIWithdrawal::deserialize(deserializer)?;
|
|
||||||
Ok(Withdrawal {
|
|
||||||
index: withdrawal.index,
|
|
||||||
validator_index: withdrawal.validator_index,
|
|
||||||
address: withdrawal.address,
|
|
||||||
amount: withdrawal.amount,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -12,11 +12,13 @@
|
|||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
mod admin;
|
mod admin;
|
||||||
|
pub mod beacon;
|
||||||
mod eth;
|
mod eth;
|
||||||
mod mev;
|
mod mev;
|
||||||
mod net;
|
mod net;
|
||||||
mod otterscan;
|
mod otterscan;
|
||||||
mod peer;
|
mod peer;
|
||||||
|
pub mod relay;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
mod serde_helpers;
|
mod serde_helpers;
|
||||||
|
|
||||||
|
|||||||
243
crates/rpc/rpc-types/src/relay.rs
Normal file
243
crates/rpc/rpc-types/src/relay.rs
Normal file
File diff suppressed because one or more lines are too long
@ -23,7 +23,7 @@ use reth::{
|
|||||||
ext::{RethCliExt, RethNodeCommandConfig},
|
ext::{RethCliExt, RethNodeCommandConfig},
|
||||||
Cli,
|
Cli,
|
||||||
},
|
},
|
||||||
rpc::types::engine::beacon_api::events::PayloadAttributesEvent,
|
rpc::types::beacon::events::PayloadAttributesEvent,
|
||||||
tasks::TaskSpawner,
|
tasks::TaskSpawner,
|
||||||
};
|
};
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
|||||||
Reference in New Issue
Block a user