Simplify payload traits and reduce cloning (#3976)

* Simplify payload traits and reduce cloning

* Fix self limiter
This commit is contained in:
Michael Sproul 2023-02-15 14:17:56 +11:00 committed by GitHub
parent 10d32ee04c
commit 918b688f72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 101 deletions

View File

@ -985,11 +985,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
})? })?
.ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?; .ok_or(Error::BlockHashMissingFromExecutionLayer(exec_block_hash))?;
//FIXME(sean) avoid the clone by comparing refs to headers (`as_execution_payload_header` method ?)
let full_payload: FullPayload<T::EthSpec> = execution_payload.clone().into();
// Verify payload integrity. // Verify payload integrity.
let header_from_payload = full_payload.to_execution_payload_header(); let header_from_payload = ExecutionPayloadHeader::from(execution_payload.to_ref());
if header_from_payload != execution_payload_header { if header_from_payload != execution_payload_header {
for txn in execution_payload.transactions() { for txn in execution_payload.transactions() {
debug!( debug!(

View File

@ -67,6 +67,7 @@ pub struct OutboundRateLimiterConfig {
pub(super) goodbye_quota: Quota, pub(super) goodbye_quota: Quota,
pub(super) blocks_by_range_quota: Quota, pub(super) blocks_by_range_quota: Quota,
pub(super) blocks_by_root_quota: Quota, pub(super) blocks_by_root_quota: Quota,
pub(super) blobs_by_range_quota: Quota,
} }
impl OutboundRateLimiterConfig { impl OutboundRateLimiterConfig {
@ -77,6 +78,8 @@ impl OutboundRateLimiterConfig {
pub const DEFAULT_BLOCKS_BY_RANGE_QUOTA: Quota = pub const DEFAULT_BLOCKS_BY_RANGE_QUOTA: Quota =
Quota::n_every(methods::MAX_REQUEST_BLOCKS, 10); Quota::n_every(methods::MAX_REQUEST_BLOCKS, 10);
pub const DEFAULT_BLOCKS_BY_ROOT_QUOTA: Quota = Quota::n_every(128, 10); pub const DEFAULT_BLOCKS_BY_ROOT_QUOTA: Quota = Quota::n_every(128, 10);
pub const DEFAULT_BLOBS_BY_RANGE_QUOTA: Quota =
Quota::n_every(methods::MAX_REQUEST_BLOBS_SIDECARS, 10);
} }
impl Default for OutboundRateLimiterConfig { impl Default for OutboundRateLimiterConfig {
@ -88,6 +91,7 @@ impl Default for OutboundRateLimiterConfig {
goodbye_quota: Self::DEFAULT_GOODBYE_QUOTA, goodbye_quota: Self::DEFAULT_GOODBYE_QUOTA,
blocks_by_range_quota: Self::DEFAULT_BLOCKS_BY_RANGE_QUOTA, blocks_by_range_quota: Self::DEFAULT_BLOCKS_BY_RANGE_QUOTA,
blocks_by_root_quota: Self::DEFAULT_BLOCKS_BY_ROOT_QUOTA, blocks_by_root_quota: Self::DEFAULT_BLOCKS_BY_ROOT_QUOTA,
blobs_by_range_quota: Self::DEFAULT_BLOBS_BY_RANGE_QUOTA,
} }
} }
} }
@ -111,6 +115,7 @@ impl Debug for OutboundRateLimiterConfig {
.field("goodbye", fmt_q!(&self.goodbye_quota)) .field("goodbye", fmt_q!(&self.goodbye_quota))
.field("blocks_by_range", fmt_q!(&self.blocks_by_range_quota)) .field("blocks_by_range", fmt_q!(&self.blocks_by_range_quota))
.field("blocks_by_root", fmt_q!(&self.blocks_by_root_quota)) .field("blocks_by_root", fmt_q!(&self.blocks_by_root_quota))
.field("blobs_by_range", fmt_q!(&self.blobs_by_range_quota))
.finish() .finish()
} }
} }
@ -129,7 +134,6 @@ impl FromStr for OutboundRateLimiterConfig {
let mut goodbye_quota = None; let mut goodbye_quota = None;
let mut blocks_by_range_quota = None; let mut blocks_by_range_quota = None;
let mut blocks_by_root_quota = None; let mut blocks_by_root_quota = None;
// TODO(eip4844): use this blob quota
let mut blobs_by_range_quota = None; let mut blobs_by_range_quota = None;
for proto_def in s.split(';') { for proto_def in s.split(';') {
let ProtocolQuota { protocol, quota } = proto_def.parse()?; let ProtocolQuota { protocol, quota } = proto_def.parse()?;
@ -154,6 +158,8 @@ impl FromStr for OutboundRateLimiterConfig {
.unwrap_or(Self::DEFAULT_BLOCKS_BY_RANGE_QUOTA), .unwrap_or(Self::DEFAULT_BLOCKS_BY_RANGE_QUOTA),
blocks_by_root_quota: blocks_by_root_quota blocks_by_root_quota: blocks_by_root_quota
.unwrap_or(Self::DEFAULT_BLOCKS_BY_ROOT_QUOTA), .unwrap_or(Self::DEFAULT_BLOCKS_BY_ROOT_QUOTA),
blobs_by_range_quota: blobs_by_range_quota
.unwrap_or(Self::DEFAULT_BLOBS_BY_RANGE_QUOTA),
}) })
} }
} }

View File

@ -60,6 +60,7 @@ impl<Id: ReqId, TSpec: EthSpec> SelfRateLimiter<Id, TSpec> {
goodbye_quota, goodbye_quota,
blocks_by_range_quota, blocks_by_range_quota,
blocks_by_root_quota, blocks_by_root_quota,
blobs_by_range_quota,
} = config; } = config;
let limiter = RateLimiter::builder() let limiter = RateLimiter::builder()
@ -69,6 +70,7 @@ impl<Id: ReqId, TSpec: EthSpec> SelfRateLimiter<Id, TSpec> {
.set_quota(Protocol::Goodbye, goodbye_quota) .set_quota(Protocol::Goodbye, goodbye_quota)
.set_quota(Protocol::BlocksByRange, blocks_by_range_quota) .set_quota(Protocol::BlocksByRange, blocks_by_range_quota)
.set_quota(Protocol::BlocksByRoot, blocks_by_root_quota) .set_quota(Protocol::BlocksByRoot, blocks_by_root_quota)
.set_quota(Protocol::BlobsByRange, blobs_by_range_quota)
// Manually set the LightClientBootstrap quota, since we use the same rate limiter for // Manually set the LightClientBootstrap quota, since we use the same rate limiter for
// inbound and outbound requests, and the LightClientBootstrap is an only inbound // inbound and outbound requests, and the LightClientBootstrap is an only inbound
// protocol. // protocol.

View File

@ -348,8 +348,7 @@ where
&mut self, &mut self,
block: &'a SignedBeaconBlock<T, Payload>, block: &'a SignedBeaconBlock<T, Payload>,
) -> Result<()> { ) -> Result<()> {
// FIXME(capella): to improve performance we might want to decompress the withdrawal pubkeys // To improve performance we might want to decompress the withdrawal pubkeys in parallel.
// in parallel.
if let Ok(bls_to_execution_changes) = block.message().body().bls_to_execution_changes() { if let Ok(bls_to_execution_changes) = block.message().body().bls_to_execution_changes() {
for bls_to_execution_change in bls_to_execution_changes { for bls_to_execution_change in bls_to_execution_changes {
self.sets.push(bls_execution_change_signature_set( self.sets.push(bls_execution_change_signature_set(

View File

@ -37,10 +37,9 @@ pub fn verify_bls_to_execution_change<T: EthSpec>(
Invalid::NonBlsWithdrawalCredentials Invalid::NonBlsWithdrawalCredentials
); );
// Re-hashing the pubkey isn't necessary during block replay, so we may want to skip that in
// future.
let pubkey_hash = hash(address_change.from_bls_pubkey.as_serialized()); let pubkey_hash = hash(address_change.from_bls_pubkey.as_serialized());
// FIXME: Should this check be put inside the verify_signatures.is_true() condition?
// I believe that's used for fuzzing so this is a Mehdi question..
verify!( verify!(
validator.withdrawal_credentials.as_bytes().get(1..) == pubkey_hash.get(1..), validator.withdrawal_credentials.as_bytes().get(1..) == pubkey_hash.get(1..),
Invalid::WithdrawalCredentialsMismatch Invalid::WithdrawalCredentialsMismatch

View File

@ -279,7 +279,7 @@ impl<E: EthSpec> From<BeaconBlockBodyMerge<E, FullPayload<E>>>
voluntary_exits, voluntary_exits,
sync_aggregate, sync_aggregate,
execution_payload: BlindedPayloadMerge { execution_payload: BlindedPayloadMerge {
execution_payload_header: From::from(execution_payload.clone()), execution_payload_header: From::from(&execution_payload),
}, },
}, },
Some(execution_payload), Some(execution_payload),
@ -320,7 +320,7 @@ impl<E: EthSpec> From<BeaconBlockBodyCapella<E, FullPayload<E>>>
voluntary_exits, voluntary_exits,
sync_aggregate, sync_aggregate,
execution_payload: BlindedPayloadCapella { execution_payload: BlindedPayloadCapella {
execution_payload_header: From::from(execution_payload.clone()), execution_payload_header: From::from(&execution_payload),
}, },
bls_to_execution_changes, bls_to_execution_changes,
}, },
@ -363,7 +363,7 @@ impl<E: EthSpec> From<BeaconBlockBodyEip4844<E, FullPayload<E>>>
voluntary_exits, voluntary_exits,
sync_aggregate, sync_aggregate,
execution_payload: BlindedPayloadEip4844 { execution_payload: BlindedPayloadEip4844 {
execution_payload_header: From::from(execution_payload.clone()), execution_payload_header: From::from(&execution_payload),
}, },
bls_to_execution_changes, bls_to_execution_changes,
blob_kzg_commitments, blob_kzg_commitments,
@ -414,7 +414,7 @@ impl<E: EthSpec> BeaconBlockBodyMerge<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(), voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(), sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadMerge { execution_payload: BlindedPayloadMerge {
execution_payload_header: From::from(execution_payload.clone()), execution_payload_header: execution_payload.into(),
}, },
} }
} }
@ -447,7 +447,7 @@ impl<E: EthSpec> BeaconBlockBodyCapella<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(), voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(), sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadCapella { 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(), bls_to_execution_changes: bls_to_execution_changes.clone(),
} }
@ -482,7 +482,7 @@ impl<E: EthSpec> BeaconBlockBodyEip4844<E, FullPayload<E>> {
voluntary_exits: voluntary_exits.clone(), voluntary_exits: voluntary_exits.clone(),
sync_aggregate: sync_aggregate.clone(), sync_aggregate: sync_aggregate.clone(),
execution_payload: BlindedPayloadEip4844 { 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(), bls_to_execution_changes: bls_to_execution_changes.clone(),
blob_kzg_commitments: blob_kzg_commitments.clone(), blob_kzg_commitments: blob_kzg_commitments.clone(),

View File

@ -35,7 +35,9 @@ pub type Withdrawals<T> = VariableList<Withdrawal, <T as EthSpec>::MaxWithdrawal
arbitrary(bound = "T: EthSpec") arbitrary(bound = "T: EthSpec")
), ),
cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"), 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( #[derive(
Debug, Clone, Serialize, Encode, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary, Debug, Clone, Serialize, Encode, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary,

View File

@ -159,40 +159,40 @@ impl<T: EthSpec> ExecutionPayloadHeaderCapella<T> {
} }
} }
impl<T: EthSpec> From<ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> { impl<'a, T: EthSpec> From<&'a ExecutionPayloadMerge<T>> for ExecutionPayloadHeaderMerge<T> {
fn from(payload: ExecutionPayloadMerge<T>) -> Self { fn from(payload: &'a ExecutionPayloadMerge<T>) -> Self {
Self { Self {
parent_hash: payload.parent_hash, parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient, fee_recipient: payload.fee_recipient,
state_root: payload.state_root, state_root: payload.state_root,
receipts_root: payload.receipts_root, receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom, logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao, prev_randao: payload.prev_randao,
block_number: payload.block_number, block_number: payload.block_number,
gas_limit: payload.gas_limit, gas_limit: payload.gas_limit,
gas_used: payload.gas_used, gas_used: payload.gas_used,
timestamp: payload.timestamp, timestamp: payload.timestamp,
extra_data: payload.extra_data, extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas, base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash, block_hash: payload.block_hash,
transactions_root: payload.transactions.tree_hash_root(), transactions_root: payload.transactions.tree_hash_root(),
} }
} }
} }
impl<T: EthSpec> From<ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> { impl<'a, T: EthSpec> From<&'a ExecutionPayloadCapella<T>> for ExecutionPayloadHeaderCapella<T> {
fn from(payload: ExecutionPayloadCapella<T>) -> Self { fn from(payload: &'a ExecutionPayloadCapella<T>) -> Self {
Self { Self {
parent_hash: payload.parent_hash, parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient, fee_recipient: payload.fee_recipient,
state_root: payload.state_root, state_root: payload.state_root,
receipts_root: payload.receipts_root, receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom, logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao, prev_randao: payload.prev_randao,
block_number: payload.block_number, block_number: payload.block_number,
gas_limit: payload.gas_limit, gas_limit: payload.gas_limit,
gas_used: payload.gas_used, gas_used: payload.gas_used,
timestamp: payload.timestamp, timestamp: payload.timestamp,
extra_data: payload.extra_data, extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas, base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash, block_hash: payload.block_hash,
transactions_root: payload.transactions.tree_hash_root(), 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 { Self {
parent_hash: payload.parent_hash, parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient, fee_recipient: payload.fee_recipient,
state_root: payload.state_root, state_root: payload.state_root,
receipts_root: payload.receipts_root, receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom, logs_bloom: payload.logs_bloom.clone(),
prev_randao: payload.prev_randao, prev_randao: payload.prev_randao,
block_number: payload.block_number, block_number: payload.block_number,
gas_limit: payload.gas_limit, gas_limit: payload.gas_limit,
gas_used: payload.gas_used, gas_used: payload.gas_used,
timestamp: payload.timestamp, timestamp: payload.timestamp,
extra_data: payload.extra_data, extra_data: payload.extra_data.clone(),
base_fee_per_gas: payload.base_fee_per_gas, base_fee_per_gas: payload.base_fee_per_gas,
excess_data_gas: payload.excess_data_gas, excess_data_gas: payload.excess_data_gas,
block_hash: payload.block_hash, 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> { // These impls are required to work around an inelegance in `to_execution_payload_header`.
fn from(payload: ExecutionPayloadMerge<T>) -> Self { // They only clone headers so they should be relatively cheap.
Self::Merge(ExecutionPayloadHeaderMerge::from(payload)) 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> { impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderCapella<T> {
fn from(payload: ExecutionPayloadCapella<T>) -> Self { fn from(payload: &'a Self) -> Self {
Self::Capella(ExecutionPayloadHeaderCapella::from(payload)) payload.clone()
} }
} }
impl<T: EthSpec> From<ExecutionPayloadEip4844<T>> for ExecutionPayloadHeader<T> { impl<'a, T: EthSpec> From<&'a Self> for ExecutionPayloadHeaderEip4844<T> {
fn from(payload: ExecutionPayloadEip4844<T>) -> Self { fn from(payload: &'a Self) -> Self {
Self::Eip4844(ExecutionPayloadHeaderEip4844::from(payload)) payload.clone()
} }
} }
impl<T: EthSpec> From<ExecutionPayload<T>> for ExecutionPayloadHeader<T> { impl<'a, T: EthSpec> From<ExecutionPayloadRef<'a, T>> for ExecutionPayloadHeader<T> {
fn from(payload: ExecutionPayload<T>) -> Self { fn from(payload: ExecutionPayloadRef<'a, T>) -> Self {
match payload { map_execution_payload_ref_into_execution_payload_header!(
ExecutionPayload::Merge(payload) => Self::from(payload), &'a _,
ExecutionPayload::Capella(payload) => Self::from(payload), payload,
ExecutionPayload::Eip4844(payload) => Self::from(payload), |inner, cons| cons(inner.into())
} )
} }
} }

View File

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