mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-16 11:22:56 +00:00
Block v3 endpoint (#4629)
## Issue Addressed #4582 ## Proposed Changes Add a new v3 block fetching flow that can decide to return a Full OR Blinded payload ## Additional Info Co-authored-by: Michael Sproul <micsproul@gmail.com>
This commit is contained in:
@@ -33,6 +33,17 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
state.build_committee_cache(RelativeEpoch::Previous, &self.spec)?;
|
||||
state.build_committee_cache(RelativeEpoch::Current, &self.spec)?;
|
||||
|
||||
self.compute_beacon_block_reward_with_cache(block, block_root, state)
|
||||
}
|
||||
|
||||
// This should only be called after a committee cache has been built
|
||||
// for both the previous and current epoch
|
||||
fn compute_beacon_block_reward_with_cache<Payload: AbstractExecPayload<T::EthSpec>>(
|
||||
&self,
|
||||
block: BeaconBlockRef<'_, T::EthSpec, Payload>,
|
||||
block_root: Hash256,
|
||||
state: &BeaconState<T::EthSpec>,
|
||||
) -> Result<StandardBlockReward, BeaconChainError> {
|
||||
let proposer_index = block.proposer_index();
|
||||
|
||||
let sync_aggregate_reward =
|
||||
@@ -178,7 +189,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
>(
|
||||
&self,
|
||||
block: BeaconBlockRef<'_, T::EthSpec, Payload>,
|
||||
state: &mut BeaconState<T::EthSpec>,
|
||||
state: &BeaconState<T::EthSpec>,
|
||||
) -> Result<BeaconBlockSubRewardValue, BeaconChainError> {
|
||||
let total_active_balance = state.get_total_active_balance()?;
|
||||
let base_reward_per_increment =
|
||||
@@ -191,6 +202,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.safe_mul(WEIGHT_DENOMINATOR)?
|
||||
.safe_div(PROPOSER_WEIGHT)?;
|
||||
|
||||
let mut current_epoch_participation = state.current_epoch_participation()?.clone();
|
||||
let mut previous_epoch_participation = state.previous_epoch_participation()?.clone();
|
||||
|
||||
for attestation in block.body().attestations() {
|
||||
let data = &attestation.data;
|
||||
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();
|
||||
@@ -203,13 +217,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
)?;
|
||||
|
||||
let attesting_indices = get_attesting_indices_from_state(state, attestation)?;
|
||||
|
||||
let mut proposer_reward_numerator = 0;
|
||||
for index in attesting_indices {
|
||||
let index = index as usize;
|
||||
for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {
|
||||
let epoch_participation =
|
||||
state.get_epoch_participation_mut(data.target.epoch)?;
|
||||
let epoch_participation = if data.target.epoch == state.current_epoch() {
|
||||
&mut current_epoch_participation
|
||||
} else {
|
||||
&mut previous_epoch_participation
|
||||
};
|
||||
|
||||
let validator_participation = epoch_participation
|
||||
.get_mut(index)
|
||||
.ok_or(BeaconStateError::ParticipationOutOfBounds(index))?;
|
||||
|
||||
@@ -72,8 +72,8 @@ use crate::{
|
||||
};
|
||||
use eth2::types::{EventKind, SseBlobSidecar, SseBlock, SseExtendedPayloadAttributes, SyncDuty};
|
||||
use execution_layer::{
|
||||
BlockProposalContents, BuilderParams, ChainHealth, ExecutionLayer, FailedCondition,
|
||||
PayloadAttributes, PayloadStatus,
|
||||
BlockProposalContents, BlockProposalContentsType, BuilderParams, ChainHealth, ExecutionLayer,
|
||||
FailedCondition, PayloadAttributes, PayloadStatus,
|
||||
};
|
||||
use fork_choice::{
|
||||
AttestationFromBlock, ExecutionStatus, ForkChoice, ForkchoiceUpdateParameters,
|
||||
@@ -120,6 +120,7 @@ use tokio_stream::Stream;
|
||||
use tree_hash::TreeHash;
|
||||
use types::beacon_state::CloneConfig;
|
||||
use types::blob_sidecar::{BlobSidecarList, FixedBlobSidecarList};
|
||||
use types::payload::BlockProductionVersion;
|
||||
use types::sidecar::BlobItems;
|
||||
use types::*;
|
||||
|
||||
@@ -320,8 +321,7 @@ pub trait BeaconChainTypes: Send + Sync + 'static {
|
||||
type EthSpec: types::EthSpec;
|
||||
}
|
||||
|
||||
/// Used internally to split block production into discrete functions.
|
||||
struct PartialBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E>> {
|
||||
struct PartialBeaconBlock<E: EthSpec> {
|
||||
state: BeaconState<E>,
|
||||
slot: Slot,
|
||||
proposer_index: u64,
|
||||
@@ -335,7 +335,7 @@ struct PartialBeaconBlock<E: EthSpec, Payload: AbstractExecPayload<E>> {
|
||||
deposits: Vec<Deposit>,
|
||||
voluntary_exits: Vec<SignedVoluntaryExit>,
|
||||
sync_aggregate: Option<SyncAggregate<E>>,
|
||||
prepare_payload_handle: Option<PreparePayloadHandle<E, Payload>>,
|
||||
prepare_payload_handle: Option<PreparePayloadHandle<E>>,
|
||||
bls_to_execution_changes: Vec<SignedBlsToExecutionChange>,
|
||||
}
|
||||
|
||||
@@ -484,11 +484,18 @@ pub struct BeaconChain<T: BeaconChainTypes> {
|
||||
pub kzg: Option<Arc<Kzg>>,
|
||||
}
|
||||
|
||||
type BeaconBlockAndState<T, Payload> = (
|
||||
BeaconBlock<T, Payload>,
|
||||
BeaconState<T>,
|
||||
Option<SidecarList<T, <Payload as AbstractExecPayload<T>>::Sidecar>>,
|
||||
);
|
||||
pub enum BeaconBlockResponseType<T: EthSpec> {
|
||||
Full(BeaconBlockResponse<T, FullPayload<T>>),
|
||||
Blinded(BeaconBlockResponse<T, BlindedPayload<T>>),
|
||||
}
|
||||
|
||||
pub struct BeaconBlockResponse<T: EthSpec, Payload: AbstractExecPayload<T>> {
|
||||
pub block: BeaconBlock<T, Payload>,
|
||||
pub state: BeaconState<T>,
|
||||
pub maybe_side_car: Option<SidecarList<T, <Payload as AbstractExecPayload<T>>::Sidecar>>,
|
||||
pub execution_payload_value: Option<Uint256>,
|
||||
pub consensus_block_value: Option<u64>,
|
||||
}
|
||||
|
||||
impl FinalizationAndCanonicity {
|
||||
pub fn is_finalized(self) -> bool {
|
||||
@@ -3949,38 +3956,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Produce a new block at the given `slot`.
|
||||
///
|
||||
/// The produced block will not be inherently valid, it must be signed by a block producer.
|
||||
/// Block signing is out of the scope of this function and should be done by a separate program.
|
||||
pub async fn produce_block<Payload: AbstractExecPayload<T::EthSpec> + 'static>(
|
||||
self: &Arc<Self>,
|
||||
randao_reveal: Signature,
|
||||
slot: Slot,
|
||||
validator_graffiti: Option<Graffiti>,
|
||||
) -> Result<BeaconBlockAndState<T::EthSpec, Payload>, BlockProductionError> {
|
||||
self.produce_block_with_verification(
|
||||
randao_reveal,
|
||||
slot,
|
||||
validator_graffiti,
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Same as `produce_block` but allowing for configuration of RANDAO-verification.
|
||||
pub async fn produce_block_with_verification<
|
||||
Payload: AbstractExecPayload<T::EthSpec> + 'static,
|
||||
>(
|
||||
pub async fn produce_block_with_verification(
|
||||
self: &Arc<Self>,
|
||||
randao_reveal: Signature,
|
||||
slot: Slot,
|
||||
validator_graffiti: Option<Graffiti>,
|
||||
verification: ProduceBlockVerification,
|
||||
) -> Result<BeaconBlockAndState<T::EthSpec, Payload>, BlockProductionError> {
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<BeaconBlockResponseType<T::EthSpec>, BlockProductionError> {
|
||||
metrics::inc_counter(&metrics::BLOCK_PRODUCTION_REQUESTS);
|
||||
let _complete_timer = metrics::start_timer(&metrics::BLOCK_PRODUCTION_TIMES);
|
||||
|
||||
// Part 1/2 (blocking)
|
||||
//
|
||||
// Load the parent state from disk.
|
||||
@@ -3998,13 +3983,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// Part 2/2 (async, with some blocking components)
|
||||
//
|
||||
// Produce the block upon the state
|
||||
self.produce_block_on_state::<Payload>(
|
||||
self.produce_block_on_state(
|
||||
state,
|
||||
state_root_opt,
|
||||
slot,
|
||||
randao_reveal,
|
||||
validator_graffiti,
|
||||
verification,
|
||||
block_production_version,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -4568,7 +4554,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// The provided `state_root_opt` should only ever be set to `Some` if the contained value is
|
||||
/// equal to the root of `state`. Providing this value will serve as an optimization to avoid
|
||||
/// performing a tree hash in some scenarios.
|
||||
pub async fn produce_block_on_state<Payload: AbstractExecPayload<T::EthSpec> + 'static>(
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn produce_block_on_state(
|
||||
self: &Arc<Self>,
|
||||
state: BeaconState<T::EthSpec>,
|
||||
state_root_opt: Option<Hash256>,
|
||||
@@ -4576,7 +4563,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
randao_reveal: Signature,
|
||||
validator_graffiti: Option<Graffiti>,
|
||||
verification: ProduceBlockVerification,
|
||||
) -> Result<BeaconBlockAndState<T::EthSpec, Payload>, BlockProductionError> {
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<BeaconBlockResponseType<T::EthSpec>, BlockProductionError> {
|
||||
// Part 1/3 (blocking)
|
||||
//
|
||||
// Perform the state advance and block-packing functions.
|
||||
@@ -4591,6 +4579,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
produce_at_slot,
|
||||
randao_reveal,
|
||||
validator_graffiti,
|
||||
block_production_version,
|
||||
)
|
||||
},
|
||||
"produce_partial_beacon_block",
|
||||
@@ -4598,50 +4587,96 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)??;
|
||||
|
||||
// Part 2/3 (async)
|
||||
//
|
||||
// Wait for the execution layer to return an execution payload (if one is required).
|
||||
let prepare_payload_handle = partial_beacon_block.prepare_payload_handle.take();
|
||||
let block_contents = if let Some(prepare_payload_handle) = prepare_payload_handle {
|
||||
Some(
|
||||
prepare_payload_handle
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)?
|
||||
.ok_or(BlockProductionError::ShuttingDown)??,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let block_contents_type_option =
|
||||
if let Some(prepare_payload_handle) = prepare_payload_handle {
|
||||
Some(
|
||||
prepare_payload_handle
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)?
|
||||
.ok_or(BlockProductionError::ShuttingDown)??,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Part 3/3 (blocking)
|
||||
//
|
||||
// Perform the final steps of combining all the parts and computing the state root.
|
||||
let chain = self.clone();
|
||||
self.task_executor
|
||||
.spawn_blocking_handle(
|
||||
move || {
|
||||
chain.complete_partial_beacon_block(
|
||||
partial_beacon_block,
|
||||
block_contents,
|
||||
verification,
|
||||
)
|
||||
},
|
||||
"complete_partial_beacon_block",
|
||||
)
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)?
|
||||
if let Some(block_contents_type) = block_contents_type_option {
|
||||
match block_contents_type {
|
||||
BlockProposalContentsType::Full(block_contents) => {
|
||||
let chain = self.clone();
|
||||
let beacon_block_response = self
|
||||
.task_executor
|
||||
.spawn_blocking_handle(
|
||||
move || {
|
||||
chain.complete_partial_beacon_block(
|
||||
partial_beacon_block,
|
||||
Some(block_contents),
|
||||
verification,
|
||||
)
|
||||
},
|
||||
"complete_partial_beacon_block",
|
||||
)
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)??;
|
||||
|
||||
Ok(BeaconBlockResponseType::Full(beacon_block_response))
|
||||
}
|
||||
BlockProposalContentsType::Blinded(block_contents) => {
|
||||
let chain = self.clone();
|
||||
let beacon_block_response = self
|
||||
.task_executor
|
||||
.spawn_blocking_handle(
|
||||
move || {
|
||||
chain.complete_partial_beacon_block(
|
||||
partial_beacon_block,
|
||||
Some(block_contents),
|
||||
verification,
|
||||
)
|
||||
},
|
||||
"complete_partial_beacon_block",
|
||||
)
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)??;
|
||||
|
||||
Ok(BeaconBlockResponseType::Blinded(beacon_block_response))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let chain = self.clone();
|
||||
let beacon_block_response = self
|
||||
.task_executor
|
||||
.spawn_blocking_handle(
|
||||
move || {
|
||||
chain.complete_partial_beacon_block(
|
||||
partial_beacon_block,
|
||||
None,
|
||||
verification,
|
||||
)
|
||||
},
|
||||
"complete_partial_beacon_block",
|
||||
)
|
||||
.ok_or(BlockProductionError::ShuttingDown)?
|
||||
.await
|
||||
.map_err(BlockProductionError::TokioJoin)??;
|
||||
|
||||
Ok(BeaconBlockResponseType::Full(beacon_block_response))
|
||||
}
|
||||
}
|
||||
|
||||
fn produce_partial_beacon_block<Payload: AbstractExecPayload<T::EthSpec> + 'static>(
|
||||
fn produce_partial_beacon_block(
|
||||
self: &Arc<Self>,
|
||||
mut state: BeaconState<T::EthSpec>,
|
||||
state_root_opt: Option<Hash256>,
|
||||
produce_at_slot: Slot,
|
||||
randao_reveal: Signature,
|
||||
validator_graffiti: Option<Graffiti>,
|
||||
) -> Result<PartialBeaconBlock<T::EthSpec, Payload>, BlockProductionError> {
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<PartialBeaconBlock<T::EthSpec>, BlockProductionError> {
|
||||
let eth1_chain = self
|
||||
.eth1_chain
|
||||
.as_ref()
|
||||
@@ -4701,6 +4736,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
parent_root,
|
||||
proposer_index,
|
||||
builder_params,
|
||||
block_production_version,
|
||||
)?;
|
||||
Some(prepare_payload_handle)
|
||||
}
|
||||
@@ -4710,6 +4746,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.op_pool.get_slashings_and_exits(&state, &self.spec);
|
||||
|
||||
let eth1_data = eth1_chain.eth1_data_for_block_production(&state, &self.spec)?;
|
||||
|
||||
let deposits = eth1_chain.deposits_for_block_inclusion(&state, ð1_data, &self.spec)?;
|
||||
|
||||
let bls_to_execution_changes = self
|
||||
@@ -4880,10 +4917,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
fn complete_partial_beacon_block<Payload: AbstractExecPayload<T::EthSpec>>(
|
||||
&self,
|
||||
partial_beacon_block: PartialBeaconBlock<T::EthSpec, Payload>,
|
||||
partial_beacon_block: PartialBeaconBlock<T::EthSpec>,
|
||||
block_contents: Option<BlockProposalContents<T::EthSpec, Payload>>,
|
||||
verification: ProduceBlockVerification,
|
||||
) -> Result<BeaconBlockAndState<T::EthSpec, Payload>, BlockProductionError> {
|
||||
) -> Result<BeaconBlockResponse<T::EthSpec, Payload>, BlockProductionError> {
|
||||
let PartialBeaconBlock {
|
||||
mut state,
|
||||
slot,
|
||||
@@ -4905,7 +4942,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
bls_to_execution_changes,
|
||||
} = partial_beacon_block;
|
||||
|
||||
let (inner_block, blobs_opt, proofs_opt) = match &state {
|
||||
let (inner_block, blobs_opt, proofs_opt, execution_payload_value) = match &state {
|
||||
BeaconState::Base(_) => (
|
||||
BeaconBlock::Base(BeaconBlockBase {
|
||||
slot,
|
||||
@@ -4926,6 +4963,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
Uint256::zero(),
|
||||
),
|
||||
BeaconState::Altair(_) => (
|
||||
BeaconBlock::Altair(BeaconBlockAltair {
|
||||
@@ -4949,11 +4987,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
Uint256::zero(),
|
||||
),
|
||||
BeaconState::Merge(_) => {
|
||||
let (payload, _, _, _) = block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
let block_proposal_contents =
|
||||
block_contents.ok_or(BlockProductionError::MissingExecutionPayload)?;
|
||||
let execution_payload_value = block_proposal_contents.block_value().to_owned();
|
||||
(
|
||||
BeaconBlock::Merge(BeaconBlockMerge {
|
||||
slot,
|
||||
@@ -4971,19 +5010,22 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
.ok_or(BlockProductionError::MissingSyncAggregate)?,
|
||||
execution_payload: payload
|
||||
execution_payload: block_proposal_contents
|
||||
.to_payload()
|
||||
.try_into()
|
||||
.map_err(|_| BlockProductionError::InvalidPayloadFork)?,
|
||||
},
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
execution_payload_value,
|
||||
)
|
||||
}
|
||||
BeaconState::Capella(_) => {
|
||||
let (payload, _, _, _) = block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
let block_proposal_contents =
|
||||
block_contents.ok_or(BlockProductionError::MissingExecutionPayload)?;
|
||||
let execution_payload_value = block_proposal_contents.block_value().to_owned();
|
||||
|
||||
(
|
||||
BeaconBlock::Capella(BeaconBlockCapella {
|
||||
slot,
|
||||
@@ -5001,7 +5043,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
.ok_or(BlockProductionError::MissingSyncAggregate)?,
|
||||
execution_payload: payload
|
||||
execution_payload: block_proposal_contents
|
||||
.to_payload()
|
||||
.try_into()
|
||||
.map_err(|_| BlockProductionError::InvalidPayloadFork)?,
|
||||
bls_to_execution_changes: bls_to_execution_changes.into(),
|
||||
@@ -5009,12 +5052,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}),
|
||||
None,
|
||||
None,
|
||||
execution_payload_value,
|
||||
)
|
||||
}
|
||||
BeaconState::Deneb(_) => {
|
||||
let (payload, kzg_commitments, blobs, proofs) = block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
let (payload, kzg_commitments, blobs, proofs, execution_payload_value) =
|
||||
block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
|
||||
(
|
||||
BeaconBlock::Deneb(BeaconBlockDeneb {
|
||||
slot,
|
||||
@@ -5042,6 +5088,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}),
|
||||
blobs,
|
||||
proofs,
|
||||
execution_payload_value,
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -5057,7 +5104,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.log,
|
||||
"Produced block on state";
|
||||
"block_size" => block_size,
|
||||
"slot" => block.slot(),
|
||||
);
|
||||
|
||||
metrics::observe(&metrics::BLOCK_SIZE, block_size as f64);
|
||||
@@ -5075,6 +5121,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// Use a context without block root or proposer index so that both are checked.
|
||||
let mut ctxt = ConsensusContext::new(block.slot());
|
||||
|
||||
let consensus_block_value = self
|
||||
.compute_beacon_block_reward(block.message(), Hash256::zero(), &mut state)
|
||||
.map(|reward| reward.total)
|
||||
.unwrap_or(0);
|
||||
|
||||
per_block_processing(
|
||||
&mut state,
|
||||
&block,
|
||||
@@ -5154,7 +5205,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
"slot" => block.slot()
|
||||
);
|
||||
|
||||
Ok((block, state, maybe_sidecar_list))
|
||||
Ok(BeaconBlockResponse {
|
||||
block,
|
||||
state,
|
||||
maybe_side_car: maybe_sidecar_list,
|
||||
execution_payload_value: Some(execution_payload_value),
|
||||
consensus_block_value: Some(consensus_block_value),
|
||||
})
|
||||
}
|
||||
|
||||
/// This method must be called whenever an execution engine indicates that a payload is
|
||||
|
||||
@@ -13,7 +13,8 @@ use crate::{
|
||||
ExecutionPayloadError,
|
||||
};
|
||||
use execution_layer::{
|
||||
BlockProposalContents, BuilderParams, NewPayloadRequest, PayloadAttributes, PayloadStatus,
|
||||
BlockProposalContents, BlockProposalContentsType, BuilderParams, NewPayloadRequest,
|
||||
PayloadAttributes, PayloadStatus,
|
||||
};
|
||||
use fork_choice::{InvalidationOperation, PayloadVerificationStatus};
|
||||
use proto_array::{Block as ProtoBlock, ExecutionStatus};
|
||||
@@ -26,11 +27,11 @@ use state_processing::per_block_processing::{
|
||||
use std::sync::Arc;
|
||||
use tokio::task::JoinHandle;
|
||||
use tree_hash::TreeHash;
|
||||
use types::payload::BlockProductionVersion;
|
||||
use types::*;
|
||||
|
||||
pub type PreparePayloadResult<E, Payload> =
|
||||
Result<BlockProposalContents<E, Payload>, BlockProductionError>;
|
||||
pub type PreparePayloadHandle<E, Payload> = JoinHandle<Option<PreparePayloadResult<E, Payload>>>;
|
||||
pub type PreparePayloadResult<E> = Result<BlockProposalContentsType<E>, BlockProductionError>;
|
||||
pub type PreparePayloadHandle<E> = JoinHandle<Option<PreparePayloadResult<E>>>;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum AllowOptimisticImport {
|
||||
@@ -398,16 +399,14 @@ pub fn validate_execution_payload_for_gossip<T: BeaconChainTypes>(
|
||||
/// Equivalent to the `get_execution_payload` function in the Validator Guide:
|
||||
///
|
||||
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
|
||||
pub fn get_execution_payload<
|
||||
T: BeaconChainTypes,
|
||||
Payload: AbstractExecPayload<T::EthSpec> + 'static,
|
||||
>(
|
||||
pub fn get_execution_payload<T: BeaconChainTypes>(
|
||||
chain: Arc<BeaconChain<T>>,
|
||||
state: &BeaconState<T::EthSpec>,
|
||||
parent_block_root: Hash256,
|
||||
proposer_index: u64,
|
||||
builder_params: BuilderParams,
|
||||
) -> Result<PreparePayloadHandle<T::EthSpec, Payload>, BlockProductionError> {
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<PreparePayloadHandle<T::EthSpec>, BlockProductionError> {
|
||||
// Compute all required values from the `state` now to avoid needing to pass it into a spawned
|
||||
// task.
|
||||
let spec = &chain.spec;
|
||||
@@ -440,7 +439,7 @@ pub fn get_execution_payload<
|
||||
.clone()
|
||||
.spawn_handle(
|
||||
async move {
|
||||
prepare_execution_payload::<T, Payload>(
|
||||
prepare_execution_payload::<T>(
|
||||
&chain,
|
||||
is_merge_transition_complete,
|
||||
timestamp,
|
||||
@@ -450,6 +449,7 @@ pub fn get_execution_payload<
|
||||
builder_params,
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
block_production_version,
|
||||
)
|
||||
.await
|
||||
},
|
||||
@@ -475,7 +475,7 @@ pub fn get_execution_payload<
|
||||
///
|
||||
/// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn prepare_execution_payload<T, Payload>(
|
||||
pub async fn prepare_execution_payload<T>(
|
||||
chain: &Arc<BeaconChain<T>>,
|
||||
is_merge_transition_complete: bool,
|
||||
timestamp: u64,
|
||||
@@ -485,10 +485,10 @@ pub async fn prepare_execution_payload<T, Payload>(
|
||||
builder_params: BuilderParams,
|
||||
withdrawals: Option<Vec<Withdrawal>>,
|
||||
parent_beacon_block_root: Option<Hash256>,
|
||||
) -> Result<BlockProposalContents<T::EthSpec, Payload>, BlockProductionError>
|
||||
block_production_version: BlockProductionVersion,
|
||||
) -> Result<BlockProposalContentsType<T::EthSpec>, BlockProductionError>
|
||||
where
|
||||
T: BeaconChainTypes,
|
||||
Payload: AbstractExecPayload<T::EthSpec>,
|
||||
{
|
||||
let current_epoch = builder_params.slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
let spec = &chain.spec;
|
||||
@@ -506,7 +506,12 @@ where
|
||||
if is_terminal_block_hash_set && !is_activation_epoch_reached {
|
||||
// Use the "empty" payload if there's a terminal block hash, but we haven't reached the
|
||||
// terminal block epoch yet.
|
||||
return BlockProposalContents::default_at_fork(fork).map_err(Into::into);
|
||||
return Ok(BlockProposalContentsType::Full(
|
||||
BlockProposalContents::Payload {
|
||||
payload: FullPayload::default_at_fork(fork)?,
|
||||
block_value: Uint256::zero(),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let terminal_pow_block_hash = execution_layer
|
||||
@@ -519,7 +524,12 @@ where
|
||||
} else {
|
||||
// If the merge transition hasn't occurred yet and the EL hasn't found the terminal
|
||||
// block, return an "empty" payload.
|
||||
return BlockProposalContents::default_at_fork(fork).map_err(Into::into);
|
||||
return Ok(BlockProposalContentsType::Full(
|
||||
BlockProposalContents::Payload {
|
||||
payload: FullPayload::default_at_fork(fork)?,
|
||||
block_value: Uint256::zero(),
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
latest_execution_payload_header_block_hash
|
||||
@@ -558,13 +568,14 @@ where
|
||||
//
|
||||
// This future is not executed here, it's up to the caller to await it.
|
||||
let block_contents = execution_layer
|
||||
.get_payload::<Payload>(
|
||||
.get_payload(
|
||||
parent_hash,
|
||||
&payload_attributes,
|
||||
forkchoice_update_params,
|
||||
builder_params,
|
||||
fork,
|
||||
&chain.spec,
|
||||
block_production_version,
|
||||
)
|
||||
.await
|
||||
.map_err(BlockProductionError::GetPayloadFailed)?;
|
||||
|
||||
@@ -56,10 +56,10 @@ pub mod validator_monitor;
|
||||
pub mod validator_pubkey_cache;
|
||||
|
||||
pub use self::beacon_chain::{
|
||||
AttestationProcessingOutcome, AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes,
|
||||
BeaconStore, ChainSegmentResult, ForkChoiceError, OverrideForkchoiceUpdate,
|
||||
ProduceBlockVerification, StateSkipConfig, WhenSlotSkipped,
|
||||
INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
|
||||
AttestationProcessingOutcome, AvailabilityProcessingStatus, BeaconBlockResponse,
|
||||
BeaconBlockResponseType, BeaconChain, BeaconChainTypes, BeaconStore, ChainSegmentResult,
|
||||
ForkChoiceError, OverrideForkchoiceUpdate, ProduceBlockVerification, StateSkipConfig,
|
||||
WhenSlotSkipped, INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
|
||||
INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON,
|
||||
};
|
||||
pub use self::beacon_snapshot::BeaconSnapshot;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::block_verification_types::{AsBlock, RpcBlock};
|
||||
use crate::observed_operations::ObservationOutcome;
|
||||
pub use crate::persisted_beacon_chain::PersistedBeaconChain;
|
||||
use crate::BeaconBlockResponseType;
|
||||
pub use crate::{
|
||||
beacon_chain::{BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY, FORK_CHOICE_DB_KEY, OP_POOL_DB_KEY},
|
||||
migrate::MigratorConfig,
|
||||
@@ -60,6 +61,7 @@ use store::{config::StoreConfig, HotColdDB, ItemStore, LevelDB, MemoryStore};
|
||||
use task_executor::TaskExecutor;
|
||||
use task_executor::{test_utils::TestRuntime, ShutdownReason};
|
||||
use tree_hash::TreeHash;
|
||||
use types::payload::BlockProductionVersion;
|
||||
use types::sync_selection_proof::SyncSelectionProof;
|
||||
pub use types::test_utils::generate_deterministic_keypairs;
|
||||
use types::test_utils::TestRandom;
|
||||
@@ -878,7 +880,7 @@ where
|
||||
|
||||
let randao_reveal = self.sign_randao_reveal(&state, proposer_index, slot);
|
||||
|
||||
let (block, state, maybe_blob_sidecars) = self
|
||||
let BeaconBlockResponseType::Full(block_response) = self
|
||||
.chain
|
||||
.produce_block_on_state(
|
||||
state,
|
||||
@@ -887,14 +889,18 @@ where
|
||||
randao_reveal,
|
||||
Some(graffiti),
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
BlockProductionVersion::FullV2,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("Should always be a full payload response");
|
||||
};
|
||||
|
||||
let signed_block = block.sign(
|
||||
let signed_block = block_response.block.sign(
|
||||
&self.validator_keypairs[proposer_index].sk,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
&block_response.state.fork(),
|
||||
block_response.state.genesis_validators_root(),
|
||||
&self.spec,
|
||||
);
|
||||
|
||||
@@ -905,11 +911,13 @@ where
|
||||
| SignedBeaconBlock::Capella(_) => (signed_block, None),
|
||||
SignedBeaconBlock::Deneb(_) => (
|
||||
signed_block,
|
||||
maybe_blob_sidecars.map(|blobs| self.sign_blobs(blobs, &state, proposer_index)),
|
||||
block_response
|
||||
.maybe_side_car
|
||||
.map(|blobs| self.sign_blobs(blobs, &block_response.state, proposer_index)),
|
||||
),
|
||||
};
|
||||
|
||||
(block_contents, state)
|
||||
(block_contents, block_response.state)
|
||||
}
|
||||
|
||||
/// Useful for the `per_block_processing` tests. Creates a block, and returns the state after
|
||||
@@ -938,7 +946,7 @@ where
|
||||
|
||||
let pre_state = state.clone();
|
||||
|
||||
let (block, state, maybe_blob_sidecars) = self
|
||||
let BeaconBlockResponseType::Full(block_response) = self
|
||||
.chain
|
||||
.produce_block_on_state(
|
||||
state,
|
||||
@@ -947,14 +955,18 @@ where
|
||||
randao_reveal,
|
||||
Some(graffiti),
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
BlockProductionVersion::FullV2,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("Should always be a full payload response");
|
||||
};
|
||||
|
||||
let signed_block = block.sign(
|
||||
let signed_block = block_response.block.sign(
|
||||
&self.validator_keypairs[proposer_index].sk,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
&block_response.state.fork(),
|
||||
block_response.state.genesis_validators_root(),
|
||||
&self.spec,
|
||||
);
|
||||
|
||||
@@ -964,14 +976,14 @@ where
|
||||
| SignedBeaconBlock::Merge(_)
|
||||
| SignedBeaconBlock::Capella(_) => (signed_block, None),
|
||||
SignedBeaconBlock::Deneb(_) => {
|
||||
if let Some(blobs) = maybe_blob_sidecars {
|
||||
if let Some(blobs) = block_response.maybe_side_car {
|
||||
let signed_blobs: SignedSidecarList<E, BlobSidecar<E>> = Vec::from(blobs)
|
||||
.into_iter()
|
||||
.map(|blob| {
|
||||
blob.sign(
|
||||
&self.validator_keypairs[proposer_index].sk,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
&block_response.state.fork(),
|
||||
block_response.state.genesis_validators_root(),
|
||||
&self.spec,
|
||||
)
|
||||
})
|
||||
@@ -990,7 +1002,6 @@ where
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(block_contents, pre_state)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user