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:
parent
6a0e9d4353
commit
e32868458f
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)?;
|
||||||
|
@ -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;
|
||||||
|
@ -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" }
|
||||||
|
@ -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,
|
||||||
@ -670,8 +676,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
|
|||||||
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);
|
||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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(),
|
||||||
},
|
},
|
||||||
|
@ -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" }
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user