feat: add more beacon API types (#5292)

This commit is contained in:
Matthias Seitz
2023-11-06 14:10:26 +01:00
committed by GitHub
parent fa803fd7ef
commit 29a8489982
17 changed files with 844 additions and 151 deletions

View 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;

View File

@ -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,
} }

View 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>;

View 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)
}
}

View 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,
})
}
}

View File

@ -1,2 +0,0 @@
/// Beacon API events support.
pub mod events;

View File

@ -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",

View File

@ -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,
} }

View File

@ -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;

View File

@ -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;

View File

@ -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::*;

View File

@ -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;

File diff suppressed because one or more lines are too long

View File

@ -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};