mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-26 09:13:41 +00:00
Kiln mev boost (#3062)
## Issue Addressed MEV boost compatibility ## Proposed Changes See #2987 ## Additional Info This is blocked on the stabilization of a couple specs, [here](https://github.com/ethereum/beacon-APIs/pull/194) and [here](https://github.com/flashbots/mev-boost/pull/20). Additional TODO's and outstanding questions - [ ] MEV boost JWT Auth - [ ] Will `builder_proposeBlindedBlock` return the revealed payload for the BN to propogate - [ ] Should we remove `private-tx-proposals` flag and communicate BN <> VC with blinded blocks by default once these endpoints enter the beacon-API's repo? This simplifies merge transition logic. Co-authored-by: realbigsean <seananderson33@gmail.com> Co-authored-by: realbigsean <sean@sigmaprime.io>
This commit is contained in:
@@ -6,8 +6,8 @@ use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
use types::{
|
||||
consts::merge::INTERVALS_PER_SLOT, AttestationShufflingId, BeaconBlock, BeaconState,
|
||||
BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||
IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
BeaconStateError, ChainSpec, Checkpoint, Epoch, EthSpec, ExecPayload, ExecutionBlockHash,
|
||||
Hash256, IndexedAttestation, RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -323,7 +323,7 @@ where
|
||||
} else {
|
||||
// Assume that this payload is valid, since the anchor should be a trusted block and
|
||||
// state.
|
||||
ExecutionStatus::Valid(message.body.execution_payload.block_hash)
|
||||
ExecutionStatus::Valid(message.body.execution_payload.block_hash())
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -648,7 +648,7 @@ where
|
||||
.map_err(Error::AfterBlockFailed)?;
|
||||
|
||||
let execution_status = if let Ok(execution_payload) = block.body().execution_payload() {
|
||||
let block_hash = execution_payload.block_hash;
|
||||
let block_hash = execution_payload.block_hash();
|
||||
|
||||
if block_hash == ExecutionBlockHash::zero() {
|
||||
// The block is post-merge-fork, but pre-terminal-PoW block. We don't need to verify
|
||||
|
||||
@@ -87,9 +87,9 @@ pub enum VerifyBlockRoot {
|
||||
/// re-calculating the root when it is already known. Note `block_root` should be equal to the
|
||||
/// tree hash root of the block, NOT the signing root of the block. This function takes
|
||||
/// care of mixing in the domain.
|
||||
pub fn per_block_processing<T: EthSpec>(
|
||||
pub fn per_block_processing<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
signed_block: &SignedBeaconBlock<T>,
|
||||
signed_block: &SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
block_signature_strategy: BlockSignatureStrategy,
|
||||
verify_block_root: VerifyBlockRoot,
|
||||
@@ -129,7 +129,12 @@ pub fn per_block_processing<T: EthSpec>(
|
||||
BlockSignatureStrategy::VerifyRandao => VerifySignatures::False,
|
||||
};
|
||||
|
||||
let proposer_index = process_block_header(state, block, verify_block_root, spec)?;
|
||||
let proposer_index = process_block_header(
|
||||
state,
|
||||
block.temporary_block_header(),
|
||||
verify_block_root,
|
||||
spec,
|
||||
)?;
|
||||
|
||||
if verify_signatures.is_true() {
|
||||
verify_block_signature(state, signed_block, block_root, spec)?;
|
||||
@@ -172,28 +177,28 @@ pub fn per_block_processing<T: EthSpec>(
|
||||
/// Processes the block header, returning the proposer index.
|
||||
pub fn process_block_header<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
block: BeaconBlockRef<'_, T>,
|
||||
block_header: BeaconBlockHeader,
|
||||
verify_block_root: VerifyBlockRoot,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, BlockOperationError<HeaderInvalid>> {
|
||||
// Verify that the slots match
|
||||
verify!(
|
||||
block.slot() == state.slot(),
|
||||
block_header.slot == state.slot(),
|
||||
HeaderInvalid::StateSlotMismatch
|
||||
);
|
||||
|
||||
// Verify that the block is newer than the latest block header
|
||||
verify!(
|
||||
block.slot() > state.latest_block_header().slot,
|
||||
block_header.slot > state.latest_block_header().slot,
|
||||
HeaderInvalid::OlderThanLatestBlockHeader {
|
||||
block_slot: block.slot(),
|
||||
block_slot: block_header.slot,
|
||||
latest_block_header_slot: state.latest_block_header().slot,
|
||||
}
|
||||
);
|
||||
|
||||
// Verify that proposer index is the correct index
|
||||
let proposer_index = block.proposer_index() as usize;
|
||||
let state_proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?;
|
||||
let proposer_index = block_header.proposer_index as usize;
|
||||
let state_proposer_index = state.get_beacon_proposer_index(block_header.slot, spec)?;
|
||||
verify!(
|
||||
proposer_index == state_proposer_index,
|
||||
HeaderInvalid::ProposerIndexMismatch {
|
||||
@@ -205,15 +210,15 @@ pub fn process_block_header<T: EthSpec>(
|
||||
if verify_block_root == VerifyBlockRoot::True {
|
||||
let expected_previous_block_root = state.latest_block_header().tree_hash_root();
|
||||
verify!(
|
||||
block.parent_root() == expected_previous_block_root,
|
||||
block_header.parent_root == expected_previous_block_root,
|
||||
HeaderInvalid::ParentBlockRootMismatch {
|
||||
state: expected_previous_block_root,
|
||||
block: block.parent_root(),
|
||||
block: block_header.parent_root,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
*state.latest_block_header_mut() = block.temporary_block_header();
|
||||
*state.latest_block_header_mut() = block_header;
|
||||
|
||||
// Verify proposer is not slashed
|
||||
verify!(
|
||||
@@ -221,15 +226,15 @@ pub fn process_block_header<T: EthSpec>(
|
||||
HeaderInvalid::ProposerSlashed(proposer_index)
|
||||
);
|
||||
|
||||
Ok(block.proposer_index())
|
||||
Ok(proposer_index as u64)
|
||||
}
|
||||
|
||||
/// Verifies the signature of a block.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
pub fn verify_block_signature<T: EthSpec>(
|
||||
pub fn verify_block_signature<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &BeaconState<T>,
|
||||
block: &SignedBeaconBlock<T>,
|
||||
block: &SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockOperationError<HeaderInvalid>> {
|
||||
@@ -250,9 +255,9 @@ pub fn verify_block_signature<T: EthSpec>(
|
||||
|
||||
/// Verifies the `randao_reveal` against the block's proposer pubkey and updates
|
||||
/// `state.latest_randao_mixes`.
|
||||
pub fn process_randao<T: EthSpec>(
|
||||
pub fn process_randao<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
block: BeaconBlockRef<'_, T>,
|
||||
block: BeaconBlockRef<'_, T, Payload>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
@@ -314,34 +319,34 @@ pub fn get_new_eth1_data<T: EthSpec>(
|
||||
/// Contains a partial set of checks from the `process_execution_payload` function:
|
||||
///
|
||||
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/beacon-chain.md#process_execution_payload
|
||||
pub fn partially_verify_execution_payload<T: EthSpec>(
|
||||
pub fn partially_verify_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &BeaconState<T>,
|
||||
payload: &ExecutionPayload<T>,
|
||||
payload: &Payload,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
if is_merge_transition_complete(state) {
|
||||
block_verify!(
|
||||
payload.parent_hash == state.latest_execution_payload_header()?.block_hash,
|
||||
payload.parent_hash() == state.latest_execution_payload_header()?.block_hash,
|
||||
BlockProcessingError::ExecutionHashChainIncontiguous {
|
||||
expected: state.latest_execution_payload_header()?.block_hash,
|
||||
found: payload.parent_hash,
|
||||
found: payload.parent_hash(),
|
||||
}
|
||||
);
|
||||
}
|
||||
block_verify!(
|
||||
payload.prev_randao == *state.get_randao_mix(state.current_epoch())?,
|
||||
payload.prev_randao() == *state.get_randao_mix(state.current_epoch())?,
|
||||
BlockProcessingError::ExecutionRandaoMismatch {
|
||||
expected: *state.get_randao_mix(state.current_epoch())?,
|
||||
found: payload.prev_randao,
|
||||
found: payload.prev_randao(),
|
||||
}
|
||||
);
|
||||
|
||||
let timestamp = compute_timestamp_at_slot(state, spec)?;
|
||||
block_verify!(
|
||||
payload.timestamp == timestamp,
|
||||
payload.timestamp() == timestamp,
|
||||
BlockProcessingError::ExecutionInvalidTimestamp {
|
||||
expected: timestamp,
|
||||
found: payload.timestamp,
|
||||
found: payload.timestamp(),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -355,29 +360,14 @@ pub fn partially_verify_execution_payload<T: EthSpec>(
|
||||
/// Partially equivalent to the `process_execution_payload` function:
|
||||
///
|
||||
/// 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>(
|
||||
pub fn process_execution_payload<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
payload: &ExecutionPayload<T>,
|
||||
payload: &Payload,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
partially_verify_execution_payload(state, payload, spec)?;
|
||||
|
||||
*state.latest_execution_payload_header_mut()? = ExecutionPayloadHeader {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data.clone(),
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions_root: payload.transactions.tree_hash_root(),
|
||||
};
|
||||
*state.latest_execution_payload_header_mut()? = payload.to_execution_payload_header();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -394,24 +384,21 @@ pub fn is_merge_transition_complete<T: EthSpec>(state: &BeaconState<T>) -> bool
|
||||
.unwrap_or(false)
|
||||
}
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_merge_transition_block
|
||||
pub fn is_merge_transition_block<T: EthSpec>(
|
||||
pub fn is_merge_transition_block<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &BeaconState<T>,
|
||||
body: BeaconBlockBodyRef<T>,
|
||||
body: BeaconBlockBodyRef<T, Payload>,
|
||||
) -> bool {
|
||||
body.execution_payload()
|
||||
.map(|payload| {
|
||||
!is_merge_transition_complete(state) && *payload != <ExecutionPayload<T>>::default()
|
||||
})
|
||||
.map(|payload| !is_merge_transition_complete(state) && *payload != Payload::default())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_execution_enabled
|
||||
pub fn is_execution_enabled<T: EthSpec>(
|
||||
pub fn is_execution_enabled<T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &BeaconState<T>,
|
||||
body: BeaconBlockBodyRef<T>,
|
||||
body: BeaconBlockBodyRef<T, Payload>,
|
||||
) -> bool {
|
||||
is_merge_transition_block(state, body) || is_merge_transition_complete(state)
|
||||
}
|
||||
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#compute_timestamp_at_slot
|
||||
pub fn compute_timestamp_at_slot<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
|
||||
@@ -7,7 +7,7 @@ use bls::{verify_signature_sets, PublicKey, PublicKeyBytes, SignatureSet};
|
||||
use rayon::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
use types::{
|
||||
BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256, IndexedAttestation,
|
||||
BeaconState, BeaconStateError, ChainSpec, EthSpec, ExecPayload, Hash256, IndexedAttestation,
|
||||
SignedBeaconBlock,
|
||||
};
|
||||
|
||||
@@ -117,11 +117,11 @@ where
|
||||
/// contains invalid signatures on deposits._
|
||||
///
|
||||
/// See `Self::verify` for more detail.
|
||||
pub fn verify_entire_block(
|
||||
pub fn verify_entire_block<Payload: ExecPayload<T>>(
|
||||
state: &'a BeaconState<T>,
|
||||
get_pubkey: F,
|
||||
decompressor: D,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<()> {
|
||||
@@ -131,9 +131,9 @@ where
|
||||
}
|
||||
|
||||
/// Includes all signatures on the block (except the deposit signatures) for verification.
|
||||
pub fn include_all_signatures(
|
||||
pub fn include_all_signatures<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
) -> Result<()> {
|
||||
self.include_block_proposal(block, block_root)?;
|
||||
@@ -144,9 +144,9 @@ where
|
||||
|
||||
/// Includes all signatures on the block (except the deposit signatures and the proposal
|
||||
/// signature) for verification.
|
||||
pub fn include_all_signatures_except_proposal(
|
||||
pub fn include_all_signatures_except_proposal<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
self.include_randao_reveal(block)?;
|
||||
self.include_proposer_slashings(block)?;
|
||||
@@ -160,9 +160,9 @@ where
|
||||
}
|
||||
|
||||
/// Includes the block signature for `self.block` for verification.
|
||||
pub fn include_block_proposal(
|
||||
pub fn include_block_proposal<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
) -> Result<()> {
|
||||
let set = block_proposal_signature_set(
|
||||
@@ -177,7 +177,10 @@ where
|
||||
}
|
||||
|
||||
/// Includes the randao signature for `self.block` for verification.
|
||||
pub fn include_randao_reveal(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
pub fn include_randao_reveal<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
let set = randao_signature_set(
|
||||
self.state,
|
||||
self.get_pubkey.clone(),
|
||||
@@ -189,7 +192,10 @@ where
|
||||
}
|
||||
|
||||
/// Includes all signatures in `self.block.body.proposer_slashings` for verification.
|
||||
pub fn include_proposer_slashings(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
pub fn include_proposer_slashings<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
self.sets
|
||||
.sets
|
||||
.reserve(block.message().body().proposer_slashings().len() * 2);
|
||||
@@ -215,7 +221,10 @@ where
|
||||
}
|
||||
|
||||
/// Includes all signatures in `self.block.body.attester_slashings` for verification.
|
||||
pub fn include_attester_slashings(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
pub fn include_attester_slashings<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
self.sets
|
||||
.sets
|
||||
.reserve(block.message().body().attester_slashings().len() * 2);
|
||||
@@ -241,9 +250,9 @@ where
|
||||
}
|
||||
|
||||
/// Includes all signatures in `self.block.body.attestations` for verification.
|
||||
pub fn include_attestations(
|
||||
pub fn include_attestations<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<Vec<IndexedAttestation<T>>> {
|
||||
self.sets
|
||||
.sets
|
||||
@@ -280,7 +289,10 @@ where
|
||||
}
|
||||
|
||||
/// Includes all signatures in `self.block.body.voluntary_exits` for verification.
|
||||
pub fn include_exits(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
pub fn include_exits<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
self.sets
|
||||
.sets
|
||||
.reserve(block.message().body().voluntary_exits().len());
|
||||
@@ -301,7 +313,10 @@ where
|
||||
}
|
||||
|
||||
/// Include the signature of the block's sync aggregate (if it exists) for verification.
|
||||
pub fn include_sync_aggregate(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
pub fn include_sync_aggregate<Payload: ExecPayload<T>>(
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T, Payload>,
|
||||
) -> Result<()> {
|
||||
if let Ok(sync_aggregate) = block.message().body().sync_aggregate() {
|
||||
if let Some(signature_set) = sync_aggregate_signature_set(
|
||||
&self.decompressor,
|
||||
|
||||
@@ -8,9 +8,9 @@ use crate::VerifySignatures;
|
||||
use safe_arith::SafeArith;
|
||||
use types::consts::altair::{PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_DENOMINATOR};
|
||||
|
||||
pub fn process_operations<'a, T: EthSpec>(
|
||||
pub fn process_operations<'a, T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T, Payload>,
|
||||
proposer_index: u64,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
@@ -217,9 +217,9 @@ pub fn process_attester_slashings<T: EthSpec>(
|
||||
}
|
||||
/// Wrapper function to handle calling the correct version of `process_attestations` based on
|
||||
/// the fork.
|
||||
pub fn process_attestations<'a, T: EthSpec>(
|
||||
pub fn process_attestations<'a, T: EthSpec, Payload: ExecPayload<T>>(
|
||||
state: &mut BeaconState<T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T, Payload>,
|
||||
proposer_index: u64,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
|
||||
@@ -8,10 +8,11 @@ use std::borrow::Cow;
|
||||
use tree_hash::TreeHash;
|
||||
use types::{
|
||||
AggregateSignature, AttesterSlashing, BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec,
|
||||
DepositData, Domain, Epoch, EthSpec, Fork, Hash256, InconsistentFork, IndexedAttestation,
|
||||
ProposerSlashing, PublicKey, PublicKeyBytes, Signature, SignedAggregateAndProof,
|
||||
SignedBeaconBlock, SignedBeaconBlockHeader, SignedContributionAndProof, SignedRoot,
|
||||
SignedVoluntaryExit, SigningData, Slot, SyncAggregate, SyncAggregatorSelectionData, Unsigned,
|
||||
DepositData, Domain, Epoch, EthSpec, ExecPayload, Fork, Hash256, InconsistentFork,
|
||||
IndexedAttestation, ProposerSlashing, PublicKey, PublicKeyBytes, Signature,
|
||||
SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockHeader,
|
||||
SignedContributionAndProof, SignedRoot, SignedVoluntaryExit, SigningData, Slot, SyncAggregate,
|
||||
SyncAggregatorSelectionData, Unsigned,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -70,10 +71,10 @@ where
|
||||
}
|
||||
|
||||
/// A signature set that is valid if a block was signed by the expected block producer.
|
||||
pub fn block_proposal_signature_set<'a, T, F>(
|
||||
pub fn block_proposal_signature_set<'a, T, F, Payload: ExecPayload<T>>(
|
||||
state: &'a BeaconState<T>,
|
||||
get_pubkey: F,
|
||||
signed_block: &'a SignedBeaconBlock<T>,
|
||||
signed_block: &'a SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
@@ -107,8 +108,8 @@ where
|
||||
/// Unlike `block_proposal_signature_set` this does **not** check that the proposer index is
|
||||
/// correct according to the shuffling. It should only be used if no suitable `BeaconState` is
|
||||
/// available.
|
||||
pub fn block_proposal_signature_set_from_parts<'a, T, F>(
|
||||
signed_block: &'a SignedBeaconBlock<T>,
|
||||
pub fn block_proposal_signature_set_from_parts<'a, T, F, Payload: ExecPayload<T>>(
|
||||
signed_block: &'a SignedBeaconBlock<T, Payload>,
|
||||
block_root: Option<Hash256>,
|
||||
proposer_index: u64,
|
||||
fork: &Fork,
|
||||
@@ -151,10 +152,10 @@ where
|
||||
}
|
||||
|
||||
/// A signature set that is valid if the block proposers randao reveal signature is correct.
|
||||
pub fn randao_signature_set<'a, T, F>(
|
||||
pub fn randao_signature_set<'a, T, F, Payload: ExecPayload<T>>(
|
||||
state: &'a BeaconState<T>,
|
||||
get_pubkey: F,
|
||||
block: BeaconBlockRef<'a, T>,
|
||||
block: BeaconBlockRef<'a, T, Payload>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
|
||||
@@ -43,7 +43,7 @@ regex = "1.5.5"
|
||||
lazy_static = "1.4.0"
|
||||
parking_lot = "0.11.1"
|
||||
itertools = "0.10.0"
|
||||
superstruct = "0.4.0"
|
||||
superstruct = "0.4.1"
|
||||
serde_json = "1.0.74"
|
||||
smallvec = "1.8.0"
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::marker::PhantomData;
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
@@ -29,8 +30,8 @@ use tree_hash_derive::TreeHash;
|
||||
TestRandom,
|
||||
Derivative,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec")),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: ExecPayload<T>")),
|
||||
serde(bound = "T: EthSpec, Payload: ExecPayload<T>", deny_unknown_fields),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary)),
|
||||
),
|
||||
ref_attributes(
|
||||
@@ -41,11 +42,11 @@ use tree_hash_derive::TreeHash;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[serde(bound = "T: EthSpec, Payload: ExecPayload<T>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct BeaconBlock<T: EthSpec> {
|
||||
pub struct BeaconBlock<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>> {
|
||||
#[superstruct(getter(copy))]
|
||||
pub slot: Slot,
|
||||
#[superstruct(getter(copy))]
|
||||
@@ -56,17 +57,17 @@ pub struct BeaconBlock<T: EthSpec> {
|
||||
#[superstruct(getter(copy))]
|
||||
pub state_root: Hash256,
|
||||
#[superstruct(only(Base), partial_getter(rename = "body_base"))]
|
||||
pub body: BeaconBlockBodyBase<T>,
|
||||
pub body: BeaconBlockBodyBase<T, Payload>,
|
||||
#[superstruct(only(Altair), partial_getter(rename = "body_altair"))]
|
||||
pub body: BeaconBlockBodyAltair<T>,
|
||||
pub body: BeaconBlockBodyAltair<T, Payload>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "body_merge"))]
|
||||
pub body: BeaconBlockBodyMerge<T>,
|
||||
pub body: BeaconBlockBodyMerge<T, Payload>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> SignedRoot for BeaconBlock<T> {}
|
||||
impl<'a, T: EthSpec> SignedRoot for BeaconBlockRef<'a, T> {}
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> SignedRoot for BeaconBlock<T, Payload> {}
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> SignedRoot for BeaconBlockRef<'a, T, Payload> {}
|
||||
|
||||
impl<T: EthSpec> BeaconBlock<T> {
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlock<T, Payload> {
|
||||
/// Returns an empty block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
if spec.bellatrix_fork_epoch == Some(T::genesis_epoch()) {
|
||||
@@ -114,12 +115,12 @@ impl<T: EthSpec> BeaconBlock<T> {
|
||||
}
|
||||
|
||||
/// Convenience accessor for the `body` as a `BeaconBlockBodyRef`.
|
||||
pub fn body(&self) -> BeaconBlockBodyRef<'_, T> {
|
||||
pub fn body(&self) -> BeaconBlockBodyRef<'_, T, Payload> {
|
||||
self.to_ref().body()
|
||||
}
|
||||
|
||||
/// Convenience accessor for the `body` as a `BeaconBlockBodyRefMut`.
|
||||
pub fn body_mut(&mut self) -> BeaconBlockBodyRefMut<'_, T> {
|
||||
pub fn body_mut(&mut self) -> BeaconBlockBodyRefMut<'_, T, Payload> {
|
||||
self.to_mut().body_mut()
|
||||
}
|
||||
|
||||
@@ -160,7 +161,7 @@ impl<T: EthSpec> BeaconBlock<T> {
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> SignedBeaconBlock<T> {
|
||||
) -> SignedBeaconBlock<T, Payload> {
|
||||
let domain = spec.get_domain(
|
||||
self.epoch(),
|
||||
Domain::BeaconProposer,
|
||||
@@ -173,7 +174,7 @@ impl<T: EthSpec> BeaconBlock<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRef<'a, T, Payload> {
|
||||
/// Returns the name of the fork pertaining to `self`.
|
||||
///
|
||||
/// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork
|
||||
@@ -197,7 +198,7 @@ impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
}
|
||||
|
||||
/// Convenience accessor for the `body` as a `BeaconBlockBodyRef`.
|
||||
pub fn body(&self) -> BeaconBlockBodyRef<'a, T> {
|
||||
pub fn body(&self) -> BeaconBlockBodyRef<'a, T, Payload> {
|
||||
match self {
|
||||
BeaconBlockRef::Base(block) => BeaconBlockBodyRef::Base(&block.body),
|
||||
BeaconBlockRef::Altair(block) => BeaconBlockBodyRef::Altair(&block.body),
|
||||
@@ -240,14 +241,14 @@ impl<'a, T: EthSpec> BeaconBlockRef<'a, T> {
|
||||
|
||||
/// Extracts a reference to an execution payload from a block, returning an error if the block
|
||||
/// is pre-merge.
|
||||
pub fn execution_payload(&self) -> Result<&ExecutionPayload<T>, Error> {
|
||||
pub fn execution_payload(&self) -> Result<&Payload, Error> {
|
||||
self.body().execution_payload()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BeaconBlockRefMut<'a, T> {
|
||||
impl<'a, T: EthSpec, Payload: ExecPayload<T>> BeaconBlockRefMut<'a, T, Payload> {
|
||||
/// Convert a mutable reference to a beacon block to a mutable ref to its body.
|
||||
pub fn body_mut(self) -> BeaconBlockBodyRefMut<'a, T> {
|
||||
pub fn body_mut(self) -> BeaconBlockBodyRefMut<'a, T, Payload> {
|
||||
match self {
|
||||
BeaconBlockRefMut::Base(block) => BeaconBlockBodyRefMut::Base(&mut block.body),
|
||||
BeaconBlockRefMut::Altair(block) => BeaconBlockBodyRefMut::Altair(&mut block.body),
|
||||
@@ -256,7 +257,7 @@ impl<'a, T: EthSpec> BeaconBlockRefMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> BeaconBlockBase<T> {
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockBase<T, Payload> {
|
||||
/// Returns an empty block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockBase {
|
||||
@@ -277,6 +278,7 @@ impl<T: EthSpec> BeaconBlockBase<T> {
|
||||
attestations: VariableList::empty(),
|
||||
deposits: VariableList::empty(),
|
||||
voluntary_exits: VariableList::empty(),
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -343,7 +345,7 @@ impl<T: EthSpec> BeaconBlockBase<T> {
|
||||
signature: Signature::empty(),
|
||||
};
|
||||
|
||||
let mut block = BeaconBlockBase::<T>::empty(spec);
|
||||
let mut block = BeaconBlockBase::<T, Payload>::empty(spec);
|
||||
for _ in 0..T::MaxProposerSlashings::to_usize() {
|
||||
block
|
||||
.body
|
||||
@@ -376,7 +378,7 @@ impl<T: EthSpec> BeaconBlockBase<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> BeaconBlockAltair<T> {
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockAltair<T, Payload> {
|
||||
/// Returns an empty Altair block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockAltair {
|
||||
@@ -398,13 +400,14 @@ impl<T: EthSpec> BeaconBlockAltair<T> {
|
||||
deposits: VariableList::empty(),
|
||||
voluntary_exits: VariableList::empty(),
|
||||
sync_aggregate: SyncAggregate::empty(),
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an Altair block where the block has maximum size.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
let base_block = BeaconBlockBase::full(spec);
|
||||
let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec);
|
||||
let sync_aggregate = SyncAggregate {
|
||||
sync_committee_signature: AggregateSignature::empty(),
|
||||
sync_committee_bits: BitVector::default(),
|
||||
@@ -428,12 +431,13 @@ impl<T: EthSpec> BeaconBlockAltair<T> {
|
||||
deposit_count: 0,
|
||||
},
|
||||
graffiti: Graffiti::default(),
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> BeaconBlockMerge<T> {
|
||||
impl<T: EthSpec, Payload: ExecPayload<T>> BeaconBlockMerge<T, Payload> {
|
||||
/// Returns an empty Merge block to be used during genesis.
|
||||
pub fn empty(spec: &ChainSpec) -> Self {
|
||||
BeaconBlockMerge {
|
||||
@@ -455,34 +459,7 @@ impl<T: EthSpec> BeaconBlockMerge<T> {
|
||||
deposits: VariableList::empty(),
|
||||
voluntary_exits: VariableList::empty(),
|
||||
sync_aggregate: SyncAggregate::empty(),
|
||||
execution_payload: ExecutionPayload::empty(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Return an Merge block where the block has maximum size.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
let altair_block = BeaconBlockAltair::full(spec);
|
||||
BeaconBlockMerge {
|
||||
slot: spec.genesis_slot,
|
||||
proposer_index: 0,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyMerge {
|
||||
proposer_slashings: altair_block.body.proposer_slashings,
|
||||
attester_slashings: altair_block.body.attester_slashings,
|
||||
attestations: altair_block.body.attestations,
|
||||
deposits: altair_block.body.deposits,
|
||||
voluntary_exits: altair_block.body.voluntary_exits,
|
||||
sync_aggregate: altair_block.body.sync_aggregate,
|
||||
randao_reveal: Signature::empty(),
|
||||
eth1_data: Eth1Data {
|
||||
deposit_root: Hash256::zero(),
|
||||
block_hash: Hash256::zero(),
|
||||
deposit_count: 0,
|
||||
},
|
||||
graffiti: Graffiti::default(),
|
||||
execution_payload: ExecutionPayload::default(),
|
||||
execution_payload: Payload::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use std::marker::PhantomData;
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
@@ -25,8 +26,8 @@ use tree_hash_derive::TreeHash;
|
||||
TestRandom,
|
||||
Derivative,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec")),
|
||||
serde(bound = "T: EthSpec", deny_unknown_fields),
|
||||
derivative(PartialEq, Hash(bound = "T: EthSpec, Payload: ExecPayload<T>")),
|
||||
serde(bound = "T: EthSpec, Payload: ExecPayload<T>", deny_unknown_fields),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))
|
||||
),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
@@ -35,9 +36,9 @@ use tree_hash_derive::TreeHash;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[serde(bound = "T: EthSpec, Payload: ExecPayload<T>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
pub struct BeaconBlockBody<T: EthSpec> {
|
||||
pub struct BeaconBlockBody<T: EthSpec, Payload: ExecPayload<T> = FullPayload<T>> {
|
||||
pub randao_reveal: Signature,
|
||||
pub eth1_data: Eth1Data,
|
||||
pub graffiti: Graffiti,
|
||||
@@ -48,8 +49,17 @@ pub struct BeaconBlockBody<T: EthSpec> {
|
||||
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
|
||||
#[superstruct(only(Altair, Merge))]
|
||||
pub sync_aggregate: SyncAggregate<T>,
|
||||
// We flatten the execution payload so that serde can use the name of the inner type,
|
||||
// either `execution_payload` for full payloads, or `execution_payload_header` for blinded
|
||||
// payloads.
|
||||
#[superstruct(only(Merge))]
|
||||
pub execution_payload: ExecutionPayload<T>,
|
||||
#[serde(flatten)]
|
||||
pub execution_payload: Payload,
|
||||
#[superstruct(only(Base, Altair))]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
#[tree_hash(skip_hashing)]
|
||||
#[serde(skip)]
|
||||
pub _phantom: PhantomData<Payload>,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BeaconBlockBodyRef<'a, T> {
|
||||
|
||||
@@ -6,7 +6,11 @@ use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
pub type Transaction<T> = VariableList<u8, T>;
|
||||
pub type Transaction<N> = VariableList<u8, N>;
|
||||
pub type Transactions<T> = VariableList<
|
||||
Transaction<<T as EthSpec>::MaxBytesPerTransaction>,
|
||||
<T as EthSpec>::MaxTransactionsPerPayload,
|
||||
>;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
@@ -36,8 +40,7 @@ pub struct ExecutionPayload<T: EthSpec> {
|
||||
pub base_fee_per_gas: Uint256,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions:
|
||||
VariableList<Transaction<T::MaxBytesPerTransaction>, T::MaxTransactionsPerPayload>,
|
||||
pub transactions: Transactions<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayload<T> {
|
||||
@@ -50,9 +53,9 @@ impl<T: EthSpec> ExecutionPayload<T> {
|
||||
pub fn max_execution_payload_size() -> usize {
|
||||
// Fixed part
|
||||
Self::empty().as_ssz_bytes().len()
|
||||
// Max size of variable length `extra_data` field
|
||||
+ (T::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len())
|
||||
// Max size of variable length `transactions` field
|
||||
+ (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction()))
|
||||
// Max size of variable length `extra_data` field
|
||||
+ (T::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len())
|
||||
// Max size of variable length `transactions` field
|
||||
+ (T::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + T::max_bytes_per_transaction()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[derive(
|
||||
Default, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
|
||||
Default, Debug, Clone, Serialize, Deserialize, Derivative, Encode, Decode, TreeHash, TestRandom,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
pub struct ExecutionPayloadHeader<T: EthSpec> {
|
||||
pub parent_hash: ExecutionBlockHash,
|
||||
pub fee_recipient: Address,
|
||||
@@ -37,3 +40,24 @@ impl<T: EthSpec> ExecutionPayloadHeader<T> {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> From<&'a ExecutionPayload<T>> for ExecutionPayloadHeader<T> {
|
||||
fn from(payload: &'a ExecutionPayload<T>) -> Self {
|
||||
ExecutionPayloadHeader {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data.clone(),
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions_root: payload.transactions.tree_hash_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ pub mod config_and_preset;
|
||||
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;
|
||||
@@ -115,7 +116,7 @@ pub use crate::enr_fork_id::EnrForkId;
|
||||
pub use crate::eth1_data::Eth1Data;
|
||||
pub use crate::eth_spec::EthSpecId;
|
||||
pub use crate::execution_block_hash::ExecutionBlockHash;
|
||||
pub use crate::execution_payload::{ExecutionPayload, Transaction};
|
||||
pub use crate::execution_payload::{ExecutionPayload, Transaction, Transactions};
|
||||
pub use crate::execution_payload_header::ExecutionPayloadHeader;
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
@@ -127,6 +128,7 @@ pub use crate::historical_batch::HistoricalBatch;
|
||||
pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::payload::{BlindedPayload, BlockType, ExecPayload, FullPayload};
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset};
|
||||
pub use crate::proposer_preparation_data::ProposerPreparationData;
|
||||
|
||||
236
consensus/types/src/payload.rs
Normal file
236
consensus/types/src/payload.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
use crate::{test_utils::TestRandom, *};
|
||||
use derivative::Derivative;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, DecodeError, Encode};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
|
||||
pub enum BlockType {
|
||||
Blinded,
|
||||
Full,
|
||||
}
|
||||
|
||||
pub trait ExecPayload<T: EthSpec>:
|
||||
Encode
|
||||
+ Decode
|
||||
+ TestRandom
|
||||
+ TreeHash
|
||||
+ Default
|
||||
+ PartialEq
|
||||
+ Serialize
|
||||
+ DeserializeOwned
|
||||
+ Hash
|
||||
+ TryFrom<ExecutionPayloadHeader<T>>
|
||||
+ From<ExecutionPayload<T>>
|
||||
{
|
||||
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 timestamp(&self) -> u64;
|
||||
fn block_hash(&self) -> ExecutionBlockHash;
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::Full
|
||||
}
|
||||
|
||||
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
|
||||
ExecutionPayloadHeader::from(&self.execution_payload)
|
||||
}
|
||||
|
||||
fn parent_hash(&self) -> ExecutionBlockHash {
|
||||
self.execution_payload.parent_hash
|
||||
}
|
||||
|
||||
fn prev_randao(&self) -> Hash256 {
|
||||
self.execution_payload.prev_randao
|
||||
}
|
||||
|
||||
fn timestamp(&self) -> u64 {
|
||||
self.execution_payload.timestamp
|
||||
}
|
||||
|
||||
fn block_hash(&self) -> ExecutionBlockHash {
|
||||
self.execution_payload.block_hash
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::Blinded
|
||||
}
|
||||
|
||||
fn to_execution_payload_header(&self) -> ExecutionPayloadHeader<T> {
|
||||
self.execution_payload_header.clone()
|
||||
}
|
||||
|
||||
fn parent_hash(&self) -> ExecutionBlockHash {
|
||||
self.execution_payload_header.parent_hash
|
||||
}
|
||||
|
||||
fn prev_randao(&self) -> Hash256 {
|
||||
self.execution_payload_header.prev_randao
|
||||
}
|
||||
|
||||
fn timestamp(&self) -> u64 {
|
||||
self.execution_payload_header.timestamp
|
||||
}
|
||||
|
||||
fn block_hash(&self) -> ExecutionBlockHash {
|
||||
self.execution_payload_header.block_hash
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, TestRandom, Serialize, Deserialize, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
pub struct BlindedPayload<T: EthSpec> {
|
||||
pub execution_payload_header: ExecutionPayloadHeader<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<ExecutionPayloadHeader<T>> for BlindedPayload<T> {
|
||||
fn from(execution_payload_header: ExecutionPayloadHeader<T>) -> Self {
|
||||
Self {
|
||||
execution_payload_header,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<BlindedPayload<T>> for ExecutionPayloadHeader<T> {
|
||||
fn from(blinded: BlindedPayload<T>) -> Self {
|
||||
blinded.execution_payload_header
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<ExecutionPayload<T>> for BlindedPayload<T> {
|
||||
fn from(execution_payload: ExecutionPayload<T>) -> Self {
|
||||
Self {
|
||||
execution_payload_header: ExecutionPayloadHeader::from(&execution_payload),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TreeHash for BlindedPayload<T> {
|
||||
fn tree_hash_type() -> tree_hash::TreeHashType {
|
||||
<ExecutionPayloadHeader<T>>::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
|
||||
self.execution_payload_header.tree_hash_packed_encoding()
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
<ExecutionPayloadHeader<T>>::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> tree_hash::Hash256 {
|
||||
self.execution_payload_header.tree_hash_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Decode for BlindedPayload<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<ExecutionPayloadHeader<T> as Decode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_fixed_len() -> usize {
|
||||
<ExecutionPayloadHeader<T> as Decode>::ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
Ok(Self {
|
||||
execution_payload_header: ExecutionPayloadHeader::from_ssz_bytes(bytes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Encode for BlindedPayload<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<ExecutionPayloadHeader<T> as Encode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
self.execution_payload_header.ssz_append(buf)
|
||||
}
|
||||
|
||||
fn ssz_bytes_len(&self) -> usize {
|
||||
self.execution_payload_header.ssz_bytes_len()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, TestRandom, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = "T: EthSpec"))]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
pub struct FullPayload<T: EthSpec> {
|
||||
pub execution_payload: ExecutionPayload<T>,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<ExecutionPayload<T>> for FullPayload<T> {
|
||||
fn from(execution_payload: ExecutionPayload<T>) -> Self {
|
||||
Self { execution_payload }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TryFrom<ExecutionPayloadHeader<T>> for FullPayload<T> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(_: ExecutionPayloadHeader<T>) -> Result<Self, Self::Error> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TreeHash for FullPayload<T> {
|
||||
fn tree_hash_type() -> tree_hash::TreeHashType {
|
||||
<ExecutionPayload<T>>::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
|
||||
self.execution_payload.tree_hash_packed_encoding()
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
<ExecutionPayload<T>>::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> tree_hash::Hash256 {
|
||||
self.execution_payload.tree_hash_root()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Decode for FullPayload<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<ExecutionPayload<T> as Decode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
Ok(FullPayload {
|
||||
execution_payload: Decode::from_ssz_bytes(bytes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> Encode for FullPayload<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
<ExecutionPayload<T> as Encode>::is_ssz_fixed_len()
|
||||
}
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
self.execution_payload.ssz_append(buf)
|
||||
}
|
||||
|
||||
fn ssz_bytes_len(&self) -> usize {
|
||||
self.execution_payload.ssz_bytes_len()
|
||||
}
|
||||
}
|
||||
@@ -52,27 +52,27 @@ impl From<SignedBeaconBlockHash> for Hash256 {
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary)),
|
||||
serde(bound = "E: EthSpec")
|
||||
serde(bound = "E: EthSpec, Payload: ExecPayload<E>"),
|
||||
)
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[serde(untagged)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[serde(bound = "E: EthSpec, Payload: ExecPayload<E>")]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct SignedBeaconBlock<E: EthSpec> {
|
||||
pub struct SignedBeaconBlock<E: EthSpec, Payload: ExecPayload<E> = FullPayload<E>> {
|
||||
#[superstruct(only(Base), partial_getter(rename = "message_base"))]
|
||||
pub message: BeaconBlockBase<E>,
|
||||
pub message: BeaconBlockBase<E, Payload>,
|
||||
#[superstruct(only(Altair), partial_getter(rename = "message_altair"))]
|
||||
pub message: BeaconBlockAltair<E>,
|
||||
pub message: BeaconBlockAltair<E, Payload>,
|
||||
#[superstruct(only(Merge), partial_getter(rename = "message_merge"))]
|
||||
pub message: BeaconBlockMerge<E>,
|
||||
pub message: BeaconBlockMerge<E, Payload>,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
impl<E: EthSpec, Payload: ExecPayload<E>> SignedBeaconBlock<E, Payload> {
|
||||
/// Returns the name of the fork pertaining to `self`.
|
||||
///
|
||||
/// Will return an `Err` if `self` has been instantiated to a variant conflicting with the fork
|
||||
@@ -94,7 +94,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
/// SSZ decode with custom decode function.
|
||||
pub fn from_ssz_bytes_with(
|
||||
bytes: &[u8],
|
||||
block_decoder: impl FnOnce(&[u8]) -> Result<BeaconBlock<E>, ssz::DecodeError>,
|
||||
block_decoder: impl FnOnce(&[u8]) -> Result<BeaconBlock<E, Payload>, ssz::DecodeError>,
|
||||
) -> Result<Self, ssz::DecodeError> {
|
||||
// We need the customer decoder for `BeaconBlock`, which doesn't compose with the other
|
||||
// SSZ utils, so we duplicate some parts of `ssz_derive` here.
|
||||
@@ -113,7 +113,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
}
|
||||
|
||||
/// Create a new `SignedBeaconBlock` from a `BeaconBlock` and `Signature`.
|
||||
pub fn from_block(block: BeaconBlock<E>, signature: Signature) -> Self {
|
||||
pub fn from_block(block: BeaconBlock<E, Payload>, signature: Signature) -> Self {
|
||||
match block {
|
||||
BeaconBlock::Base(message) => {
|
||||
SignedBeaconBlock::Base(SignedBeaconBlockBase { message, signature })
|
||||
@@ -131,7 +131,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
///
|
||||
/// This is necessary to get a `&BeaconBlock` from a `SignedBeaconBlock` because
|
||||
/// `SignedBeaconBlock` only contains a `BeaconBlock` _variant_.
|
||||
pub fn deconstruct(self) -> (BeaconBlock<E>, Signature) {
|
||||
pub fn deconstruct(self) -> (BeaconBlock<E, Payload>, Signature) {
|
||||
match self {
|
||||
SignedBeaconBlock::Base(block) => (BeaconBlock::Base(block.message), block.signature),
|
||||
SignedBeaconBlock::Altair(block) => {
|
||||
@@ -142,7 +142,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
}
|
||||
|
||||
/// Accessor for the block's `message` field as a ref.
|
||||
pub fn message(&self) -> BeaconBlockRef<'_, E> {
|
||||
pub fn message(&self) -> BeaconBlockRef<'_, E, Payload> {
|
||||
match self {
|
||||
SignedBeaconBlock::Base(inner) => BeaconBlockRef::Base(&inner.message),
|
||||
SignedBeaconBlock::Altair(inner) => BeaconBlockRef::Altair(&inner.message),
|
||||
@@ -151,7 +151,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
|
||||
}
|
||||
|
||||
/// Accessor for the block's `message` as a mutable reference (for testing only).
|
||||
pub fn message_mut(&mut self) -> BeaconBlockRefMut<'_, E> {
|
||||
pub fn message_mut(&mut self) -> BeaconBlockRefMut<'_, E, Payload> {
|
||||
match self {
|
||||
SignedBeaconBlock::Base(inner) => BeaconBlockRefMut::Base(&mut inner.message),
|
||||
SignedBeaconBlock::Altair(inner) => BeaconBlockRefMut::Altair(&mut inner.message),
|
||||
|
||||
@@ -3,6 +3,7 @@ use rand::RngCore;
|
||||
use rand::SeedableRng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use ssz_types::typenum::Unsigned;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod address;
|
||||
@@ -25,6 +26,12 @@ pub trait TestRandom {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self;
|
||||
}
|
||||
|
||||
impl<T> TestRandom for PhantomData<T> {
|
||||
fn random_for_test(_rng: &mut impl RngCore) -> Self {
|
||||
PhantomData::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestRandom for bool {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
(rng.next_u32() % 2) == 1
|
||||
|
||||
Reference in New Issue
Block a user