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

2
Cargo.lock generated
View File

@ -1932,6 +1932,7 @@ dependencies = [
"ethers-providers", "ethers-providers",
"execution_layer", "execution_layer",
"exit-future", "exit-future",
"fork_choice",
"futures", "futures",
"hex", "hex",
"reqwest", "reqwest",
@ -1958,6 +1959,7 @@ dependencies = [
"eth2_ssz_types", "eth2_ssz_types",
"ethers-core", "ethers-core",
"exit-future", "exit-future",
"fork_choice",
"futures", "futures",
"hex", "hex",
"jsonwebtoken", "jsonwebtoken",

View File

@ -3256,14 +3256,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let prepare_payload_handle = match &state { let prepare_payload_handle = match &state {
BeaconState::Base(_) | BeaconState::Altair(_) => None, BeaconState::Base(_) | BeaconState::Altair(_) => None,
BeaconState::Merge(_) => { BeaconState::Merge(_) => {
let finalized_checkpoint = self.canonical_head.cached_head().finalized_checkpoint(); let prepare_payload_handle =
let prepare_payload_handle = get_execution_payload( get_execution_payload(self.clone(), &state, proposer_index, pubkey_opt)?;
self.clone(),
&state,
finalized_checkpoint,
proposer_index,
pubkey_opt,
)?;
Some(prepare_payload_handle) Some(prepare_payload_handle)
} }
}; };
@ -3890,11 +3884,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// `execution_engine_forkchoice_lock` apart from the one here. // `execution_engine_forkchoice_lock` apart from the one here.
let forkchoice_lock = execution_layer.execution_engine_forkchoice_lock().await; 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, params.head_root,
head_hash, head_hash,
params
.justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
params params
.finalized_hash .finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero), .unwrap_or_else(ExecutionBlockHash::zero),
@ -3925,6 +3923,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
( (
params.head_root, params.head_root,
terminal_pow_block_hash, terminal_pow_block_hash,
params
.justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
params params
.finalized_hash .finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero), .unwrap_or_else(ExecutionBlockHash::zero),
@ -3942,7 +3943,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}; };
let forkchoice_updated_response = execution_layer 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 .await
.map_err(Error::ExecutionForkChoiceUpdateFailed); .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` /// The `execution_payload.block_hash` of the block at the head of the chain. Set to `None`
/// before Bellatrix. /// before Bellatrix.
head_hash: Option<ExecutionBlockHash>, 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. /// The `execution_payload.block_hash` of the finalized block. Set to `None` before Bellatrix.
finalized_hash: Option<ExecutionBlockHash>, finalized_hash: Option<ExecutionBlockHash>,
} }
@ -183,6 +185,7 @@ impl<E: EthSpec> CachedHead<E> {
ForkchoiceUpdateParameters { ForkchoiceUpdateParameters {
head_root: self.snapshot.beacon_block_root, head_root: self.snapshot.beacon_block_root,
head_hash: self.head_hash, head_hash: self.head_hash,
justified_hash: self.justified_hash,
finalized_hash: self.finalized_hash, finalized_hash: self.finalized_hash,
} }
} }
@ -224,6 +227,7 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
justified_checkpoint: fork_choice_view.justified_checkpoint, justified_checkpoint: fork_choice_view.justified_checkpoint,
finalized_checkpoint: fork_choice_view.finalized_checkpoint, finalized_checkpoint: fork_choice_view.finalized_checkpoint,
head_hash: forkchoice_update_params.head_hash, head_hash: forkchoice_update_params.head_hash,
justified_hash: forkchoice_update_params.justified_hash,
finalized_hash: forkchoice_update_params.finalized_hash, finalized_hash: forkchoice_update_params.finalized_hash,
}; };
@ -272,6 +276,7 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
justified_checkpoint: fork_choice_view.justified_checkpoint, justified_checkpoint: fork_choice_view.justified_checkpoint,
finalized_checkpoint: fork_choice_view.finalized_checkpoint, finalized_checkpoint: fork_choice_view.finalized_checkpoint,
head_hash: forkchoice_update_params.head_hash, head_hash: forkchoice_update_params.head_hash,
justified_hash: forkchoice_update_params.justified_hash,
finalized_hash: forkchoice_update_params.finalized_hash, finalized_hash: forkchoice_update_params.finalized_hash,
}; };
@ -612,6 +617,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
justified_checkpoint: new_view.justified_checkpoint, justified_checkpoint: new_view.justified_checkpoint,
finalized_checkpoint: new_view.finalized_checkpoint, finalized_checkpoint: new_view.finalized_checkpoint,
head_hash: new_forkchoice_update_parameters.head_hash, head_hash: new_forkchoice_update_parameters.head_hash,
justified_hash: new_forkchoice_update_parameters.justified_hash,
finalized_hash: new_forkchoice_update_parameters.finalized_hash, finalized_hash: new_forkchoice_update_parameters.finalized_hash,
}; };
@ -638,6 +644,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
justified_checkpoint: new_view.justified_checkpoint, justified_checkpoint: new_view.justified_checkpoint,
finalized_checkpoint: new_view.finalized_checkpoint, finalized_checkpoint: new_view.finalized_checkpoint,
head_hash: new_forkchoice_update_parameters.head_hash, head_hash: new_forkchoice_update_parameters.head_hash,
justified_hash: new_forkchoice_update_parameters.justified_hash,
finalized_hash: new_forkchoice_update_parameters.finalized_hash, finalized_hash: new_forkchoice_update_parameters.finalized_hash,
}; };

View File

@ -302,7 +302,6 @@ pub fn get_execution_payload<
>( >(
chain: Arc<BeaconChain<T>>, chain: Arc<BeaconChain<T>>,
state: &BeaconState<T::EthSpec>, state: &BeaconState<T::EthSpec>,
finalized_checkpoint: Checkpoint,
proposer_index: u64, proposer_index: u64,
pubkey: Option<PublicKeyBytes>, pubkey: Option<PublicKeyBytes>,
) -> Result<PreparePayloadHandle<Payload>, BlockProductionError> { ) -> Result<PreparePayloadHandle<Payload>, BlockProductionError> {
@ -330,7 +329,6 @@ pub fn get_execution_payload<
is_merge_transition_complete, is_merge_transition_complete,
timestamp, timestamp,
random, random,
finalized_checkpoint,
proposer_index, proposer_index,
pubkey, pubkey,
latest_execution_payload_header_block_hash, latest_execution_payload_header_block_hash,
@ -365,7 +363,6 @@ pub async fn prepare_execution_payload<T, Payload>(
is_merge_transition_complete: bool, is_merge_transition_complete: bool,
timestamp: u64, timestamp: u64,
random: Hash256, random: Hash256,
finalized_checkpoint: Checkpoint,
proposer_index: u64, proposer_index: u64,
pubkey: Option<PublicKeyBytes>, pubkey: Option<PublicKeyBytes>,
latest_execution_payload_header_block_hash: ExecutionBlockHash, latest_execution_payload_header_block_hash: ExecutionBlockHash,
@ -408,44 +405,24 @@ where
latest_execution_payload_header_block_hash 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. // core `tokio` executor.
let inner_chain = chain.clone(); let inner_chain = chain.clone();
let finalized_proto_block = chain let forkchoice_update_params = chain
.spawn_blocking_handle( .spawn_blocking_handle(
move || { move || {
inner_chain inner_chain
.canonical_head .canonical_head
.fork_choice_read_lock() .cached_head()
.get_block(&finalized_checkpoint.root) .forkchoice_update_parameters()
}, },
"prepare_execution_payload_finalized_hash", "prepare_execution_payload_forkchoice_update_params",
) )
.await .await
.map_err(BlockProductionError::BeaconChain)?; .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. // 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. // This future is not executed here, it's up to the caller to await it.
@ -454,10 +431,10 @@ where
parent_hash, parent_hash,
timestamp, timestamp,
random, random,
finalized_block_hash.unwrap_or_else(ExecutionBlockHash::zero),
proposer_index, proposer_index,
pubkey, pubkey,
slot, slot,
forkchoice_update_params,
) )
.await .await
.map_err(BlockProductionError::GetPayloadFailed)?; .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 canonical_head::{CachedHead, CanonicalHead, CanonicalHeadRwLock};
pub use eth1_chain::{Eth1Chain, Eth1ChainBackend}; pub use eth1_chain::{Eth1Chain, Eth1ChainBackend};
pub use events::ServerSentEventHandler; pub use events::ServerSentEventHandler;
pub use fork_choice::ExecutionStatus; pub use fork_choice::{ExecutionStatus, ForkchoiceUpdateParameters};
pub use metrics::scrape_for_metrics; pub use metrics::scrape_for_metrics;
pub use parking_lot; pub use parking_lot;
pub use slot_clock; pub use slot_clock;

View File

@ -39,3 +39,4 @@ lighthouse_metrics = { path = "../../common/lighthouse_metrics" }
lazy_static = "1.4.0" lazy_static = "1.4.0"
ethers-core = { git = "https://github.com/gakonst/ethers-rs", rev = "02ad93a1cfb7b62eb051c77c61dc4c0218428e4a" } ethers-core = { git = "https://github.com/gakonst/ethers-rs", rev = "02ad93a1cfb7b62eb051c77c61dc4c0218428e4a" }
builder_client = { path = "../builder_client" } builder_client = { path = "../builder_client" }
fork_choice = { path = "../../consensus/fork_choice" }

View File

@ -11,6 +11,7 @@ pub use engine_api::*;
pub use engine_api::{http, http::deposit_methods, http::HttpJsonRpc}; pub use engine_api::{http, http::deposit_methods, http::HttpJsonRpc};
pub use engines::ForkChoiceState; pub use engines::ForkChoiceState;
use engines::{Engine, EngineError}; use engines::{Engine, EngineError};
use fork_choice::ForkchoiceUpdateParameters;
use lru::LruCache; use lru::LruCache;
use payload_status::process_payload_status; use payload_status::process_payload_status;
pub use payload_status::PayloadStatus; pub use payload_status::PayloadStatus;
@ -502,10 +503,10 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash: ExecutionBlockHash, parent_hash: ExecutionBlockHash,
timestamp: u64, timestamp: u64,
prev_randao: Hash256, prev_randao: Hash256,
finalized_block_hash: ExecutionBlockHash,
proposer_index: u64, proposer_index: u64,
pubkey: Option<PublicKeyBytes>, pubkey: Option<PublicKeyBytes>,
slot: Slot, slot: Slot,
forkchoice_update_params: ForkchoiceUpdateParameters,
) -> Result<Payload, Error> { ) -> Result<Payload, Error> {
let suggested_fee_recipient = self.get_suggested_fee_recipient(proposer_index).await; let suggested_fee_recipient = self.get_suggested_fee_recipient(proposer_index).await;
@ -519,10 +520,10 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
suggested_fee_recipient, suggested_fee_recipient,
pubkey, pubkey,
slot, slot,
forkchoice_update_params,
) )
.await .await
} }
@ -535,8 +536,8 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
suggested_fee_recipient, suggested_fee_recipient,
forkchoice_update_params,
) )
.await .await
} }
@ -549,17 +550,22 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash: ExecutionBlockHash, parent_hash: ExecutionBlockHash,
timestamp: u64, timestamp: u64,
prev_randao: Hash256, prev_randao: Hash256,
finalized_block_hash: ExecutionBlockHash,
suggested_fee_recipient: Address, suggested_fee_recipient: Address,
pubkey_opt: Option<PublicKeyBytes>, pubkey_opt: Option<PublicKeyBytes>,
slot: Slot, slot: Slot,
forkchoice_update_params: ForkchoiceUpdateParameters,
) -> Result<Payload, Error> { ) -> Result<Payload, Error> {
//FIXME(sean) fallback logic included in PR #3134 //FIXME(sean) fallback logic included in PR #3134
// Don't attempt to outsource payload construction until after the merge transition has been // Don't attempt to outsource payload construction until after the merge transition has been
// finalized. We want to be conservative with payload construction until then. // finalized. We want to be conservative with payload construction until then.
if let (Some(builder), Some(pubkey)) = (self.builder(), pubkey_opt) { if let (Some(builder), Some(pubkey)) = (self.builder(), pubkey_opt) {
if finalized_block_hash != ExecutionBlockHash::zero() { if forkchoice_update_params
.finalized_hash
.map_or(false, |finalized_block_hash| {
finalized_block_hash != ExecutionBlockHash::zero()
})
{
info!( info!(
self.log(), self.log(),
"Requesting blinded header from connected builder"; "Requesting blinded header from connected builder";
@ -578,8 +584,8 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
suggested_fee_recipient, suggested_fee_recipient,
forkchoice_update_params,
) )
.await .await
} }
@ -590,15 +596,15 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash: ExecutionBlockHash, parent_hash: ExecutionBlockHash,
timestamp: u64, timestamp: u64,
prev_randao: Hash256, prev_randao: Hash256,
finalized_block_hash: ExecutionBlockHash,
suggested_fee_recipient: Address, suggested_fee_recipient: Address,
forkchoice_update_params: ForkchoiceUpdateParameters,
) -> Result<Payload, Error> { ) -> Result<Payload, Error> {
self.get_full_payload_with( self.get_full_payload_with(
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
suggested_fee_recipient, suggested_fee_recipient,
forkchoice_update_params,
noop, noop,
) )
.await .await
@ -609,8 +615,8 @@ impl<T: EthSpec> ExecutionLayer<T> {
parent_hash: ExecutionBlockHash, parent_hash: ExecutionBlockHash,
timestamp: u64, timestamp: u64,
prev_randao: Hash256, prev_randao: Hash256,
finalized_block_hash: ExecutionBlockHash,
suggested_fee_recipient: Address, suggested_fee_recipient: Address,
forkchoice_update_params: ForkchoiceUpdateParameters,
f: fn(&ExecutionLayer<T>, &ExecutionPayload<T>) -> Option<ExecutionPayload<T>>, f: fn(&ExecutionLayer<T>, &ExecutionPayload<T>) -> Option<ExecutionPayload<T>>,
) -> Result<Payload, Error> { ) -> Result<Payload, Error> {
debug!( debug!(
@ -634,20 +640,20 @@ impl<T: EthSpec> ExecutionLayer<T> {
); );
id id
} else { } else {
// The payload id has *not* been cached for this engine. Trigger an artificial // The payload id has *not* been cached. Trigger an artificial
// fork choice update to retrieve a payload ID. // fork choice update to retrieve a payload ID.
//
// TODO(merge): a better algorithm might try to favour a node that already had a
// cached payload id, since a payload that has had more time to produce is
// likely to be more profitable.
metrics::inc_counter_vec( metrics::inc_counter_vec(
&metrics::EXECUTION_LAYER_PRE_PREPARED_PAYLOAD_ID, &metrics::EXECUTION_LAYER_PRE_PREPARED_PAYLOAD_ID,
&[metrics::MISS], &[metrics::MISS],
); );
let fork_choice_state = ForkChoiceState { let fork_choice_state = ForkChoiceState {
head_block_hash: parent_hash, head_block_hash: parent_hash,
safe_block_hash: parent_hash, safe_block_hash: forkchoice_update_params
finalized_block_hash, .justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
finalized_block_hash: forkchoice_update_params
.finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero),
}; };
let payload_attributes = PayloadAttributes { let payload_attributes = PayloadAttributes {
timestamp, timestamp,
@ -655,29 +661,28 @@ impl<T: EthSpec> ExecutionLayer<T> {
suggested_fee_recipient, suggested_fee_recipient,
}; };
let response = engine let response = engine
.notify_forkchoice_updated( .notify_forkchoice_updated(
fork_choice_state, fork_choice_state,
Some(payload_attributes), Some(payload_attributes),
self.log(), self.log(),
) )
.await?; .await?;
match response.payload_id { match response.payload_id {
Some(payload_id) => payload_id, Some(payload_id) => payload_id,
None => { None => {
error!( error!(
self.log(), self.log(),
"Exec engine unable to produce payload"; "Exec engine unable to produce payload";
"msg" => "No payload ID, the engine is likely syncing. \ "msg" => "No payload ID, the engine is likely syncing. \
This has the potential to cause a missed block \ This has the potential to cause a missed block proposal.",
proposal.", "status" => ?response.payload_status
"status" => ?response.payload_status );
); return Err(ApiError::PayloadIdUnavailable);
return Err(ApiError::PayloadIdUnavailable); }
} }
} };
};
engine engine
.api .api
@ -685,7 +690,11 @@ impl<T: EthSpec> ExecutionLayer<T> {
.await .await
.map(|full_payload| { .map(|full_payload| {
if f(self, &full_payload).is_some() { if f(self, &full_payload).is_some() {
warn!(self.log(), "Duplicate payload cached, this might indicate redundant proposal attempts."); warn!(
self.log(),
"Duplicate payload cached, this might indicate redundant proposal \
attempts."
);
} }
full_payload.into() full_payload.into()
}) })
@ -809,6 +818,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
pub async fn notify_forkchoice_updated( pub async fn notify_forkchoice_updated(
&self, &self,
head_block_hash: ExecutionBlockHash, head_block_hash: ExecutionBlockHash,
justified_block_hash: ExecutionBlockHash,
finalized_block_hash: ExecutionBlockHash, finalized_block_hash: ExecutionBlockHash,
current_slot: Slot, current_slot: Slot,
head_block_root: Hash256, head_block_root: Hash256,
@ -822,6 +832,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
self.log(), self.log(),
"Issuing engine_forkchoiceUpdated"; "Issuing engine_forkchoiceUpdated";
"finalized_block_hash" => ?finalized_block_hash, "finalized_block_hash" => ?finalized_block_hash,
"justified_block_hash" => ?justified_block_hash,
"head_block_hash" => ?head_block_hash, "head_block_hash" => ?head_block_hash,
); );
@ -848,11 +859,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
} }
} }
// see https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
// for now, we must set safe_block_hash = head_block_hash
let forkchoice_state = ForkChoiceState { let forkchoice_state = ForkChoiceState {
head_block_hash, head_block_hash,
safe_block_hash: head_block_hash, safe_block_hash: justified_block_hash,
finalized_block_hash, finalized_block_hash,
}; };

View File

@ -335,7 +335,9 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
} }
let unknown_head_block_hash = !self.blocks.contains_key(&forkchoice_state.head_block_hash); let unknown_head_block_hash = !self.blocks.contains_key(&forkchoice_state.head_block_hash);
let unknown_safe_block_hash = !self.blocks.contains_key(&forkchoice_state.safe_block_hash); let unknown_safe_block_hash = forkchoice_state.safe_block_hash
!= ExecutionBlockHash::zero()
&& !self.blocks.contains_key(&forkchoice_state.safe_block_hash);
let unknown_finalized_block_hash = forkchoice_state.finalized_block_hash let unknown_finalized_block_hash = forkchoice_state.finalized_block_hash
!= ExecutionBlockHash::zero() != ExecutionBlockHash::zero()
&& !self && !self

View File

@ -88,11 +88,16 @@ impl<T: EthSpec> MockExecutionLayer<T> {
let block_number = latest_execution_block.block_number() + 1; let block_number = latest_execution_block.block_number() + 1;
let timestamp = block_number; let timestamp = block_number;
let prev_randao = Hash256::from_low_u64_be(block_number); let prev_randao = Hash256::from_low_u64_be(block_number);
let finalized_block_hash = parent_hash; let head_block_root = Hash256::repeat_byte(42);
let forkchoice_update_params = ForkchoiceUpdateParameters {
head_root: head_block_root,
head_hash: Some(parent_hash),
justified_hash: None,
finalized_hash: None,
};
// Insert a proposer to ensure the fork choice updated command works. // Insert a proposer to ensure the fork choice updated command works.
let slot = Slot::new(0); let slot = Slot::new(0);
let head_block_root = Hash256::repeat_byte(42);
let validator_index = 0; let validator_index = 0;
self.el self.el
.insert_proposer( .insert_proposer(
@ -111,6 +116,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
.notify_forkchoice_updated( .notify_forkchoice_updated(
parent_hash, parent_hash,
ExecutionBlockHash::zero(), ExecutionBlockHash::zero(),
ExecutionBlockHash::zero(),
slot, slot,
head_block_root, head_block_root,
) )
@ -124,10 +130,10 @@ impl<T: EthSpec> MockExecutionLayer<T> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
validator_index, validator_index,
None, None,
slot, slot,
forkchoice_update_params,
) )
.await .await
.unwrap() .unwrap()
@ -148,6 +154,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
.notify_forkchoice_updated( .notify_forkchoice_updated(
block_hash, block_hash,
ExecutionBlockHash::zero(), ExecutionBlockHash::zero(),
ExecutionBlockHash::zero(),
slot, slot,
head_block_root, head_block_root,
) )

View File

@ -259,6 +259,7 @@ pub enum AttestationFromBlock {
pub struct ForkchoiceUpdateParameters { pub struct ForkchoiceUpdateParameters {
pub head_root: Hash256, pub head_root: Hash256,
pub head_hash: Option<ExecutionBlockHash>, pub head_hash: Option<ExecutionBlockHash>,
pub justified_hash: Option<ExecutionBlockHash>,
pub finalized_hash: Option<ExecutionBlockHash>, pub finalized_hash: Option<ExecutionBlockHash>,
} }
@ -372,6 +373,7 @@ where
// This will be updated during the next call to `Self::get_head`. // This will be updated during the next call to `Self::get_head`.
forkchoice_update_parameters: ForkchoiceUpdateParameters { forkchoice_update_parameters: ForkchoiceUpdateParameters {
head_hash: None, head_hash: None,
justified_hash: None,
finalized_hash: None, finalized_hash: None,
head_root: Hash256::zero(), head_root: Hash256::zero(),
}, },
@ -489,13 +491,18 @@ where
let head_hash = self let head_hash = self
.get_block(&head_root) .get_block(&head_root)
.and_then(|b| b.execution_status.block_hash()); .and_then(|b| b.execution_status.block_hash());
let justified_root = self.justified_checkpoint().root;
let finalized_root = self.finalized_checkpoint().root; let finalized_root = self.finalized_checkpoint().root;
let justified_hash = self
.get_block(&justified_root)
.and_then(|b| b.execution_status.block_hash());
let finalized_hash = self let finalized_hash = self
.get_block(&finalized_root) .get_block(&finalized_root)
.and_then(|b| b.execution_status.block_hash()); .and_then(|b| b.execution_status.block_hash());
self.forkchoice_update_parameters = ForkchoiceUpdateParameters { self.forkchoice_update_parameters = ForkchoiceUpdateParameters {
head_root, head_root,
head_hash, head_hash,
justified_hash,
finalized_hash, finalized_hash,
}; };
@ -1211,6 +1218,7 @@ where
// Will be updated in the following call to `Self::get_head`. // Will be updated in the following call to `Self::get_head`.
forkchoice_update_parameters: ForkchoiceUpdateParameters { forkchoice_update_parameters: ForkchoiceUpdateParameters {
head_hash: None, head_hash: None,
justified_hash: None,
finalized_hash: None, finalized_hash: None,
head_root: Hash256::zero(), head_root: Hash256::zero(),
}, },

View File

@ -20,3 +20,4 @@ ethers-providers = { git = "https://github.com/gakonst/ethers-rs", rev = "02ad93
deposit_contract = { path = "../../common/deposit_contract" } deposit_contract = { path = "../../common/deposit_contract" }
reqwest = { version = "0.11.0", features = ["json"] } reqwest = { version = "0.11.0", features = ["json"] }
hex = "0.4.2" hex = "0.4.2"
fork_choice = { path = "../../consensus/fork_choice" }

View File

@ -4,6 +4,7 @@ use crate::execution_engine::{
use crate::transactions::transactions; use crate::transactions::transactions;
use ethers_providers::Middleware; use ethers_providers::Middleware;
use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatus}; use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatus};
use fork_choice::ForkchoiceUpdateParameters;
use reqwest::{header::CONTENT_TYPE, Client}; use reqwest::{header::CONTENT_TYPE, Client};
use sensitive_url::SensitiveUrl; use sensitive_url::SensitiveUrl;
use serde_json::{json, Value}; use serde_json::{json, Value};
@ -254,7 +255,15 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let parent_hash = terminal_pow_block_hash; let parent_hash = terminal_pow_block_hash;
let timestamp = timestamp_now(); let timestamp = timestamp_now();
let prev_randao = Hash256::zero(); let prev_randao = Hash256::zero();
let head_root = Hash256::zero();
let justified_block_hash = ExecutionBlockHash::zero();
let finalized_block_hash = ExecutionBlockHash::zero(); let finalized_block_hash = ExecutionBlockHash::zero();
let forkchoice_update_params = ForkchoiceUpdateParameters {
head_root,
head_hash: Some(parent_hash),
justified_hash: Some(justified_block_hash),
finalized_hash: Some(finalized_block_hash),
};
let proposer_index = 0; let proposer_index = 0;
let prepared = self let prepared = self
@ -262,7 +271,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
.execution_layer .execution_layer
.insert_proposer( .insert_proposer(
Slot::new(1), // Insert proposer for the next slot Slot::new(1), // Insert proposer for the next slot
Hash256::zero(), head_root,
proposer_index, proposer_index,
PayloadAttributes { PayloadAttributes {
timestamp, timestamp,
@ -280,6 +289,7 @@ impl<E: GenericExecutionEngine> TestRig<E> {
.execution_layer .execution_layer
.notify_forkchoice_updated( .notify_forkchoice_updated(
parent_hash, parent_hash,
justified_block_hash,
finalized_block_hash, finalized_block_hash,
Slot::new(0), Slot::new(0),
Hash256::zero(), Hash256::zero(),
@ -302,10 +312,10 @@ impl<E: GenericExecutionEngine> TestRig<E> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
proposer_index, proposer_index,
None, None,
Slot::new(0), Slot::new(0),
forkchoice_update_params,
) )
.await .await
.unwrap() .unwrap()
@ -326,7 +336,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let status = self let status = self
.ee_a .ee_a
.execution_layer .execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root) .notify_forkchoice_updated(
head_block_hash,
justified_block_hash,
finalized_block_hash,
slot,
head_block_root,
)
.await .await
.unwrap(); .unwrap();
assert_eq!(status, PayloadStatus::Syncing); assert_eq!(status, PayloadStatus::Syncing);
@ -360,7 +376,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let status = self let status = self
.ee_a .ee_a
.execution_layer .execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root) .notify_forkchoice_updated(
head_block_hash,
justified_block_hash,
finalized_block_hash,
slot,
head_block_root,
)
.await .await
.unwrap(); .unwrap();
assert_eq!(status, PayloadStatus::Valid); assert_eq!(status, PayloadStatus::Valid);
@ -390,7 +412,6 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let parent_hash = valid_payload.block_hash; let parent_hash = valid_payload.block_hash;
let timestamp = valid_payload.timestamp + 1; let timestamp = valid_payload.timestamp + 1;
let prev_randao = Hash256::zero(); let prev_randao = Hash256::zero();
let finalized_block_hash = ExecutionBlockHash::zero();
let proposer_index = 0; let proposer_index = 0;
let second_payload = self let second_payload = self
.ee_a .ee_a
@ -399,10 +420,10 @@ impl<E: GenericExecutionEngine> TestRig<E> {
parent_hash, parent_hash,
timestamp, timestamp,
prev_randao, prev_randao,
finalized_block_hash,
proposer_index, proposer_index,
None, None,
Slot::new(0), Slot::new(0),
forkchoice_update_params,
) )
.await .await
.unwrap() .unwrap()
@ -445,7 +466,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let status = self let status = self
.ee_a .ee_a
.execution_layer .execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root) .notify_forkchoice_updated(
head_block_hash,
justified_block_hash,
finalized_block_hash,
slot,
head_block_root,
)
.await .await
.unwrap(); .unwrap();
assert_eq!(status, PayloadStatus::Valid); assert_eq!(status, PayloadStatus::Valid);
@ -475,7 +502,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let status = self let status = self
.ee_b .ee_b
.execution_layer .execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root) .notify_forkchoice_updated(
head_block_hash,
justified_block_hash,
finalized_block_hash,
slot,
head_block_root,
)
.await .await
.unwrap(); .unwrap();
assert_eq!(status, PayloadStatus::Syncing); assert_eq!(status, PayloadStatus::Syncing);
@ -521,7 +554,13 @@ impl<E: GenericExecutionEngine> TestRig<E> {
let status = self let status = self
.ee_b .ee_b
.execution_layer .execution_layer
.notify_forkchoice_updated(head_block_hash, finalized_block_hash, slot, head_block_root) .notify_forkchoice_updated(
head_block_hash,
justified_block_hash,
finalized_block_hash,
slot,
head_block_root,
)
.await .await
.unwrap(); .unwrap();
assert_eq!(status, PayloadStatus::Valid); assert_eq!(status, PayloadStatus::Valid);