merge with upstream

This commit is contained in:
realbigsean
2023-02-15 14:20:12 -05:00
63 changed files with 2499 additions and 454 deletions

View File

@@ -685,6 +685,24 @@ impl<E: EthSpec> From<BeaconBlock<E, FullPayload<E>>>
}
}
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
for BeaconBlock<T, Payload>
{
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
Ok(map_fork_name!(
fork_name,
Self,
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
"BeaconBlock failed to deserialize: {:?}",
e
)))?
))
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -278,7 +278,7 @@ impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
voluntary_exits,
sync_aggregate,
execution_payload: BlindedPayloadMerge {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: From::from(&execution_payload),
},
},
Some(execution_payload),
@@ -319,7 +319,7 @@ impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
voluntary_exits,
sync_aggregate,
execution_payload: BlindedPayloadCapella {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: From::from(&execution_payload),
},
bls_to_execution_changes,
},
@@ -362,7 +362,7 @@ impl<E: EthSpec> From<BeaconBlockBodyEip4844<E, FullPayload<E>>>
voluntary_exits,
sync_aggregate,
execution_payload: BlindedPayloadEip4844 {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: From::from(&execution_payload),
},
bls_to_execution_changes,
blob_kzg_commitments,
@@ -413,7 +413,7 @@ impl<E: EthSpec> BeaconBlockBodyMerge<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadMerge {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: execution_payload.into(),
},
}
}
@@ -446,7 +446,7 @@ impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadCapella {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: execution_payload.into(),
},
bls_to_execution_changes: bls_to_execution_changes.clone(),
}
@@ -481,7 +481,7 @@ impl<E: EthSpec> BeaconBlockBodyEip4844<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadEip4844 {
execution_payload_header: From::from(execution_payload.clone()),
execution_payload_header: execution_payload.into(),
},
bls_to_execution_changes: bls_to_execution_changes.clone(),
blob_kzg_commitments: blob_kzg_commitments.clone(),

View File

@@ -301,8 +301,10 @@ where
// Capella
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub next_withdrawal_index: u64,
#[superstruct(only(Capella, Eip4844), partial_getter(copy))]
#[serde(with = "eth2_serde_utils::quoted_u64")]
pub next_withdrawal_validator_index: u64,
// Deep history valid from Capella onwards.
#[superstruct(only(Capella, Eip4844))]
@@ -1853,3 +1855,19 @@ impl<T: EthSpec> CompareFields for BeaconState<T> {
}
}
}
impl<T: EthSpec> ForkVersionDeserialize for BeaconState<T> {
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
Ok(map_fork_name!(
fork_name,
Self,
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
"BeaconState failed to deserialize: {:?}",
e
)))?
))
}
}

View File

@@ -1,6 +1,6 @@
use crate::{
AbstractExecPayload, ChainSpec, EthSpec, ExecPayload, ExecutionPayloadHeader, SignedRoot,
Uint256,
AbstractExecPayload, ChainSpec, EthSpec, ExecPayload, ExecutionPayloadHeader, ForkName,
ForkVersionDeserialize, SignedRoot, Uint256,
};
use bls::PublicKeyBytes;
use bls::Signature;
@@ -34,6 +34,60 @@ pub struct SignedBuilderBid<E: EthSpec, Payload: AbstractExecPayload<E>> {
pub signature: Signature,
}
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
for BuilderBid<T, Payload>
{
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
let convert_err = |_| {
serde::de::Error::custom(
"BuilderBid failed to deserialize: unable to convert payload header to payload",
)
};
#[derive(Deserialize)]
struct Helper {
header: serde_json::Value,
#[serde(with = "eth2_serde_utils::quoted_u256")]
value: Uint256,
pubkey: PublicKeyBytes,
}
let helper: Helper = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
let payload_header =
ExecutionPayloadHeader::deserialize_by_fork::<'de, D>(helper.header, fork_name)?;
Ok(Self {
header: Payload::try_from(payload_header).map_err(convert_err)?,
value: helper.value,
pubkey: helper.pubkey,
_phantom_data: Default::default(),
})
}
}
impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
for SignedBuilderBid<T, Payload>
{
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
#[derive(Deserialize)]
struct Helper {
pub message: serde_json::Value,
pub signature: Signature,
}
let helper: Helper = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
Ok(Self {
message: BuilderBid::deserialize_by_fork::<'de, D>(helper.message, fork_name)?,
signature: helper.signature,
})
}
}
struct BlindedPayloadAsHeader<E>(PhantomData<E>);
impl<E: EthSpec, Payload: ExecPayload<E>> SerializeAs<Payload> for BlindedPayloadAsHeader<E> {

View File

@@ -35,7 +35,9 @@ pub type Withdrawals<T> = VariableList<Withdrawal, <T as EthSpec>::MaxWithdrawal
arbitrary(bound = "T: EthSpec")
),
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
map_into(FullPayload, BlindedPayload),
map_ref_into(ExecutionPayloadHeader)
)]
#[derive(
Debug, Clone, Serialize, Encode, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary,
@@ -146,3 +148,26 @@ impl<T: EthSpec> ExecutionPayload<T> {
+ (T::max_withdrawals_per_payload() * <Withdrawal as Encode>::ssz_fixed_len())
}
}
impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayload<T> {
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
let convert_err = |e| {
serde::de::Error::custom(format!("ExecutionPayload failed to deserialize: {:?}", e))
};
Ok(match fork_name {
ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Eip4844 => Self::Eip4844(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Base | ForkName::Altair => {
return Err(serde::de::Error::custom(format!(
"ExecutionPayload failed to deserialize: unsupported fork '{}'",
fork_name
)));
}
})
}
}

View File

@@ -159,40 +159,40 @@ impl<T: EthSpec> ExecutionPayloadHeaderCapella<T> {
}
}
impl<T: EthSpec> From<ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
fn from(payload: ExecutionPayloadMerge<T>) -> Self {
impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
fn from(payload: &'a ExecutionPayloadMerge<T>) -> Self {
Self {
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data,
extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
transactions_root: payload.transactions.tree_hash_root(),
}
}
}
impl<T: EthSpec> From<ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> {
fn from(payload: ExecutionPayloadCapella<T>) -> Self {
impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> {
fn from(payload: &'a ExecutionPayloadCapella<T>) -> Self {
Self {
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data,
extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
transactions_root: payload.transactions.tree_hash_root(),
@@ -200,20 +200,21 @@ impl<T: EthSpec> From<ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCape
}
}
}
impl<T: EthSpec> From<ExecutionPayloadEip4844<T>> for ExecutionPayloadHeaderEip4844<T> {
fn from(payload: ExecutionPayloadEip4844<T>) -> Self {
impl<'a, T: EthSpec> From<&'a ExecutionPayloadEip4844<T>> for ExecutionPayloadHeaderEip4844<T> {
fn from(payload: &'a ExecutionPayloadEip4844<T>) -> Self {
Self {
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
extra_data: payload.extra_data,
extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas,
excess_data_gas: payload.excess_data_gas,
block_hash: payload.block_hash,
@@ -223,31 +224,33 @@ impl<T: EthSpec> From<ExecutionPayloadEip4844<T>> for ExecutionPayloadHeaderEip4
}
}
impl<T: EthSpec> From<ExecutionPayloadMerge<T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayloadMerge<T>) -> Self {
Self::Merge(ExecutionPayloadHeaderMerge::from(payload))
// These impls are required to work around an inelegance in `to_execution_payload_header`.
// They only clone headers so they should be relatively cheap.
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderMerge<T> {
fn from(payload: &'a Self) -> Self {
payload.clone()
}
}
impl<T: EthSpec> From<ExecutionPayloadCapella<T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayloadCapella<T>) -> Self {
Self::Capella(ExecutionPayloadHeaderCapella::from(payload))
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderCapella<T> {
fn from(payload: &'a Self) -> Self {
payload.clone()
}
}
impl<T: EthSpec> From<ExecutionPayloadEip4844<T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayloadEip4844<T>) -> Self {
Self::Eip4844(ExecutionPayloadHeaderEip4844::from(payload))
impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderEip4844<T> {
fn from(payload: &'a Self) -> Self {
payload.clone()
}
}
impl<T: EthSpec> From<ExecutionPayload<T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayload<T>) -> Self {
match payload {
ExecutionPayload::Merge(payload) => Self::from(payload),
ExecutionPayload::Capella(payload) => Self::from(payload),
ExecutionPayload::Eip4844(payload) => Self::from(payload),
}
impl<'a, T: EthSpec> From<ExecutionPayloadRef<'a, T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayloadRef<'a, T>) -> Self {
map_execution_payload_ref_into_execution_payload_header!(
&'a _,
payload,
|inner, cons| cons(inner.into())
)
}
}
@@ -282,3 +285,29 @@ impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for ExecutionPayloadHeaderEi
}
}
}
impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayloadHeader<T> {
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
let convert_err = |e| {
serde::de::Error::custom(format!(
"ExecutionPayloadHeader failed to deserialize: {:?}",
e
))
};
Ok(match fork_name {
ForkName::Merge => Self::Merge(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Eip4844 => Self::Eip4844(serde_json::from_value(value).map_err(convert_err)?),
ForkName::Base | ForkName::Altair => {
return Err(serde::de::Error::custom(format!(
"ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'",
fork_name
)));
}
})
}
}

View File

@@ -0,0 +1,138 @@
use crate::ForkName;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::value::Value;
use std::sync::Arc;
// Deserialize is only implemented for types that implement ForkVersionDeserialize
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct ExecutionOptimisticForkVersionedResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<ForkName>,
pub execution_optimistic: Option<bool>,
pub data: T,
}
impl<'de, F> serde::Deserialize<'de> for ExecutionOptimisticForkVersionedResponse<F>
where
F: ForkVersionDeserialize,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Helper {
version: Option<ForkName>,
execution_optimistic: Option<bool>,
data: serde_json::Value,
}
let helper = Helper::deserialize(deserializer)?;
let data = match helper.version {
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
};
Ok(ExecutionOptimisticForkVersionedResponse {
version: helper.version,
execution_optimistic: helper.execution_optimistic,
data,
})
}
}
pub trait ForkVersionDeserialize: Sized + DeserializeOwned {
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
value: Value,
fork_name: ForkName,
) -> Result<Self, D::Error>;
}
// Deserialize is only implemented for types that implement ForkVersionDeserialize
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct ForkVersionedResponse<T> {
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<ForkName>,
pub data: T,
}
impl<'de, F> serde::Deserialize<'de> for ForkVersionedResponse<F>
where
F: ForkVersionDeserialize,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Helper {
version: Option<ForkName>,
data: serde_json::Value,
}
let helper = Helper::deserialize(deserializer)?;
let data = match helper.version {
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
};
Ok(ForkVersionedResponse {
version: helper.version,
data,
})
}
}
impl<F: ForkVersionDeserialize> ForkVersionDeserialize for Arc<F> {
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
value: Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
Ok(Arc::new(F::deserialize_by_fork::<'de, D>(
value, fork_name,
)?))
}
}
#[cfg(test)]
mod fork_version_response_tests {
use crate::{
ExecutionPayload, ExecutionPayloadMerge, ForkName, ForkVersionedResponse, MainnetEthSpec,
};
use serde_json::json;
#[test]
fn fork_versioned_response_deserialize_correct_fork() {
type E = MainnetEthSpec;
let response_json =
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
version: Some(ForkName::Merge),
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
}))
.unwrap();
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
serde_json::from_str(&response_json);
assert!(result.is_ok());
}
#[test]
fn fork_versioned_response_deserialize_incorrect_fork() {
type E = MainnetEthSpec;
let response_json =
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
version: Some(ForkName::Capella),
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
}))
.unwrap();
let result: Result<ForkVersionedResponse<ExecutionPayload<E>>, _> =
serde_json::from_str(&response_json);
assert!(result.is_err());
}
}

View File

@@ -46,6 +46,7 @@ pub mod execution_payload_header;
pub mod fork;
pub mod fork_data;
pub mod fork_name;
pub mod fork_versioned_response;
pub mod free_attestation;
pub mod graffiti;
pub mod historical_batch;
@@ -150,6 +151,9 @@ pub use crate::fork::Fork;
pub use crate::fork_context::ForkContext;
pub use crate::fork_data::ForkData;
pub use crate::fork_name::{ForkName, InconsistentFork};
pub use crate::fork_versioned_response::{
ExecutionOptimisticForkVersionedResponse, ForkVersionDeserialize, ForkVersionedResponse,
};
pub use crate::free_attestation::FreeAttestation;
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
pub use crate::historical_batch::HistoricalBatch;

View File

@@ -4,6 +4,7 @@ use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use ssz::{Decode, Encode};
use ssz_derive::{Decode, Encode};
use std::borrow::Cow;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::hash::Hash;
@@ -90,15 +91,15 @@ pub trait AbstractExecPayload<T: EthSpec>:
type Merge: OwnedExecPayload<T>
+ Into<Self>
+ From<ExecutionPayloadMerge<T>>
+ for<'a> From<Cow<'a, ExecutionPayloadMerge<T>>>
+ TryFrom<ExecutionPayloadHeaderMerge<T>>;
type Capella: OwnedExecPayload<T>
+ Into<Self>
+ From<ExecutionPayloadCapella<T>>
+ for<'a> From<Cow<'a, ExecutionPayloadCapella<T>>>
+ TryFrom<ExecutionPayloadHeaderCapella<T>>;
type Eip4844: OwnedExecPayload<T>
+ Into<Self>
+ From<ExecutionPayloadEip4844<T>>
+ for<'a> From<Cow<'a, ExecutionPayloadEip4844<T>>>
+ TryFrom<ExecutionPayloadHeaderEip4844<T>>;
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error>;
@@ -150,31 +151,21 @@ pub struct FullPayload<T: EthSpec> {
impl<T: EthSpec> From<FullPayload<T>> for ExecutionPayload<T> {
fn from(full_payload: FullPayload<T>) -> Self {
match full_payload {
FullPayload::Merge(payload) => ExecutionPayload::Merge(payload.execution_payload),
FullPayload::Capella(payload) => ExecutionPayload::Capella(payload.execution_payload),
FullPayload::Eip4844(payload) => ExecutionPayload::Eip4844(payload.execution_payload),
}
map_full_payload_into_execution_payload!(full_payload, move |payload, cons| {
cons(payload.execution_payload)
})
}
}
impl<'a, T: EthSpec> From<FullPayloadRef<'a, T>> for ExecutionPayload<T> {
fn from(full_payload_ref: FullPayloadRef<'a, T>) -> Self {
match full_payload_ref {
FullPayloadRef::Merge(payload) => {
ExecutionPayload::Merge(payload.execution_payload.clone())
}
FullPayloadRef::Capella(payload) => {
ExecutionPayload::Capella(payload.execution_payload.clone())
}
FullPayloadRef::Eip4844(payload) => {
ExecutionPayload::Eip4844(payload.execution_payload.clone())
}
}
map_full_payload_ref!(&'a _, full_payload_ref, move |payload, cons| {
cons(payload);
payload.execution_payload.clone().into()
})
}
}
// FIXME: can this be implemented as Deref or Clone somehow?
impl<'a, T: EthSpec> From<FullPayloadRef<'a, T>> for FullPayload<T> {
fn from(full_payload_ref: FullPayloadRef<'a, T>) -> Self {
map_full_payload_ref!(&'a _, full_payload_ref, move |payload, cons| {
@@ -189,11 +180,12 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
BlockType::Full
}
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
let payload = map_full_payload_into_execution_payload!(self.clone(), |inner, cons| {
cons(inner.execution_payload)
});
ExecutionPayloadHeader::from(payload)
fn to_execution_payload_header<'a>(&'a self) -> ExecutionPayloadHeader<T> {
map_full_payload_ref!(&'a _, self.to_ref(), move |inner, cons| {
cons(inner);
let exec_payload_ref: ExecutionPayloadRef<'a, T> = From::from(&inner.execution_payload);
ExecutionPayloadHeader::from(exec_payload_ref)
})
}
fn parent_hash<'a>(&'a self) -> ExecutionBlockHash {
@@ -404,17 +396,9 @@ impl<T: EthSpec> AbstractExecPayload<T> for FullPayload<T> {
impl<T: EthSpec> From<ExecutionPayload<T>> for FullPayload<T> {
fn from(execution_payload: ExecutionPayload<T>) -> Self {
match execution_payload {
ExecutionPayload::Merge(execution_payload) => {
Self::Merge(FullPayloadMerge { execution_payload })
}
ExecutionPayload::Capella(execution_payload) => {
Self::Capella(FullPayloadCapella { execution_payload })
}
ExecutionPayload::Eip4844(execution_payload) => {
Self::Eip4844(FullPayloadEip4844 { execution_payload })
}
}
map_execution_payload_into_full_payload!(execution_payload, |inner, cons| {
cons(inner.into())
})
}
}
@@ -666,6 +650,7 @@ macro_rules! impl_exec_payload_common {
$wrapped_field:ident, // execution_payload_header | execution_payload
$fork_variant:ident, // Merge | Merge
$block_type_variant:ident, // Blinded | Full
$is_default_with_empty_roots:block,
$f:block,
$g:block) => {
impl<T: EthSpec> ExecPayload<T> for $wrapper_type<T> {
@@ -675,7 +660,7 @@ macro_rules! impl_exec_payload_common {
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
ExecutionPayloadHeader::$fork_variant($wrapped_type_header::from(
self.$wrapped_field.clone(),
&self.$wrapped_field,
))
}
@@ -712,15 +697,8 @@ macro_rules! impl_exec_payload_common {
}
fn is_default_with_empty_roots(&self) -> bool {
// FIXME: is there a better way than ignoring this lint?
// This is necessary because the first invocation of this macro might expand to:
// self.execution_payload_header == ExecutionPayloadHeaderMerge::from(ExecutionPayloadMerge::default())
// but the second invocation might expand to:
// self.execution_payload == ExecutionPayloadMerge::from(ExecutionPayloadMerge::default())
#[allow(clippy::cmp_owned)]
{
self.$wrapped_field == $wrapped_type::from($wrapped_type_full::default())
}
let f = $is_default_with_empty_roots;
f(self)
}
fn transactions(&self) -> Option<&Transactions<T>> {
@@ -755,6 +733,12 @@ macro_rules! impl_exec_payload_for_fork {
execution_payload_header,
$fork_variant, // Merge
Blinded,
{
|wrapper: &$wrapper_type_header<T>| {
wrapper.execution_payload_header
== $wrapped_type_header::from(&$wrapped_type_full::default())
}
},
{ |_| { None } },
{
let c: for<'a> fn(&'a $wrapper_type_header<T>) -> Result<Hash256, Error> =
@@ -788,7 +772,7 @@ macro_rules! impl_exec_payload_for_fork {
fn default() -> Self {
Self {
execution_payload_header: $wrapped_type_header::from(
$wrapped_type_full::default(),
&$wrapped_type_full::default(),
),
}
}
@@ -806,11 +790,11 @@ macro_rules! impl_exec_payload_for_fork {
}
}
// FIXME(sproul): consider adding references to these From impls
impl<T: EthSpec> From<$wrapped_type_full<T>> for $wrapper_type_header<T> {
fn from(execution_payload: $wrapped_type_full<T>) -> Self {
// BlindedPayload* from CoW reference to ExecutionPayload* (hopefully just a reference).
impl<'a, T: EthSpec> From<Cow<'a, $wrapped_type_full<T>>> for $wrapper_type_header<T> {
fn from(execution_payload: Cow<'a, $wrapped_type_full<T>>) -> Self {
Self {
execution_payload_header: $wrapped_type_header::from(execution_payload),
execution_payload_header: $wrapped_type_header::from(&*execution_payload),
}
}
}
@@ -825,6 +809,11 @@ macro_rules! impl_exec_payload_for_fork {
execution_payload,
$fork_variant, // Merge
Full,
{
|wrapper: &$wrapper_type_full<T>| {
wrapper.execution_payload == $wrapped_type_full::default()
}
},
{
let c: for<'a> fn(&'a $wrapper_type_full<T>) -> Option<&'a Transactions<T>> =
|payload: &$wrapper_type_full<T>| Some(&payload.execution_payload.transactions);
@@ -848,6 +837,15 @@ macro_rules! impl_exec_payload_for_fork {
}
}
// FullPayload * from CoW reference to ExecutionPayload* (hopefully already owned).
impl<'a, T: EthSpec> From<Cow<'a, $wrapped_type_full<T>>> for $wrapper_type_full<T> {
fn from(execution_payload: Cow<'a, $wrapped_type_full<T>>) -> Self {
Self {
execution_payload: $wrapped_type_full::from(execution_payload.into_owned()),
}
}
}
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for $wrapper_type_full<T> {
type Error = Error;
fn try_from(_: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
@@ -915,11 +913,12 @@ impl<T: EthSpec> AbstractExecPayload<T> for BlindedPayload<T> {
impl<T: EthSpec> From<ExecutionPayload<T>> for BlindedPayload<T> {
fn from(payload: ExecutionPayload<T>) -> Self {
match payload {
ExecutionPayload::Merge(payload) => BlindedPayload::Merge(payload.into()),
ExecutionPayload::Capella(payload) => BlindedPayload::Capella(payload.into()),
ExecutionPayload::Eip4844(payload) => BlindedPayload::Eip4844(payload.into()),
}
// This implementation is a bit wasteful in that it discards the payload body.
// Required by the top-level constraint on AbstractExecPayload but could maybe be loosened
// in future.
map_execution_payload_into_blinded_payload!(payload, |inner, cons| cons(From::from(
Cow::Owned(inner)
)))
}
}

View File

@@ -522,6 +522,24 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
}
}
impl<E: EthSpec, Payload: AbstractExecPayload<E>> ForkVersionDeserialize
for SignedBeaconBlock<E, Payload>
{
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
value: serde_json::value::Value,
fork_name: ForkName,
) -> Result<Self, D::Error> {
Ok(map_fork_name!(
fork_name,
Self,
serde_json::from_value(value).map_err(|e| serde::de::Error::custom(format!(
"SignedBeaconBlock failed to deserialize: {:?}",
e
)))?
))
}
}
#[cfg(test)]
mod test {
use super::*;