Fix parent_beacon_block_root during proposer prep (#4703)

* Fix `parent_beacon_block_root` during prep/reorg

* Fix another bug and add tests

* Remove overzealous payload attributes check
This commit is contained in:
Michael Sproul
2023-09-07 15:43:23 +10:00
committed by GitHub
parent f9bea3c174
commit 8db44decb7
7 changed files with 202 additions and 187 deletions

View File

@@ -236,9 +236,12 @@ pub enum ProduceBlockVerification {
pub struct PrePayloadAttributes {
pub proposer_index: u64,
pub prev_randao: Hash256,
/// The block number of the block being built upon (same block as fcU `headBlockHash`).
///
/// The parent block number is not part of the payload attributes sent to the EL, but *is*
/// sent to builders via SSE.
pub parent_block_number: u64,
/// The block root of the block being built upon (same block as fcU `headBlockHash`).
pub parent_beacon_block_root: Hash256,
}
@@ -4111,10 +4114,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let proposal_epoch = proposal_slot.epoch(T::EthSpec::slots_per_epoch());
let head_block_root = cached_head.head_block_root();
let parent_beacon_block_root = cached_head.parent_block_root();
let head_parent_block_root = cached_head.parent_block_root();
// The proposer head must be equal to the canonical head or its parent.
if proposer_head != head_block_root && proposer_head != parent_beacon_block_root {
if proposer_head != head_block_root && proposer_head != head_parent_block_root {
warn!(
self.log,
"Unable to compute payload attributes";
@@ -4193,7 +4196,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Get the `prev_randao` and parent block number.
let head_block_number = cached_head.head_block_number()?;
let (prev_randao, parent_block_number) = if proposer_head == parent_beacon_block_root {
let (prev_randao, parent_block_number) = if proposer_head == head_parent_block_root {
(
cached_head.parent_random()?,
head_block_number.saturating_sub(1),
@@ -4206,7 +4209,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
proposer_index,
prev_randao,
parent_block_number,
parent_beacon_block_root,
parent_beacon_block_root: proposer_head,
}))
}
@@ -4589,8 +4592,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let prepare_payload_handle = match &state {
BeaconState::Base(_) | BeaconState::Altair(_) => None,
BeaconState::Merge(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) => {
let prepare_payload_handle =
get_execution_payload(self.clone(), &state, proposer_index, builder_params)?;
let prepare_payload_handle = get_execution_payload(
self.clone(),
&state,
parent_root,
proposer_index,
builder_params,
)?;
Some(prepare_payload_handle)
}
};

View File

@@ -404,6 +404,7 @@ pub fn get_execution_payload<
>(
chain: Arc<BeaconChain<T>>,
state: &BeaconState<T::EthSpec>,
parent_block_root: Hash256,
proposer_index: u64,
builder_params: BuilderParams,
) -> Result<PreparePayloadHandle<T::EthSpec, Payload>, BlockProductionError> {
@@ -426,10 +427,10 @@ pub fn get_execution_payload<
&BeaconState::Base(_) | &BeaconState::Altair(_) => None,
};
let parent_beacon_block_root = match state {
&BeaconState::Deneb(_) => Some(state.latest_block_header().canonical_root()),
&BeaconState::Merge(_) | &BeaconState::Capella(_) => None,
BeaconState::Deneb(_) => Some(parent_block_root),
BeaconState::Merge(_) | BeaconState::Capella(_) => None,
// These shouldn't happen but they're here to make the pattern irrefutable
&BeaconState::Base(_) | &BeaconState::Altair(_) => None,
BeaconState::Base(_) | BeaconState::Altair(_) => None,
};
// Spawn a task to obtain the execution payload from the EL via a series of async calls. The

View File

@@ -890,32 +890,10 @@ where
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Merge(_)
| SignedBeaconBlock::Capella(_) => (signed_block, None),
SignedBeaconBlock::Deneb(_) => {
if let Some(blobs) = maybe_blob_sidecars {
let signed_blobs: SignedSidecarList<E, BlobSidecar<E>> = Vec::from(blobs)
.into_iter()
.map(|blob| {
blob.sign(
&self.validator_keypairs[proposer_index].sk,
&state.fork(),
state.genesis_validators_root(),
&self.spec,
)
})
.collect::<Vec<_>>()
.into();
let mut guard = self.blob_signature_cache.write();
for blob in &signed_blobs {
guard.insert(
BlobSignatureKey::new(blob.message.block_root, blob.message.index),
blob.signature.clone(),
);
}
(signed_block, Some(signed_blobs))
} else {
(signed_block, None)
}
}
SignedBeaconBlock::Deneb(_) => (
signed_block,
maybe_blob_sidecars.map(|blobs| self.sign_blobs(blobs, &state, proposer_index)),
),
};
(block_contents, state)
@@ -1037,6 +1015,35 @@ where
)
}
/// Sign blobs, and cache their signatures.
pub fn sign_blobs(
&self,
blobs: BlobSidecarList<E>,
state: &BeaconState<E>,
proposer_index: usize,
) -> SignedSidecarList<E, BlobSidecar<E>> {
let signed_blobs: SignedSidecarList<E, BlobSidecar<E>> = Vec::from(blobs)
.into_iter()
.map(|blob| {
blob.sign(
&self.validator_keypairs[proposer_index].sk,
&state.fork(),
state.genesis_validators_root(),
&self.spec,
)
})
.collect::<Vec<_>>()
.into();
let mut guard = self.blob_signature_cache.write();
for blob in &signed_blobs {
guard.insert(
BlobSignatureKey::new(blob.message.block_root, blob.message.index),
blob.signature.clone(),
);
}
signed_blobs
}
/// Produces an "unaggregated" attestation for the given `slot` and `index` that attests to
/// `beacon_block_root`. The provided `state` should match the `block.state_root` for the
/// `block` identified by `beacon_block_root`.
@@ -1940,7 +1947,7 @@ where
)
.await?
.try_into()
.unwrap();
.expect("block blobs are available");
self.chain.recompute_head_at_current_slot().await;
Ok(block_hash)
}