mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-26 09:13:41 +00:00
payload verification with commitments
This commit is contained in:
@@ -13,7 +13,6 @@ pub use self::verify_attester_slashing::{
|
||||
pub use self::verify_proposer_slashing::verify_proposer_slashing;
|
||||
pub use altair::sync_committee::process_sync_aggregate;
|
||||
pub use block_signature_verifier::{BlockSignatureVerifier, ParallelSignatureSets};
|
||||
pub use deneb::deneb::process_blob_kzg_commitments;
|
||||
pub use is_valid_indexed_attestation::is_valid_indexed_attestation;
|
||||
pub use process_operations::process_operations;
|
||||
pub use verify_attestation::{
|
||||
@@ -163,11 +162,11 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
// `process_randao` as the former depends on the `randao_mix` computed with the reveal of the
|
||||
// previous block.
|
||||
if is_execution_enabled(state, block.body()) {
|
||||
let payload = block.body().execution_payload()?;
|
||||
let body = block.body();
|
||||
if state_processing_strategy == StateProcessingStrategy::Accurate {
|
||||
process_withdrawals::<T, Payload>(state, payload, spec)?;
|
||||
process_withdrawals::<T, Payload>(state, body.execution_payload()?, spec)?;
|
||||
}
|
||||
process_execution_payload::<T, Payload>(state, payload, spec)?;
|
||||
process_execution_payload::<T, Payload>(state, body, spec)?;
|
||||
}
|
||||
|
||||
process_randao(state, block, verify_randao, ctxt, spec)?;
|
||||
@@ -184,8 +183,6 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
)?;
|
||||
}
|
||||
|
||||
process_blob_kzg_commitments(block.body(), ctxt)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -350,9 +347,10 @@ pub fn get_new_eth1_data<T: EthSpec>(
|
||||
pub fn partially_verify_execution_payload<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
state: &BeaconState<T>,
|
||||
block_slot: Slot,
|
||||
payload: Payload::Ref<'_>,
|
||||
body: BeaconBlockBodyRef<T, Payload>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
let payload = body.execution_payload()?;
|
||||
if is_merge_transition_complete(state) {
|
||||
block_verify!(
|
||||
payload.parent_hash() == state.latest_execution_payload_header()?.block_hash(),
|
||||
@@ -379,6 +377,17 @@ pub fn partially_verify_execution_payload<T: EthSpec, Payload: AbstractExecPaylo
|
||||
}
|
||||
);
|
||||
|
||||
if let Ok(blob_commitments) = body.blob_kzg_commitments() {
|
||||
// Verify commitments are under the limit.
|
||||
block_verify!(
|
||||
blob_commitments.len() <= T::max_blobs_per_block(),
|
||||
BlockProcessingError::ExecutionInvalidBlobsLen {
|
||||
max: T::max_blobs_per_block(),
|
||||
actual: blob_commitments.len(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -391,11 +400,11 @@ pub fn partially_verify_execution_payload<T: EthSpec, Payload: AbstractExecPaylo
|
||||
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#process_execution_payload
|
||||
pub fn process_execution_payload<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
payload: Payload::Ref<'_>,
|
||||
body: BeaconBlockBodyRef<T, Payload>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
partially_verify_execution_payload::<T, Payload>(state, state.slot(), payload, spec)?;
|
||||
|
||||
partially_verify_execution_payload::<T, Payload>(state, state.slot(), body, spec)?;
|
||||
let payload = body.execution_payload()?;
|
||||
match state.latest_execution_payload_header_mut()? {
|
||||
ExecutionPayloadHeaderRefMut::Merge(header_mut) => {
|
||||
match payload.to_execution_payload_header() {
|
||||
|
||||
@@ -1,125 +1,8 @@
|
||||
use crate::{BlockProcessingError, ConsensusContext};
|
||||
use ethereum_hashing::hash_fixed;
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use safe_arith::SafeArith;
|
||||
use ssz::Decode;
|
||||
use types::consts::deneb::{BLOB_TX_TYPE, VERSIONED_HASH_VERSION_KZG};
|
||||
use types::{
|
||||
AbstractExecPayload, BeaconBlockBodyRef, EthSpec, ExecPayload, KzgCommitment, Transaction,
|
||||
Transactions, VersionedHash,
|
||||
};
|
||||
use types::consts::deneb::VERSIONED_HASH_VERSION_KZG;
|
||||
use types::{KzgCommitment, VersionedHash};
|
||||
|
||||
pub fn process_blob_kzg_commitments<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
block_body: BeaconBlockBodyRef<T, Payload>,
|
||||
ctxt: &mut ConsensusContext<T>,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Return early if this check has already been run.
|
||||
if ctxt.kzg_commitments_consistent() {
|
||||
return Ok(());
|
||||
}
|
||||
if let (Ok(payload), Ok(kzg_commitments)) = (
|
||||
block_body.execution_payload(),
|
||||
block_body.blob_kzg_commitments(),
|
||||
) {
|
||||
if let Some(transactions) = payload.transactions() {
|
||||
if !verify_kzg_commitments_against_transactions::<T>(transactions, kzg_commitments)? {
|
||||
return Err(BlockProcessingError::BlobVersionHashMismatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn verify_kzg_commitments_against_transactions<T: EthSpec>(
|
||||
transactions: &Transactions<T>,
|
||||
kzg_commitments: &[KzgCommitment],
|
||||
) -> Result<bool, BlockProcessingError> {
|
||||
let nested_iter = transactions
|
||||
.into_iter()
|
||||
.filter(|tx| {
|
||||
tx.first()
|
||||
.map(|tx_type| *tx_type == BLOB_TX_TYPE)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(|tx| tx_peek_versioned_hashes::<T>(tx));
|
||||
|
||||
itertools::process_results(nested_iter, |iter| {
|
||||
let zipped_iter = iter
|
||||
.flatten()
|
||||
// Need to use `itertools::zip_longest` here because just zipping hides if one iter is shorter
|
||||
// and `itertools::zip_eq` panics.
|
||||
.zip_longest(kzg_commitments.iter())
|
||||
.enumerate()
|
||||
.map(|(index, next)| match next {
|
||||
EitherOrBoth::Both(hash, commitment) => Ok((hash?, commitment)),
|
||||
// The number of versioned hashes from the blob transactions exceeds the number of
|
||||
// commitments in the block.
|
||||
EitherOrBoth::Left(_) => Err(BlockProcessingError::BlobNumCommitmentsMismatch {
|
||||
commitments_processed_in_block: index,
|
||||
commitments_processed_in_transactions: index.safe_add(1)?,
|
||||
}),
|
||||
// The number of commitments in the block exceeds the number of versioned hashes
|
||||
// in the blob transactions.
|
||||
EitherOrBoth::Right(_) => Err(BlockProcessingError::BlobNumCommitmentsMismatch {
|
||||
commitments_processed_in_block: index.safe_add(1)?,
|
||||
commitments_processed_in_transactions: index,
|
||||
}),
|
||||
});
|
||||
|
||||
itertools::process_results(zipped_iter, |mut iter| {
|
||||
iter.all(|(tx_versioned_hash, commitment)| {
|
||||
tx_versioned_hash == kzg_commitment_to_versioned_hash(commitment)
|
||||
})
|
||||
})
|
||||
})?
|
||||
}
|
||||
|
||||
/// Only transactions of type `BLOB_TX_TYPE` should be passed into this function.
|
||||
fn tx_peek_versioned_hashes<T: EthSpec>(
|
||||
opaque_tx: &Transaction<T::MaxBytesPerTransaction>,
|
||||
) -> Result<
|
||||
impl IntoIterator<Item = Result<VersionedHash, BlockProcessingError>> + '_,
|
||||
BlockProcessingError,
|
||||
> {
|
||||
let tx_len = opaque_tx.len();
|
||||
let message_offset = 1.safe_add(u32::from_ssz_bytes(opaque_tx.get(1..5).ok_or(
|
||||
BlockProcessingError::BlobVersionHashIndexOutOfBounds {
|
||||
length: tx_len,
|
||||
index: 5,
|
||||
},
|
||||
)?)?)?;
|
||||
|
||||
let message_offset_usize = message_offset as usize;
|
||||
|
||||
// field offset: 32 + 8 + 32 + 32 + 8 + 4 + 32 + 4 + 4 + 32 = 188
|
||||
let versioned_hashes_offset = message_offset.safe_add(u32::from_ssz_bytes(
|
||||
opaque_tx
|
||||
.get(message_offset_usize.safe_add(188)?..message_offset_usize.safe_add(192)?)
|
||||
.ok_or(BlockProcessingError::BlobVersionHashIndexOutOfBounds {
|
||||
length: tx_len,
|
||||
index: message_offset_usize.safe_add(192)?,
|
||||
})?,
|
||||
)?)?;
|
||||
|
||||
let num_hashes = tx_len
|
||||
.safe_sub(versioned_hashes_offset as usize)?
|
||||
.safe_div(32)?;
|
||||
|
||||
Ok((0..num_hashes).map(move |i| {
|
||||
let next_version_hash_index =
|
||||
(versioned_hashes_offset as usize).safe_add(i.safe_mul(32)?)?;
|
||||
let bytes = opaque_tx
|
||||
.get(next_version_hash_index..next_version_hash_index.safe_add(32)?)
|
||||
.ok_or(BlockProcessingError::BlobVersionHashIndexOutOfBounds {
|
||||
length: tx_len,
|
||||
index: (next_version_hash_index).safe_add(32)?,
|
||||
})?;
|
||||
Ok(VersionedHash::from_slice(bytes))
|
||||
}))
|
||||
}
|
||||
|
||||
fn kzg_commitment_to_versioned_hash(kzg_commitment: &KzgCommitment) -> VersionedHash {
|
||||
pub fn kzg_commitment_to_versioned_hash(kzg_commitment: &KzgCommitment) -> VersionedHash {
|
||||
let mut hashed_commitment = hash_fixed(&kzg_commitment.0);
|
||||
hashed_commitment[0] = VERSIONED_HASH_VERSION_KZG;
|
||||
VersionedHash::from(hashed_commitment)
|
||||
|
||||
@@ -76,6 +76,10 @@ pub enum BlockProcessingError {
|
||||
expected: u64,
|
||||
found: u64,
|
||||
},
|
||||
ExecutionInvalidBlobsLen {
|
||||
max: usize,
|
||||
actual: usize,
|
||||
},
|
||||
ExecutionInvalid,
|
||||
ConsensusContext(ContextError),
|
||||
WithdrawalsRootMismatch {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user