diff --git a/Cargo.lock b/Cargo.lock index c1277ed1d..1c2d69cee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1932,6 +1932,7 @@ dependencies = [ "ethers-providers", "execution_layer", "exit-future", + "fork_choice", "futures", "hex", "reqwest", @@ -1958,6 +1959,7 @@ dependencies = [ "eth2_ssz_types", "ethers-core", "exit-future", + "fork_choice", "futures", "hex", "jsonwebtoken", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index aa719b1a6..78e846e74 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -3256,14 +3256,8 @@ impl BeaconChain { 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 BeaconChain { // `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 BeaconChain { ( 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 BeaconChain { }; 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); diff --git a/beacon_node/beacon_chain/src/canonical_head.rs b/beacon_node/beacon_chain/src/canonical_head.rs index c02ddb826..a07b346c1 100644 --- a/beacon_node/beacon_chain/src/canonical_head.rs +++ b/beacon_node/beacon_chain/src/canonical_head.rs @@ -99,6 +99,8 @@ pub struct CachedHead { /// The `execution_payload.block_hash` of the block at the head of the chain. Set to `None` /// before Bellatrix. head_hash: Option, + /// The `execution_payload.block_hash` of the justified block. Set to `None` before Bellatrix. + justified_hash: Option, /// The `execution_payload.block_hash` of the finalized block. Set to `None` before Bellatrix. finalized_hash: Option, } @@ -183,6 +185,7 @@ impl CachedHead { 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 CanonicalHead { 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 CanonicalHead { 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 BeaconChain { 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 BeaconChain { 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, }; diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index 5c7c3c05d..81193563c 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -302,7 +302,6 @@ pub fn get_execution_payload< >( chain: Arc>, state: &BeaconState, - finalized_checkpoint: Checkpoint, proposer_index: u64, pubkey: Option, ) -> Result, 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( is_merge_transition_complete: bool, timestamp: u64, random: Hash256, - finalized_checkpoint: Checkpoint, proposer_index: u64, pubkey: Option, 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)?; diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index b54964aa3..728057c90 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -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; diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index c181c1905..26e4ba52e 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -39,3 +39,4 @@ lighthouse_metrics = { path = "../../common/lighthouse_metrics" } lazy_static = "1.4.0" ethers-core = { git = "https://github.com/gakonst/ethers-rs", rev = "02ad93a1cfb7b62eb051c77c61dc4c0218428e4a" } builder_client = { path = "../builder_client" } +fork_choice = { path = "../../consensus/fork_choice" } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 4ab38cb3a..e89e9ba81 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -11,6 +11,7 @@ pub use engine_api::*; pub use engine_api::{http, http::deposit_methods, http::HttpJsonRpc}; pub use engines::ForkChoiceState; use engines::{Engine, EngineError}; +use fork_choice::ForkchoiceUpdateParameters; use lru::LruCache; use payload_status::process_payload_status; pub use payload_status::PayloadStatus; @@ -502,10 +503,10 @@ impl ExecutionLayer { parent_hash: ExecutionBlockHash, timestamp: u64, prev_randao: Hash256, - finalized_block_hash: ExecutionBlockHash, proposer_index: u64, pubkey: Option, slot: Slot, + forkchoice_update_params: ForkchoiceUpdateParameters, ) -> Result { let suggested_fee_recipient = self.get_suggested_fee_recipient(proposer_index).await; @@ -519,10 +520,10 @@ impl ExecutionLayer { parent_hash, timestamp, prev_randao, - finalized_block_hash, suggested_fee_recipient, pubkey, slot, + forkchoice_update_params, ) .await } @@ -535,8 +536,8 @@ impl ExecutionLayer { parent_hash, timestamp, prev_randao, - finalized_block_hash, suggested_fee_recipient, + forkchoice_update_params, ) .await } @@ -549,17 +550,22 @@ impl ExecutionLayer { parent_hash: ExecutionBlockHash, timestamp: u64, prev_randao: Hash256, - finalized_block_hash: ExecutionBlockHash, suggested_fee_recipient: Address, pubkey_opt: Option, slot: Slot, + forkchoice_update_params: ForkchoiceUpdateParameters, ) -> Result { //FIXME(sean) fallback logic included in PR #3134 // 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. 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!( self.log(), "Requesting blinded header from connected builder"; @@ -578,8 +584,8 @@ impl ExecutionLayer { parent_hash, timestamp, prev_randao, - finalized_block_hash, suggested_fee_recipient, + forkchoice_update_params, ) .await } @@ -590,15 +596,15 @@ impl ExecutionLayer { parent_hash: ExecutionBlockHash, timestamp: u64, prev_randao: Hash256, - finalized_block_hash: ExecutionBlockHash, suggested_fee_recipient: Address, + forkchoice_update_params: ForkchoiceUpdateParameters, ) -> Result { self.get_full_payload_with( parent_hash, timestamp, prev_randao, - finalized_block_hash, suggested_fee_recipient, + forkchoice_update_params, noop, ) .await @@ -609,8 +615,8 @@ impl ExecutionLayer { parent_hash: ExecutionBlockHash, timestamp: u64, prev_randao: Hash256, - finalized_block_hash: ExecutionBlockHash, suggested_fee_recipient: Address, + forkchoice_update_params: ForkchoiceUpdateParameters, f: fn(&ExecutionLayer, &ExecutionPayload) -> Option>, ) -> Result { debug!( @@ -634,20 +640,20 @@ impl ExecutionLayer { ); id } 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. - // - // 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::EXECUTION_LAYER_PRE_PREPARED_PAYLOAD_ID, &[metrics::MISS], ); let fork_choice_state = ForkChoiceState { head_block_hash: parent_hash, - safe_block_hash: parent_hash, - finalized_block_hash, + safe_block_hash: forkchoice_update_params + .justified_hash + .unwrap_or_else(ExecutionBlockHash::zero), + finalized_block_hash: forkchoice_update_params + .finalized_hash + .unwrap_or_else(ExecutionBlockHash::zero), }; let payload_attributes = PayloadAttributes { timestamp, @@ -655,29 +661,28 @@ impl ExecutionLayer { suggested_fee_recipient, }; - let response = engine - .notify_forkchoice_updated( - fork_choice_state, - Some(payload_attributes), - self.log(), - ) - .await?; + let response = engine + .notify_forkchoice_updated( + fork_choice_state, + Some(payload_attributes), + self.log(), + ) + .await?; - match response.payload_id { - Some(payload_id) => payload_id, - None => { - error!( - self.log(), - "Exec engine unable to produce payload"; - "msg" => "No payload ID, the engine is likely syncing. \ - This has the potential to cause a missed block \ - proposal.", - "status" => ?response.payload_status - ); - return Err(ApiError::PayloadIdUnavailable); - } - } - }; + match response.payload_id { + Some(payload_id) => payload_id, + None => { + error!( + self.log(), + "Exec engine unable to produce payload"; + "msg" => "No payload ID, the engine is likely syncing. \ + This has the potential to cause a missed block proposal.", + "status" => ?response.payload_status + ); + return Err(ApiError::PayloadIdUnavailable); + } + } + }; engine .api @@ -685,7 +690,11 @@ impl ExecutionLayer { .await .map(|full_payload| { 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() }) @@ -809,6 +818,7 @@ impl ExecutionLayer { pub async fn notify_forkchoice_updated( &self, head_block_hash: ExecutionBlockHash, + justified_block_hash: ExecutionBlockHash, finalized_block_hash: ExecutionBlockHash, current_slot: Slot, head_block_root: Hash256, @@ -822,6 +832,7 @@ impl ExecutionLayer { self.log(), "Issuing engine_forkchoiceUpdated"; "finalized_block_hash" => ?finalized_block_hash, + "justified_block_hash" => ?justified_block_hash, "head_block_hash" => ?head_block_hash, ); @@ -848,11 +859,9 @@ impl ExecutionLayer { } } - // see https://hackmd.io/@n0ble/kintsugi-spec#Engine-API - // for now, we must set safe_block_hash = head_block_hash let forkchoice_state = ForkChoiceState { head_block_hash, - safe_block_hash: head_block_hash, + safe_block_hash: justified_block_hash, finalized_block_hash, }; diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index bf8ed4947..6935c88f2 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -335,7 +335,9 @@ impl ExecutionBlockGenerator { } 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 != ExecutionBlockHash::zero() && !self diff --git a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs index 517772a69..8a5c26fe8 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs @@ -88,11 +88,16 @@ impl MockExecutionLayer { let block_number = latest_execution_block.block_number() + 1; let timestamp = 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. let slot = Slot::new(0); - let head_block_root = Hash256::repeat_byte(42); let validator_index = 0; self.el .insert_proposer( @@ -111,6 +116,7 @@ impl MockExecutionLayer { .notify_forkchoice_updated( parent_hash, ExecutionBlockHash::zero(), + ExecutionBlockHash::zero(), slot, head_block_root, ) @@ -124,10 +130,10 @@ impl MockExecutionLayer { parent_hash, timestamp, prev_randao, - finalized_block_hash, validator_index, None, slot, + forkchoice_update_params, ) .await .unwrap() @@ -148,6 +154,7 @@ impl MockExecutionLayer { .notify_forkchoice_updated( block_hash, ExecutionBlockHash::zero(), + ExecutionBlockHash::zero(), slot, head_block_root, ) diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index 7390ce7f9..d06d52235 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -259,6 +259,7 @@ pub enum AttestationFromBlock { pub struct ForkchoiceUpdateParameters { pub head_root: Hash256, pub head_hash: Option, + pub justified_hash: Option, pub finalized_hash: Option, } @@ -372,6 +373,7 @@ where // This will be updated during the next call to `Self::get_head`. forkchoice_update_parameters: ForkchoiceUpdateParameters { head_hash: None, + justified_hash: None, finalized_hash: None, head_root: Hash256::zero(), }, @@ -489,13 +491,18 @@ where let head_hash = self .get_block(&head_root) .and_then(|b| b.execution_status.block_hash()); + let justified_root = self.justified_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 .get_block(&finalized_root) .and_then(|b| b.execution_status.block_hash()); self.forkchoice_update_parameters = ForkchoiceUpdateParameters { head_root, head_hash, + justified_hash, finalized_hash, }; @@ -1211,6 +1218,7 @@ where // Will be updated in the following call to `Self::get_head`. forkchoice_update_parameters: ForkchoiceUpdateParameters { head_hash: None, + justified_hash: None, finalized_hash: None, head_root: Hash256::zero(), }, diff --git a/testing/execution_engine_integration/Cargo.toml b/testing/execution_engine_integration/Cargo.toml index f42a7f6ab..7a8d7e99b 100644 --- a/testing/execution_engine_integration/Cargo.toml +++ b/testing/execution_engine_integration/Cargo.toml @@ -20,3 +20,4 @@ ethers-providers = { git = "https://github.com/gakonst/ethers-rs", rev = "02ad93 deposit_contract = { path = "../../common/deposit_contract" } reqwest = { version = "0.11.0", features = ["json"] } hex = "0.4.2" +fork_choice = { path = "../../consensus/fork_choice" } diff --git a/testing/execution_engine_integration/src/test_rig.rs b/testing/execution_engine_integration/src/test_rig.rs index 9c09ec8d9..7dac2010b 100644 --- a/testing/execution_engine_integration/src/test_rig.rs +++ b/testing/execution_engine_integration/src/test_rig.rs @@ -4,6 +4,7 @@ use crate::execution_engine::{ use crate::transactions::transactions; use ethers_providers::Middleware; use execution_layer::{ExecutionLayer, PayloadAttributes, PayloadStatus}; +use fork_choice::ForkchoiceUpdateParameters; use reqwest::{header::CONTENT_TYPE, Client}; use sensitive_url::SensitiveUrl; use serde_json::{json, Value}; @@ -254,7 +255,15 @@ impl TestRig { let parent_hash = terminal_pow_block_hash; let timestamp = timestamp_now(); let prev_randao = Hash256::zero(); + let head_root = Hash256::zero(); + let justified_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 prepared = self @@ -262,7 +271,7 @@ impl TestRig { .execution_layer .insert_proposer( Slot::new(1), // Insert proposer for the next slot - Hash256::zero(), + head_root, proposer_index, PayloadAttributes { timestamp, @@ -280,6 +289,7 @@ impl TestRig { .execution_layer .notify_forkchoice_updated( parent_hash, + justified_block_hash, finalized_block_hash, Slot::new(0), Hash256::zero(), @@ -302,10 +312,10 @@ impl TestRig { parent_hash, timestamp, prev_randao, - finalized_block_hash, proposer_index, None, Slot::new(0), + forkchoice_update_params, ) .await .unwrap() @@ -326,7 +336,13 @@ impl TestRig { let status = self .ee_a .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 .unwrap(); assert_eq!(status, PayloadStatus::Syncing); @@ -360,7 +376,13 @@ impl TestRig { let status = self .ee_a .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 .unwrap(); assert_eq!(status, PayloadStatus::Valid); @@ -390,7 +412,6 @@ impl TestRig { let parent_hash = valid_payload.block_hash; let timestamp = valid_payload.timestamp + 1; let prev_randao = Hash256::zero(); - let finalized_block_hash = ExecutionBlockHash::zero(); let proposer_index = 0; let second_payload = self .ee_a @@ -399,10 +420,10 @@ impl TestRig { parent_hash, timestamp, prev_randao, - finalized_block_hash, proposer_index, None, Slot::new(0), + forkchoice_update_params, ) .await .unwrap() @@ -445,7 +466,13 @@ impl TestRig { let status = self .ee_a .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 .unwrap(); assert_eq!(status, PayloadStatus::Valid); @@ -475,7 +502,13 @@ impl TestRig { let status = self .ee_b .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 .unwrap(); assert_eq!(status, PayloadStatus::Syncing); @@ -521,7 +554,13 @@ impl TestRig { let status = self .ee_b .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 .unwrap(); assert_eq!(status, PayloadStatus::Valid);