mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-01 11:43:44 +00:00
Re-issue ForkchoiceUpdate based on updated PayloadStatus (#9102)
Co-Authored-By: hopinheimer <knmanas6@gmail.com> Co-Authored-By: Michael Sproul <michael@sigmaprime.io> Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use alloy_rlp::RlpEncodable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, TryFromIter};
|
||||
use ssz::{Decode, Encode, TryFromIter};
|
||||
use ssz_types::{FixedVector, VariableList, typenum::Unsigned};
|
||||
use strum::EnumString;
|
||||
use superstruct::superstruct;
|
||||
@@ -481,6 +481,34 @@ pub enum RequestsError {
|
||||
#[serde(transparent)]
|
||||
pub struct JsonExecutionRequests(pub Vec<String>);
|
||||
|
||||
impl<E: EthSpec> From<ExecutionRequests<E>> for JsonExecutionRequests {
|
||||
fn from(requests: ExecutionRequests<E>) -> Self {
|
||||
let mut result = Vec::new();
|
||||
if !requests.deposits.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Deposit.to_u8(),
|
||||
hex::encode(requests.deposits.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
if !requests.withdrawals.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Withdrawal.to_u8(),
|
||||
hex::encode(requests.withdrawals.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
if !requests.consolidations.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Consolidation.to_u8(),
|
||||
hex::encode(requests.consolidations.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
JsonExecutionRequests(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
type Error = RequestsError;
|
||||
|
||||
|
||||
@@ -403,6 +403,7 @@ impl ProposerPreparationDataEntry {
|
||||
pub struct ProposerKey {
|
||||
slot: Slot,
|
||||
head_block_root: Hash256,
|
||||
head_payload_status: fork_choice::PayloadStatus,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
@@ -1461,12 +1462,14 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
&self,
|
||||
slot: Slot,
|
||||
head_block_root: Hash256,
|
||||
head_payload_status: fork_choice::PayloadStatus,
|
||||
validator_index: u64,
|
||||
payload_attributes: PayloadAttributes,
|
||||
) -> bool {
|
||||
let proposers_key = ProposerKey {
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
};
|
||||
|
||||
let existing = self.proposers().write().await.insert(
|
||||
@@ -1485,16 +1488,18 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
}
|
||||
|
||||
/// If there has been a proposer registered via `Self::insert_proposer` with a matching `slot`
|
||||
/// `head_block_root`, then return the appropriate `PayloadAttributes` for inclusion in
|
||||
/// `forkchoiceUpdated` calls.
|
||||
/// `head_block_root`, and `head_payload_status` then return the appropriate `PayloadAttributes`
|
||||
/// for inclusion in `forkchoiceUpdated` calls.
|
||||
pub async fn payload_attributes(
|
||||
&self,
|
||||
current_slot: Slot,
|
||||
head_block_root: Hash256,
|
||||
head_payload_status: fork_choice::PayloadStatus,
|
||||
) -> Option<PayloadAttributes> {
|
||||
let proposers_key = ProposerKey {
|
||||
slot: current_slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
};
|
||||
|
||||
let proposer = self.proposers().read().await.get(&proposers_key).cloned()?;
|
||||
@@ -1518,6 +1523,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
finalized_block_hash: ExecutionBlockHash,
|
||||
current_slot: Slot,
|
||||
head_block_root: Hash256,
|
||||
head_payload_status: fork_choice::PayloadStatus,
|
||||
) -> Result<PayloadStatus, Error> {
|
||||
let _timer = metrics::start_timer_vec(
|
||||
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
|
||||
@@ -1534,7 +1540,9 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
);
|
||||
|
||||
let next_slot = current_slot + 1;
|
||||
let payload_attributes = self.payload_attributes(next_slot, head_block_root).await;
|
||||
let payload_attributes = self
|
||||
.payload_attributes(next_slot, head_block_root, head_payload_status)
|
||||
.await;
|
||||
|
||||
// Compute the "lookahead", the time between when the payload will be produced and now.
|
||||
if let Some(ref payload_attributes) = payload_attributes
|
||||
|
||||
@@ -26,8 +26,8 @@ use tree_hash_derive::TreeHash;
|
||||
use types::{
|
||||
Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix,
|
||||
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu,
|
||||
ExecutionPayloadGloas, ExecutionPayloadHeader, ForkName, Hash256, KzgProofs, Transaction,
|
||||
Transactions, Uint256,
|
||||
ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionRequests, ForkName, Hash256, KzgProofs,
|
||||
Transaction, Transactions, Uint256,
|
||||
};
|
||||
|
||||
const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
|
||||
@@ -161,6 +161,14 @@ pub struct ExecutionBlockGenerator<E: EthSpec> {
|
||||
pub blobs_bundles: HashMap<PayloadId, BlobsBundle<E>>,
|
||||
pub kzg: Option<Arc<Kzg>>,
|
||||
rng: Arc<Mutex<StdRng>>,
|
||||
/*
|
||||
* Execution requests (electra+)
|
||||
*/
|
||||
/// Per-payload execution requests returned by `getPayload`.
|
||||
execution_requests: HashMap<PayloadId, ExecutionRequests<E>>,
|
||||
/// If set, the next call to `build_new_execution_payload` will associate these
|
||||
/// execution requests with the generated payload ID.
|
||||
next_execution_requests: Option<ExecutionRequests<E>>,
|
||||
}
|
||||
|
||||
fn make_rng() -> Arc<Mutex<StdRng>> {
|
||||
@@ -199,6 +207,8 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
blobs_bundles: <_>::default(),
|
||||
kzg,
|
||||
rng: make_rng(),
|
||||
execution_requests: <_>::default(),
|
||||
next_execution_requests: None,
|
||||
};
|
||||
|
||||
generator.insert_pow_block(0).unwrap();
|
||||
@@ -458,6 +468,15 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
self.blobs_bundles.get(id).cloned()
|
||||
}
|
||||
|
||||
pub fn get_execution_requests(&self, id: &PayloadId) -> Option<ExecutionRequests<E>> {
|
||||
self.execution_requests.get(id).cloned()
|
||||
}
|
||||
|
||||
/// Set execution requests to be returned alongside the next generated payload.
|
||||
pub fn set_next_execution_requests(&mut self, requests: ExecutionRequests<E>) {
|
||||
self.next_execution_requests = Some(requests);
|
||||
}
|
||||
|
||||
/// Look up a blob and proof by versioned hash across all stored bundles.
|
||||
pub fn get_blob_and_proof(&self, versioned_hash: &Hash256) -> Option<BlobAndProof<E>> {
|
||||
self.blobs_bundles
|
||||
@@ -763,6 +782,11 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
},
|
||||
};
|
||||
|
||||
// Store execution requests for this payload if configured.
|
||||
if let Some(requests) = self.next_execution_requests.take() {
|
||||
self.execution_requests.insert(id, requests);
|
||||
}
|
||||
|
||||
let fork_name = execution_payload.fork_name();
|
||||
if fork_name.deneb_enabled() {
|
||||
// get random number between 0 and 1 blobs by default
|
||||
|
||||
@@ -295,6 +295,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
})?;
|
||||
|
||||
let maybe_blobs = ctx.execution_block_generator.write().get_blobs_bundle(&id);
|
||||
let maybe_execution_requests = ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
.get_execution_requests(&id);
|
||||
|
||||
// validate method called correctly according to shanghai fork time
|
||||
if ctx
|
||||
@@ -432,8 +436,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -453,7 +459,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -473,7 +482,9 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -800,6 +800,10 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
|
||||
let head_block_root = head_block_root.unwrap_or(head.canonical_root());
|
||||
|
||||
// TODO(gloas): Currently the tests are pre-Gloas and we are not considering
|
||||
// other payload statuses. This codepath may not be relevant for Gloas.
|
||||
let head_payload_status = fork_choice::PayloadStatus::Pending;
|
||||
|
||||
let head_execution_payload = head
|
||||
.message()
|
||||
.body()
|
||||
@@ -934,7 +938,13 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
);
|
||||
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
|
||||
.insert_proposer(
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
val_index,
|
||||
payload_attributes.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
@@ -952,6 +962,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
finalized_execution_hash,
|
||||
slot - 1,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("fcu call failed : {:?}", e))?;
|
||||
|
||||
@@ -90,6 +90,8 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
let timestamp = block_number;
|
||||
let prev_randao = Hash256::from_low_u64_be(block_number);
|
||||
let head_block_root = Hash256::repeat_byte(42);
|
||||
// TODO(gloas): allow statuses other than Pending?
|
||||
let head_payload_status = fork_choice::PayloadStatus::Pending;
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
head_root: head_block_root,
|
||||
head_hash: Some(parent_hash),
|
||||
@@ -109,7 +111,13 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
let slot = Slot::new(0);
|
||||
let validator_index = 0;
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, validator_index, payload_attributes)
|
||||
.insert_proposer(
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
validator_index,
|
||||
payload_attributes,
|
||||
)
|
||||
.await;
|
||||
|
||||
self.el
|
||||
@@ -119,6 +127,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
ExecutionBlockHash::zero(),
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -280,6 +289,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
// Use junk values for slot/head-root to ensure there is no payload supplied.
|
||||
let slot = Slot::new(0);
|
||||
let head_block_root = Hash256::repeat_byte(13);
|
||||
// TODO(gloas): reconsider the state_payload_status
|
||||
self.el
|
||||
.notify_forkchoice_updated(
|
||||
block_hash,
|
||||
@@ -287,6 +297,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
ExecutionBlockHash::zero(),
|
||||
slot,
|
||||
head_block_root,
|
||||
fork_choice::PayloadStatus::Pending,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user