Use fork choice to ensure that the execution envelope snapshot is populated in most cases

This commit is contained in:
Eitan Seri-Levi
2026-05-25 17:11:57 +03:00
parent 309719d2c6
commit eead95f112
5 changed files with 104 additions and 6 deletions

View File

@@ -802,7 +802,24 @@ where
.map_err(|e| format!("Error loading head execution envelope: {:?}", e))?
.map(Arc::new)
} else {
None
let latest_full_block_root_opt = fork_choice
.latest_parent_full_block(head_block_root, &self.spec)
.map_err(|e| {
format!(
"Error fetching latest full beacon block root from fork choice: {:?}",
e
)
})?;
if let Some(latest_full_block_root) = latest_full_block_root_opt {
store
.get_payload_envelope(&latest_full_block_root)
.map_err(|e| format!("Error loading latest execution envelope: {:?}", e))?
.map(Arc::new)
} else {
// TODO(gloas) handle the case where the non-finalized portion of the chain has no canonical payload envelopes.
None
}
};
let mut head_snapshot = BeaconSnapshot {

View File

@@ -200,9 +200,9 @@ impl<E: EthSpec> CachedHead<E> {
Some(head_block_number)
} else {
// This fallback is strictly for the fork boundary case when self.snapshot.execution_envelope is `None`.
// Note: If there is a missed/orphaned envelope at the fork boundary we wont be able to get the block number using this fallback.
// We could try handling that edge case but it doesn't seem worth it. Returning `None` here just means that we don't
// emit a payload attributes SSE event further upstream.
// TODO(gloas) If there is a missed/orphaned envelope at the fork boundary we wont be able to get the block number using this fallback.
// We might want to try handling that edge case. Returning `None` here means that we don't emit a payload attributes SSE event which
// might be important for upstream consumers (i.e. the builder client).
self.head_block_number().ok()
}
}
@@ -345,7 +345,17 @@ impl<T: BeaconChainTypes> CanonicalHead<T> {
.get_payload_envelope(&beacon_block_root)?
.map(Arc::new)
} else {
None
let latest_full_block_root_opt =
fork_choice.latest_parent_full_block(beacon_block_root, spec)?;
if let Some(latest_full_block_root) = latest_full_block_root_opt {
store
.get_payload_envelope(&latest_full_block_root)?
.map(Arc::new)
} else {
// TODO(gloas) handle the case where the non-finalized portion of the chain has no canonical payload envelopes.
None
}
};
let snapshot = BeaconSnapshot {
@@ -744,7 +754,24 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Some(envelope)
} else {
None
let fork_choice = self.canonical_head.fork_choice_read_lock();
let latest_full_block_root_opt = fork_choice
.latest_parent_full_block(new_view.head_block_root, &self.spec)?;
drop(fork_choice);
if let Some(latest_full_block_root) = latest_full_block_root_opt {
let envelope = self
.store
.get_payload_envelope(&latest_full_block_root)?
.map(Arc::new)
.ok_or(Error::MissingExecutionPayloadEnvelope(
latest_full_block_root,
))?;
Some(envelope)
} else {
// TODO(gloas) handle the case where the non-finalized portion of the chain has no canonical payload envelopes.
None
}
};
let (_, beacon_state) = self
.store