Set safe block hash to justified (#3347)

## Issue Addressed

Closes https://github.com/sigp/lighthouse/issues/3189.

## Proposed Changes

- Always supply the justified block hash as the `safe_block_hash` when calling `forkchoiceUpdated` on the execution engine.
- Refactor the `get_payload` routine to use the new `ForkchoiceUpdateParameters` struct rather than just the `finalized_block_hash`. I think this is a nice simplification and that the old way of computing the `finalized_block_hash` was unnecessary, but if anyone sees reason to keep that approach LMK.
This commit is contained in:
Michael Sproul
2022-07-21 05:45:37 +00:00
parent 6a0e9d4353
commit e32868458f
12 changed files with 156 additions and 96 deletions

View File

@@ -3256,14 +3256,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let prepare_payload_handle = match &state {
BeaconState::Base(_) | BeaconState::Altair(_) => None,
BeaconState::Merge(_) => {
let finalized_checkpoint = self.canonical_head.cached_head().finalized_checkpoint();
let prepare_payload_handle = get_execution_payload(
self.clone(),
&state,
finalized_checkpoint,
proposer_index,
pubkey_opt,
)?;
let prepare_payload_handle =
get_execution_payload(self.clone(), &state, proposer_index, pubkey_opt)?;
Some(prepare_payload_handle)
}
};
@@ -3890,11 +3884,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// `execution_engine_forkchoice_lock` apart from the one here.
let forkchoice_lock = execution_layer.execution_engine_forkchoice_lock().await;
let (head_block_root, head_hash, finalized_hash) = if let Some(head_hash) = params.head_hash
let (head_block_root, head_hash, justified_hash, finalized_hash) = if let Some(head_hash) =
params.head_hash
{
(
params.head_root,
head_hash,
params
.justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
params
.finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero),
@@ -3925,6 +3923,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
(
params.head_root,
terminal_pow_block_hash,
params
.justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
params
.finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero),
@@ -3942,7 +3943,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
};
let forkchoice_updated_response = execution_layer
.notify_forkchoice_updated(head_hash, finalized_hash, current_slot, head_block_root)
.notify_forkchoice_updated(
head_hash,
justified_hash,
finalized_hash,
current_slot,
head_block_root,
)
.await
.map_err(Error::ExecutionForkChoiceUpdateFailed);

View File

@@ -99,6 +99,8 @@ pub struct CachedHead<E: EthSpec> {
/// The `execution_payload.block_hash` of the block at the head of the chain. Set to `None`
/// before Bellatrix.
head_hash: Option<ExecutionBlockHash>,
/// The `execution_payload.block_hash` of the justified block. Set to `None` before Bellatrix.
justified_hash: Option<ExecutionBlockHash>,
/// The `execution_payload.block_hash` of the finalized block. Set to `None` before Bellatrix.
finalized_hash: Option<ExecutionBlockHash>,
}
@@ -183,6 +185,7 @@ impl<E: EthSpec> CachedHead<E> {
ForkchoiceUpdateParameters {
head_root: self.snapshot.beacon_block_root,
head_hash: self.head_hash,
justified_hash: self.justified_hash,
finalized_hash: self.finalized_hash,
}
}
@@ -224,6 +227,7 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
justified_checkpoint: fork_choice_view.justified_checkpoint,
finalized_checkpoint: fork_choice_view.finalized_checkpoint,
head_hash: forkchoice_update_params.head_hash,
justified_hash: forkchoice_update_params.justified_hash,
finalized_hash: forkchoice_update_params.finalized_hash,
};
@@ -272,6 +276,7 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
justified_checkpoint: fork_choice_view.justified_checkpoint,
finalized_checkpoint: fork_choice_view.finalized_checkpoint,
head_hash: forkchoice_update_params.head_hash,
justified_hash: forkchoice_update_params.justified_hash,
finalized_hash: forkchoice_update_params.finalized_hash,
};
@@ -612,6 +617,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
justified_checkpoint: new_view.justified_checkpoint,
finalized_checkpoint: new_view.finalized_checkpoint,
head_hash: new_forkchoice_update_parameters.head_hash,
justified_hash: new_forkchoice_update_parameters.justified_hash,
finalized_hash: new_forkchoice_update_parameters.finalized_hash,
};
@@ -638,6 +644,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
justified_checkpoint: new_view.justified_checkpoint,
finalized_checkpoint: new_view.finalized_checkpoint,
head_hash: new_forkchoice_update_parameters.head_hash,
justified_hash: new_forkchoice_update_parameters.justified_hash,
finalized_hash: new_forkchoice_update_parameters.finalized_hash,
};

View File

@@ -302,7 +302,6 @@ pub fn get_execution_payload<
>(
chain: Arc<BeaconChain<T>>,
state: &BeaconState<T::EthSpec>,
finalized_checkpoint: Checkpoint,
proposer_index: u64,
pubkey: Option<PublicKeyBytes>,
) -> Result<PreparePayloadHandle<Payload>, BlockProductionError> {
@@ -330,7 +329,6 @@ pub fn get_execution_payload<
is_merge_transition_complete,
timestamp,
random,
finalized_checkpoint,
proposer_index,
pubkey,
latest_execution_payload_header_block_hash,
@@ -365,7 +363,6 @@ pub async fn prepare_execution_payload<T, Payload>(
is_merge_transition_complete: bool,
timestamp: u64,
random: Hash256,
finalized_checkpoint: Checkpoint,
proposer_index: u64,
pubkey: Option<PublicKeyBytes>,
latest_execution_payload_header_block_hash: ExecutionBlockHash,
@@ -408,44 +405,24 @@ where
latest_execution_payload_header_block_hash
};
// Try to obtain the finalized proto block from fork choice.
// Try to obtain the fork choice update parameters from the cached head.
//
// Use a blocking task to interact with the `fork_choice` lock otherwise we risk blocking the
// Use a blocking task to interact with the `canonical_head` lock otherwise we risk blocking the
// core `tokio` executor.
let inner_chain = chain.clone();
let finalized_proto_block = chain
let forkchoice_update_params = chain
.spawn_blocking_handle(
move || {
inner_chain
.canonical_head
.fork_choice_read_lock()
.get_block(&finalized_checkpoint.root)
.cached_head()
.forkchoice_update_parameters()
},
"prepare_execution_payload_finalized_hash",
"prepare_execution_payload_forkchoice_update_params",
)
.await
.map_err(BlockProductionError::BeaconChain)?;
// The finalized block hash is not included in the specification, however we provide this
// parameter so that the execution layer can produce a payload id if one is not already known
// (e.g., due to a recent reorg).
let finalized_block_hash = if let Some(block) = finalized_proto_block {
block.execution_status.block_hash()
} else {
chain
.store
.get_blinded_block(&finalized_checkpoint.root)
.map_err(BlockProductionError::FailedToReadFinalizedBlock)?
.ok_or(BlockProductionError::MissingFinalizedBlock(
finalized_checkpoint.root,
))?
.message()
.body()
.execution_payload()
.ok()
.map(|ep| ep.block_hash())
};
// Note: the suggested_fee_recipient is stored in the `execution_layer`, it will add this parameter.
//
// This future is not executed here, it's up to the caller to await it.
@@ -454,10 +431,10 @@ where
parent_hash,
timestamp,
random,
finalized_block_hash.unwrap_or_else(ExecutionBlockHash::zero),
proposer_index,
pubkey,
slot,
forkchoice_update_params,
)
.await
.map_err(BlockProductionError::GetPayloadFailed)?;

View File

@@ -57,7 +57,7 @@ pub use block_verification::{BlockError, ExecutionPayloadError, GossipVerifiedBl
pub use canonical_head::{CachedHead, CanonicalHead, CanonicalHeadRwLock};
pub use eth1_chain::{Eth1Chain, Eth1ChainBackend};
pub use events::ServerSentEventHandler;
pub use fork_choice::ExecutionStatus;
pub use fork_choice::{ExecutionStatus, ForkchoiceUpdateParameters};
pub use metrics::scrape_for_metrics;
pub use parking_lot;
pub use slot_clock;