payload verification with commitments

This commit is contained in:
realbigsean
2023-06-07 14:29:39 -04:00
parent 6970f7a19f
commit 5d73a9bdde
12 changed files with 94 additions and 1147 deletions

View File

@@ -73,12 +73,12 @@ pub mod validator_subscription;
pub mod voluntary_exit;
#[macro_use]
pub mod slot_epoch_macros;
pub mod body;
pub mod config_and_preset;
pub mod execution_block_header;
pub mod fork_context;
pub mod participation_flags;
pub mod participation_list;
pub mod payload;
pub mod preset;
pub mod slot_epoch;
pub mod subnet_id;
@@ -121,6 +121,11 @@ pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee};
pub use crate::beacon_state::{BeaconTreeHashCache, Error as BeaconStateError, *};
pub use crate::blob_sidecar::{BlobSidecar, BlobSidecarList};
pub use crate::bls_to_execution_change::BlsToExecutionChange;
pub use crate::body::{
AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadDeneb,
BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload, FullPayload,
FullPayloadCapella, FullPayloadDeneb, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
};
pub use crate::chain_spec::{ChainSpec, Config, Domain};
pub use crate::checkpoint::Checkpoint;
pub use crate::config_and_preset::{
@@ -156,11 +161,6 @@ pub use crate::light_client_finality_update::LightClientFinalityUpdate;
pub use crate::light_client_optimistic_update::LightClientOptimisticUpdate;
pub use crate::participation_flags::ParticipationFlags;
pub use crate::participation_list::ParticipationList;
pub use crate::payload::{
AbstractExecPayload, BlindedPayload, BlindedPayloadCapella, BlindedPayloadDeneb,
BlindedPayloadMerge, BlindedPayloadRef, BlockType, ExecPayload, FullPayload,
FullPayloadCapella, FullPayloadDeneb, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
};
pub use crate::pending_attestation::PendingAttestation;
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset};
pub use crate::proposer_preparation_data::ProposerPreparationData;

View File

@@ -1,957 +0,0 @@
use crate::{test_utils::TestRandom, *};
use derivative::Derivative;
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;
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq)]
pub enum BlockType {
Blinded,
Full,
}
/// A trait representing behavior of an `ExecutionPayload` that either has a full list of transactions
/// or a transaction hash in it's place.
pub trait ExecPayload<T: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash + Send {
fn block_type() -> BlockType;
/// Convert the payload into a payload header.
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T>;
/// We provide a subset of field accessors, for the fields used in `consensus`.
///
/// More fields can be added here if you wish.
fn parent_hash(&self) -> ExecutionBlockHash;
fn prev_randao(&self) -> Hash256;
fn block_number(&self) -> u64;
fn timestamp(&self) -> u64;
fn block_hash(&self) -> ExecutionBlockHash;
fn fee_recipient(&self) -> Address;
fn gas_limit(&self) -> u64;
fn transactions(&self) -> Option<&Transactions<T>>;
/// fork-specific fields
fn withdrawals_root(&self) -> Result<Hash256, Error>;
/// Is this a default payload with 0x0 roots for transactions and withdrawals?
fn is_default_with_zero_roots(&self) -> bool;
/// Is this a default payload with the hash of the empty list for transactions and withdrawals?
fn is_default_with_empty_roots(&self) -> bool;
}
/// `ExecPayload` functionality the requires ownership.
pub trait OwnedExecPayload<T: EthSpec>:
ExecPayload<T>
+ Default
+ Serialize
+ DeserializeOwned
+ Encode
+ Decode
+ TestRandom
+ for<'a> arbitrary::Arbitrary<'a>
+ 'static
{
}
impl<T: EthSpec, P> OwnedExecPayload<T> for P where
P: ExecPayload<T>
+ Default
+ Serialize
+ DeserializeOwned
+ Encode
+ Decode
+ TestRandom
+ for<'a> arbitrary::Arbitrary<'a>
+ 'static
{
}
pub trait AbstractExecPayload<T: EthSpec>:
ExecPayload<T>
+ Sized
+ From<ExecutionPayload<T>>
+ TryFrom<ExecutionPayloadHeader<T>>
+ TryInto<Self::Merge>
+ TryInto<Self::Capella>
+ TryInto<Self::Deneb>
{
type Ref<'a>: ExecPayload<T>
+ Copy
+ From<&'a Self::Merge>
+ From<&'a Self::Capella>
+ From<&'a Self::Deneb>;
type Merge: OwnedExecPayload<T>
+ Into<Self>
+ for<'a> From<Cow<'a, ExecutionPayloadMerge<T>>>
+ TryFrom<ExecutionPayloadHeaderMerge<T>>;
type Capella: OwnedExecPayload<T>
+ Into<Self>
+ for<'a> From<Cow<'a, ExecutionPayloadCapella<T>>>
+ TryFrom<ExecutionPayloadHeaderCapella<T>>;
type Deneb: OwnedExecPayload<T>
+ Into<Self>
+ for<'a> From<Cow<'a, ExecutionPayloadDeneb<T>>>
+ TryFrom<ExecutionPayloadHeaderDeneb<T>>;
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error>;
}
#[superstruct(
variants(Merge, Capella, Deneb),
variant_attributes(
derive(
Debug,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TestRandom,
TreeHash,
Derivative,
arbitrary::Arbitrary,
),
derivative(PartialEq, Hash(bound = "T: EthSpec")),
serde(bound = "T: EthSpec", deny_unknown_fields),
arbitrary(bound = "T: EthSpec"),
ssz(struct_behaviour = "transparent"),
),
ref_attributes(
derive(Debug, Derivative, TreeHash),
derivative(PartialEq, Hash(bound = "T: EthSpec")),
tree_hash(enum_behaviour = "transparent"),
),
map_into(ExecutionPayload),
map_ref_into(ExecutionPayloadRef),
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
)]
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary)]
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
#[serde(bound = "T: EthSpec")]
#[arbitrary(bound = "T: EthSpec")]
#[tree_hash(enum_behaviour = "transparent")]
pub struct FullPayload<T: EthSpec> {
#[superstruct(only(Merge), partial_getter(rename = "execution_payload_merge"))]
pub execution_payload: ExecutionPayloadMerge<T>,
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
pub execution_payload: ExecutionPayloadCapella<T>,
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
pub execution_payload: ExecutionPayloadDeneb<T>,
}
impl<T: EthSpec> From<FullPayload<T>> for ExecutionPayload<T> {
fn from(full_payload: FullPayload<T>) -> Self {
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 {
map_full_payload_ref!(&'a _, full_payload_ref, move |payload, cons| {
cons(payload);
payload.execution_payload.clone().into()
})
}
}
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| {
cons(payload);
payload.clone().into()
})
}
}
impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
fn block_type() -> BlockType {
BlockType::Full
}
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 {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.parent_hash
})
}
fn prev_randao<'a>(&'a self) -> Hash256 {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.prev_randao
})
}
fn block_number<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.block_number
})
}
fn timestamp<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.timestamp
})
}
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.block_hash
})
}
fn fee_recipient<'a>(&'a self) -> Address {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.fee_recipient
})
}
fn gas_limit<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload.gas_limit
})
}
fn transactions<'a>(&'a self) -> Option<&'a Transactions<T>> {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
Some(&payload.execution_payload.transactions)
})
}
fn withdrawals_root(&self) -> Result<Hash256, Error> {
match self {
FullPayload::Merge(_) => Err(Error::IncorrectStateVariant),
FullPayload::Capella(ref inner) => {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
FullPayload::Deneb(ref inner) => {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
}
}
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload == <_>::default()
})
}
fn is_default_with_empty_roots(&self) -> bool {
// For full payloads the empty/zero distinction does not exist.
self.is_default_with_zero_roots()
}
}
impl<T: EthSpec> FullPayload<T> {
pub fn execution_payload(self) -> ExecutionPayload<T> {
map_full_payload_into_execution_payload!(self, |inner, cons| {
cons(inner.execution_payload)
})
}
}
impl<'a, T: EthSpec> FullPayloadRef<'a, T> {
pub fn execution_payload_ref(self) -> ExecutionPayloadRef<'a, T> {
map_full_payload_ref_into_execution_payload_ref!(&'a _, self, |inner, cons| {
cons(&inner.execution_payload)
})
}
}
impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
fn block_type() -> BlockType {
BlockType::Full
}
fn to_execution_payload_header<'a>(&'a self) -> ExecutionPayloadHeader<T> {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.to_execution_payload_header()
})
}
fn parent_hash<'a>(&'a self) -> ExecutionBlockHash {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.parent_hash
})
}
fn prev_randao<'a>(&'a self) -> Hash256 {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.prev_randao
})
}
fn block_number<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.block_number
})
}
fn timestamp<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.timestamp
})
}
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.block_hash
})
}
fn fee_recipient<'a>(&'a self) -> Address {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.fee_recipient
})
}
fn gas_limit<'a>(&'a self) -> u64 {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload.gas_limit
})
}
fn transactions<'a>(&'a self) -> Option<&'a Transactions<T>> {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
Some(&payload.execution_payload.transactions)
})
}
fn withdrawals_root(&self) -> Result<Hash256, Error> {
match self {
FullPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant),
FullPayloadRef::Capella(inner) => {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
FullPayloadRef::Deneb(inner) => {
Ok(inner.execution_payload.withdrawals.tree_hash_root())
}
}
}
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
map_full_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload == <_>::default()
})
}
fn is_default_with_empty_roots(&self) -> bool {
// For full payloads the empty/zero distinction does not exist.
self.is_default_with_zero_roots()
}
}
impl<T: EthSpec> AbstractExecPayload<T> for FullPayload<T> {
type Ref<'a> = FullPayloadRef<'a, T>;
type Merge = FullPayloadMerge<T>;
type Capella = FullPayloadCapella<T>;
type Deneb = FullPayloadDeneb<T>;
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error> {
match fork_name {
ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant),
ForkName::Merge => Ok(FullPayloadMerge::default().into()),
ForkName::Capella => Ok(FullPayloadCapella::default().into()),
ForkName::Deneb => Ok(FullPayloadDeneb::default().into()),
}
}
}
impl<T: EthSpec> From<ExecutionPayload<T>> for FullPayload<T> {
fn from(execution_payload: ExecutionPayload<T>) -> Self {
map_execution_payload_into_full_payload!(execution_payload, |inner, cons| {
cons(inner.into())
})
}
}
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for FullPayload<T> {
type Error = ();
fn try_from(_: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
Err(())
}
}
#[superstruct(
variants(Merge, Capella, Deneb),
variant_attributes(
derive(
Debug,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TestRandom,
TreeHash,
Derivative,
arbitrary::Arbitrary
),
derivative(PartialEq, Hash(bound = "T: EthSpec")),
serde(bound = "T: EthSpec", deny_unknown_fields),
arbitrary(bound = "T: EthSpec"),
ssz(struct_behaviour = "transparent"),
),
ref_attributes(
derive(Debug, Derivative, TreeHash),
derivative(PartialEq, Hash(bound = "T: EthSpec")),
tree_hash(enum_behaviour = "transparent"),
),
map_into(ExecutionPayloadHeader),
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"),
partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant")
)]
#[derive(Debug, Clone, Serialize, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary)]
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
#[serde(bound = "T: EthSpec")]
#[arbitrary(bound = "T: EthSpec")]
#[tree_hash(enum_behaviour = "transparent")]
pub struct BlindedPayload<T: EthSpec> {
#[superstruct(only(Merge), partial_getter(rename = "execution_payload_merge"))]
pub execution_payload_header: ExecutionPayloadHeaderMerge<T>,
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
pub execution_payload_header: ExecutionPayloadHeaderCapella<T>,
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
pub execution_payload_header: ExecutionPayloadHeaderDeneb<T>,
}
impl<'a, T: EthSpec> From<BlindedPayloadRef<'a, T>> for BlindedPayload<T> {
fn from(blinded_payload_ref: BlindedPayloadRef<'a, T>) -> Self {
map_blinded_payload_ref!(&'a _, blinded_payload_ref, move |payload, cons| {
cons(payload);
payload.clone().into()
})
}
}
impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
fn block_type() -> BlockType {
BlockType::Blinded
}
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
map_blinded_payload_into_execution_payload_header!(self.clone(), |inner, cons| {
cons(inner.execution_payload_header)
})
}
fn parent_hash<'a>(&'a self) -> ExecutionBlockHash {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.parent_hash
})
}
fn prev_randao<'a>(&'a self) -> Hash256 {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.prev_randao
})
}
fn block_number<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.block_number
})
}
fn timestamp<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.timestamp
})
}
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.block_hash
})
}
fn fee_recipient<'a>(&'a self) -> Address {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.fee_recipient
})
}
fn gas_limit<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
cons(payload);
payload.execution_payload_header.gas_limit
})
}
fn transactions(&self) -> Option<&Transactions<T>> {
None
}
fn withdrawals_root(&self) -> Result<Hash256, Error> {
match self {
BlindedPayload::Merge(_) => Err(Error::IncorrectStateVariant),
BlindedPayload::Capella(ref inner) => {
Ok(inner.execution_payload_header.withdrawals_root)
}
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.withdrawals_root),
}
}
fn is_default_with_zero_roots(&self) -> bool {
self.to_ref().is_default_with_zero_roots()
}
// For blinded payloads we must check "defaultness" against the default `ExecutionPayload`
// which has been blinded into an `ExecutionPayloadHeader`, NOT against the default
// `ExecutionPayloadHeader` which has a zeroed out `transactions_root`. The transactions root
// should be the root of the empty list.
fn is_default_with_empty_roots(&self) -> bool {
self.to_ref().is_default_with_empty_roots()
}
}
impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
fn block_type() -> BlockType {
BlockType::Blinded
}
fn to_execution_payload_header<'a>(&'a self) -> ExecutionPayloadHeader<T> {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.to_execution_payload_header()
})
}
fn parent_hash<'a>(&'a self) -> ExecutionBlockHash {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.parent_hash
})
}
fn prev_randao<'a>(&'a self) -> Hash256 {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.prev_randao
})
}
fn block_number<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.block_number
})
}
fn timestamp<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.timestamp
})
}
fn block_hash<'a>(&'a self) -> ExecutionBlockHash {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.block_hash
})
}
fn fee_recipient<'a>(&'a self) -> Address {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.fee_recipient
})
}
fn gas_limit<'a>(&'a self) -> u64 {
map_blinded_payload_ref!(&'a _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header.gas_limit
})
}
fn transactions(&self) -> Option<&Transactions<T>> {
None
}
fn withdrawals_root(&self) -> Result<Hash256, Error> {
match self {
BlindedPayloadRef::Merge(_) => Err(Error::IncorrectStateVariant),
BlindedPayloadRef::Capella(inner) => {
Ok(inner.execution_payload_header.withdrawals_root)
}
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.withdrawals_root),
}
}
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
map_blinded_payload_ref!(&'b _, self, move |payload, cons| {
cons(payload);
payload.execution_payload_header == <_>::default()
})
}
fn is_default_with_empty_roots<'a>(&'a self) -> bool {
map_blinded_payload_ref!(&'b _, self, move |payload, cons| {
cons(payload);
payload.is_default_with_empty_roots()
})
}
}
macro_rules! impl_exec_payload_common {
($wrapper_type:ident, // BlindedPayloadMerge | FullPayloadMerge
$wrapped_type:ident, // ExecutionPayloadHeaderMerge | ExecutionPayloadMerge
$wrapped_type_full:ident, // ExecutionPayloadMerge | ExecutionPayloadMerge
$wrapped_type_header:ident, // ExecutionPayloadHeaderMerge | ExecutionPayloadHeaderMerge
$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> {
fn block_type() -> BlockType {
BlockType::$block_type_variant
}
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
ExecutionPayloadHeader::$fork_variant($wrapped_type_header::from(
&self.$wrapped_field,
))
}
fn parent_hash(&self) -> ExecutionBlockHash {
self.$wrapped_field.parent_hash
}
fn prev_randao(&self) -> Hash256 {
self.$wrapped_field.prev_randao
}
fn block_number(&self) -> u64 {
self.$wrapped_field.block_number
}
fn timestamp(&self) -> u64 {
self.$wrapped_field.timestamp
}
fn block_hash(&self) -> ExecutionBlockHash {
self.$wrapped_field.block_hash
}
fn fee_recipient(&self) -> Address {
self.$wrapped_field.fee_recipient
}
fn gas_limit(&self) -> u64 {
self.$wrapped_field.gas_limit
}
fn is_default_with_zero_roots(&self) -> bool {
self.$wrapped_field == $wrapped_type::default()
}
fn is_default_with_empty_roots(&self) -> bool {
let f = $is_default_with_empty_roots;
f(self)
}
fn transactions(&self) -> Option<&Transactions<T>> {
let f = $f;
f(self)
}
fn withdrawals_root(&self) -> Result<Hash256, Error> {
let g = $g;
g(self)
}
}
impl<T: EthSpec> From<$wrapped_type<T>> for $wrapper_type<T> {
fn from($wrapped_field: $wrapped_type<T>) -> Self {
Self { $wrapped_field }
}
}
};
}
macro_rules! impl_exec_payload_for_fork {
// BlindedPayloadMerge, FullPayloadMerge, ExecutionPayloadHeaderMerge, ExecutionPayloadMerge, Merge
($wrapper_type_header:ident, $wrapper_type_full:ident, $wrapped_type_header:ident, $wrapped_type_full:ident, $fork_variant:ident) => {
//*************** Blinded payload implementations ******************//
impl_exec_payload_common!(
$wrapper_type_header, // BlindedPayloadMerge
$wrapped_type_header, // ExecutionPayloadHeaderMerge
$wrapped_type_full, // ExecutionPayloadMerge
$wrapped_type_header, // ExecutionPayloadHeaderMerge
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> =
|payload: &$wrapper_type_header<T>| {
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
wrapper_ref_type.withdrawals_root()
};
c
}
);
impl<T: EthSpec> TryInto<$wrapper_type_header<T>> for BlindedPayload<T> {
type Error = Error;
fn try_into(self) -> Result<$wrapper_type_header<T>, Self::Error> {
match self {
BlindedPayload::$fork_variant(payload) => Ok(payload),
_ => Err(Error::IncorrectStateVariant),
}
}
}
// NOTE: the `Default` implementation for `BlindedPayload` needs to be different from the `Default`
// implementation for `ExecutionPayloadHeader` because payloads are checked for equality against the
// default payload in `is_merge_transition_block` to determine whether the merge has occurred.
//
// The default `BlindedPayload` is therefore the payload header that results from blinding the
// default `ExecutionPayload`, which differs from the default `ExecutionPayloadHeader` in that
// its `transactions_root` is the hash of the empty list rather than 0x0.
impl<T: EthSpec> Default for $wrapper_type_header<T> {
fn default() -> Self {
Self {
execution_payload_header: $wrapped_type_header::from(
&$wrapped_type_full::default(),
),
}
}
}
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for $wrapper_type_header<T> {
type Error = Error;
fn try_from(header: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
match header {
ExecutionPayloadHeader::$fork_variant(execution_payload_header) => {
Ok(execution_payload_header.into())
}
_ => Err(Error::PayloadConversionLogicFlaw),
}
}
}
// 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),
}
}
}
//*************** Full payload implementations ******************//
impl_exec_payload_common!(
$wrapper_type_full, // FullPayloadMerge
$wrapped_type_full, // ExecutionPayloadMerge
$wrapped_type_full, // ExecutionPayloadMerge
$wrapped_type_header, // ExecutionPayloadHeaderMerge
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);
c
},
{
let c: for<'a> fn(&'a $wrapper_type_full<T>) -> Result<Hash256, Error> =
|payload: &$wrapper_type_full<T>| {
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
wrapper_ref_type.withdrawals_root()
};
c
}
);
impl<T: EthSpec> Default for $wrapper_type_full<T> {
fn default() -> Self {
Self {
execution_payload: $wrapped_type_full::default(),
}
}
}
// 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> {
Err(Error::PayloadConversionLogicFlaw)
}
}
impl<T: EthSpec> TryFrom<$wrapped_type_header<T>> for $wrapper_type_full<T> {
type Error = Error;
fn try_from(_: $wrapped_type_header<T>) -> Result<Self, Self::Error> {
Err(Error::PayloadConversionLogicFlaw)
}
}
impl<T: EthSpec> TryInto<$wrapper_type_full<T>> for FullPayload<T> {
type Error = Error;
fn try_into(self) -> Result<$wrapper_type_full<T>, Self::Error> {
match self {
FullPayload::$fork_variant(payload) => Ok(payload),
_ => Err(Error::PayloadConversionLogicFlaw),
}
}
}
};
}
impl_exec_payload_for_fork!(
BlindedPayloadMerge,
FullPayloadMerge,
ExecutionPayloadHeaderMerge,
ExecutionPayloadMerge,
Merge
);
impl_exec_payload_for_fork!(
BlindedPayloadCapella,
FullPayloadCapella,
ExecutionPayloadHeaderCapella,
ExecutionPayloadCapella,
Capella
);
impl_exec_payload_for_fork!(
BlindedPayloadDeneb,
FullPayloadDeneb,
ExecutionPayloadHeaderDeneb,
ExecutionPayloadDeneb,
Deneb
);
impl<T: EthSpec> AbstractExecPayload<T> for BlindedPayload<T> {
type Ref<'a> = BlindedPayloadRef<'a, T>;
type Merge = BlindedPayloadMerge<T>;
type Capella = BlindedPayloadCapella<T>;
type Deneb = BlindedPayloadDeneb<T>;
fn default_at_fork(fork_name: ForkName) -> Result<Self, Error> {
match fork_name {
ForkName::Base | ForkName::Altair => Err(Error::IncorrectStateVariant),
ForkName::Merge => Ok(BlindedPayloadMerge::default().into()),
ForkName::Capella => Ok(BlindedPayloadCapella::default().into()),
ForkName::Deneb => Ok(BlindedPayloadDeneb::default().into()),
}
}
}
impl<T: EthSpec> From<ExecutionPayload<T>> for BlindedPayload<T> {
fn from(payload: ExecutionPayload<T>) -> Self {
// 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)
)))
}
}
impl<T: EthSpec> From<ExecutionPayloadHeader<T>> for BlindedPayload<T> {
fn from(execution_payload_header: ExecutionPayloadHeader<T>) -> Self {
match execution_payload_header {
ExecutionPayloadHeader::Merge(execution_payload_header) => {
Self::Merge(BlindedPayloadMerge {
execution_payload_header,
})
}
ExecutionPayloadHeader::Capella(execution_payload_header) => {
Self::Capella(BlindedPayloadCapella {
execution_payload_header,
})
}
ExecutionPayloadHeader::Deneb(execution_payload_header) => {
Self::Deneb(BlindedPayloadDeneb {
execution_payload_header,
})
}
}
}
}
impl<T: EthSpec> From<BlindedPayload<T>> for ExecutionPayloadHeader<T> {
fn from(blinded: BlindedPayload<T>) -> Self {
match blinded {
BlindedPayload::Merge(blinded_payload) => {
ExecutionPayloadHeader::Merge(blinded_payload.execution_payload_header)
}
BlindedPayload::Capella(blinded_payload) => {
ExecutionPayloadHeader::Capella(blinded_payload.execution_payload_header)
}
BlindedPayload::Deneb(blinded_payload) => {
ExecutionPayloadHeader::Deneb(blinded_payload.execution_payload_header)
}
}
}
}