Update PR

This commit is contained in:
dapplion
2026-05-19 02:44:30 -06:00
parent e0effdbfb9
commit e4f40836d8
8 changed files with 527 additions and 594 deletions

View File

@@ -6221,10 +6221,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.contains_block(root)
}
// TODO(gloas): implement this once issue #8956 is resolved
pub fn envelope_is_known_to_fork_choice(&self, root: &Hash256) -> bool {
// for now just check the database
self.store.payload_envelope_exists(root).unwrap_or(false)
self.canonical_head
.fork_choice_read_lock()
.is_payload_received(root)
}
/// Determines the beacon proposer for the next slot. If that proposer is registered in the

View File

@@ -720,17 +720,19 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
MessageAcceptance::Accept,
);
}
GossipDataColumnError::ParentUnknown { parent_root, .. } => {
GossipDataColumnError::ParentUnknown { parent_root, slot } => {
debug!(
action = "requesting parent",
%block_root,
%parent_root,
"Unknown parent hash for column"
);
self.send_sync_message(SyncMessage::UnknownParentDataColumn(
self.send_sync_message(SyncMessage::UnknownParentSidecarHeader {
peer_id,
column_sidecar,
));
block_root,
parent_root,
slot,
});
}
GossipDataColumnError::PubkeyCacheTimeout
| GossipDataColumnError::BeaconChainError(_) => {
@@ -926,7 +928,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
%parent_root,
"Unknown parent hash for partial column"
);
self.send_sync_message(SyncMessage::UnknownParentPartialDataColumn {
self.send_sync_message(SyncMessage::UnknownParentSidecarHeader {
peer_id,
block_root,
parent_root,
@@ -1143,10 +1145,12 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
%commitment,
"Unknown parent hash for blob"
);
self.send_sync_message(SyncMessage::UnknownParentBlob(
self.send_sync_message(SyncMessage::UnknownParentSidecarHeader {
peer_id,
blob_sidecar,
));
block_root: root,
parent_root,
slot,
});
}
GossipBlobError::PubkeyCacheTimeout | GossipBlobError::BeaconChainError(_) => {
crit!(

View File

@@ -21,16 +21,14 @@
//! returned to this module as `LookupRequestResult` variants.
use self::parent_chain::{NodeChain, compute_parent_chains};
pub use self::single_block_lookup::DownloadResult;
use self::single_block_lookup::{
AwaitingParent, LookupRequestError, LookupResult, PeerType, SingleBlockLookup,
};
pub use self::single_block_lookup::{AwaitingParent, DownloadResult};
use self::single_block_lookup::{LookupRequestError, LookupResult, SingleBlockLookup};
use super::manager::{BlockProcessType, BlockProcessingResult, SLOT_IMPORT_TOLERANCE};
use super::network_context::{PeerGroup, RpcResponseError, SyncNetworkContext};
use crate::metrics;
use crate::sync::SyncMessage;
use crate::sync::block_lookups::parent_chain::find_oldest_fork_ancestor;
use beacon_chain::block_verification_types::AsBlock;
use crate::sync::block_lookups::single_block_lookup::PeerType;
use beacon_chain::data_availability_checker::{
AvailabilityCheckError, AvailabilityCheckErrorCategory,
};
@@ -87,28 +85,7 @@ type PayloadDownloadResponse<E> =
pub enum BlockComponent<E: EthSpec> {
Block(DownloadResult<Arc<SignedBeaconBlock<E>>>),
Blob(DownloadResult<Hash256>),
DataColumn(DownloadResult<Hash256>),
PartialDataColumn(DownloadResult<Hash256>),
}
impl<E: EthSpec> BlockComponent<E> {
fn parent_root(&self) -> Hash256 {
match self {
BlockComponent::Block(block) => block.value.parent_root(),
BlockComponent::Blob(parent_root)
| BlockComponent::DataColumn(parent_root)
| BlockComponent::PartialDataColumn(parent_root) => parent_root.value,
}
}
fn get_type(&self) -> &'static str {
match self {
BlockComponent::Block(_) => "block",
BlockComponent::Blob(_) => "blob",
BlockComponent::DataColumn(_) => "data_column",
BlockComponent::PartialDataColumn(_) => "partial_data_column",
}
}
Sidecar,
}
pub type SingleLookupId = u32;
@@ -200,31 +177,26 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
&mut self,
block_root: Hash256,
block_component: BlockComponent<T::EthSpec>,
awaiting_parent: AwaitingParent,
peer_id: PeerId,
cx: &mut SyncNetworkContext<T>,
) -> bool {
let parent_root = block_component.parent_root();
// We don't know the child's fork yet (no block downloaded), use PreGloas conservatively.
// The correct AwaitingParent will be set when the child's block downloads.
let awaiting = AwaitingParent::pre_gloas(parent_root);
let parent_lookup_exists =
self.search_parent_of_child(awaiting, block_root, &[peer_id], cx);
self.search_parent_of_child(awaiting_parent, block_root, &[peer_id], cx);
// Only create the child lookup if the parent exists
if parent_lookup_exists {
// `search_parent_of_child` ensures that the parent lookup exists so we can safely wait for it
self.new_current_lookup(
block_root,
Some(block_component),
Some(parent_root),
Some(awaiting_parent),
// On a `UnknownParentBlock` or `UnknownParentBlob` event the peer is not required
// to have the rest of the block components (refer to decoupled blob gossip). Create
// the lookup with zero peers to house the block components.
&[],
&PeerType {
data: false,
payload: false,
},
&PeerType::PreGloas,
cx,
)
} else {
@@ -242,41 +214,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
peer_source: &[PeerId],
cx: &mut SyncNetworkContext<T>,
) -> bool {
self.new_current_lookup(
block_root,
None,
None,
peer_source,
&PeerType {
data: false,
payload: false,
},
cx,
)
}
/// Search for a block triggered by a Gloas data column. The peer that sent the data column
/// is a valid data source, so mark it as data-capable.
///
/// Returns true if the lookup is created or already exists
#[must_use = "only reference the new lookup if returns true"]
pub fn search_unknown_block_with_data_peer(
&mut self,
block_root: Hash256,
peer_source: &[PeerId],
cx: &mut SyncNetworkContext<T>,
) -> bool {
self.new_current_lookup(
block_root,
None,
None,
peer_source,
&PeerType {
data: true,
payload: false,
},
cx,
)
self.new_current_lookup(block_root, None, None, peer_source, &PeerType::PreGloas, cx)
}
/// A block or blob triggers the search of a parent.
@@ -391,24 +329,10 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
// Child's peers can serve block, and data + payload if the parent is full.
// In Gloas, data and payload are coupled: empty blocks have neither.
// Pre-Gloas: data is always needed with block, payload is never needed.
let peer_type = if awaiting_parent.is_post_gloas() {
let is_full = self
.single_block_lookups
.values()
.find(|l| l.is_for_block(block_root_to_search))
.map(|parent| parent.is_full_payload(&awaiting_parent))
.unwrap_or(false);
PeerType {
data: is_full,
payload: is_full,
}
} else {
PeerType {
data: true,
payload: false,
}
let peer_type = match awaiting_parent.parent_hash() {
Some(parent_hash) => PeerType::PostGloas(parent_hash),
None => PeerType::PreGloas,
};
// `block_root_to_search` is a failed chain check happens inside new_current_lookup
self.new_current_lookup(block_root_to_search, None, None, peers, &peer_type, cx)
}
@@ -421,7 +345,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
&mut self,
block_root: Hash256,
block_component: Option<BlockComponent<T::EthSpec>>,
awaiting_parent: Option<Hash256>,
awaiting_parent: Option<AwaitingParent>,
peers: &[PeerId],
peer_type: &PeerType,
cx: &mut SyncNetworkContext<T>,
@@ -436,16 +360,12 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
if let Some((&lookup_id, lookup)) = self
.single_block_lookups
.iter_mut()
.find(|(_id, lookup)| lookup.is_for_block(block_root))
.find(|(_id, lookup)| lookup.block_root() == block_root)
{
if let Some(block_component) = block_component {
let component_type = block_component.get_type();
let imported = lookup.add_child_components(block_component);
if !imported {
debug!(
?block_root,
component_type, "Lookup child component ignored"
);
debug!(?block_root, "Lookup child component ignored");
}
}
@@ -462,7 +382,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
&& !self
.single_block_lookups
.iter()
.any(|(_, lookup)| lookup.is_for_block(awaiting_parent))
.any(|(_, lookup)| lookup.block_root() == awaiting_parent.parent_root())
{
warn!(block_root = ?awaiting_parent, "Ignoring child lookup parent lookup not found");
return false;
@@ -477,13 +397,8 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
// If we know that this lookup has unknown parent (is awaiting a parent lookup to resolve),
// signal here to hold processing downloaded data.
let mut lookup = SingleBlockLookup::new(
block_root,
peers,
peer_type,
cx.next_id(),
awaiting_parent.map(AwaitingParent::pre_gloas),
);
let mut lookup =
SingleBlockLookup::new(block_root, peers, peer_type, cx.next_id(), awaiting_parent);
let _guard = lookup.span.clone().entered();
// Add block components to the new request
@@ -771,10 +686,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
// Use the data kind to pick a penalty string the peer-scoring tests
// distinguish on (blobs vs custody columns).
let penalty_msg = match lookup.data_is_columns() {
Some(true) => "lookup_custody_column_processing_failure",
_ => "lookup_blobs_processing_failure",
};
let penalty_msg = "lookup_data_processing_failure";
match &e {
// No penalization for internal / non-attributable errors
@@ -818,7 +730,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
let Some((id, lookup)) = self
.single_block_lookups
.iter_mut()
.find(|(_, lookup)| lookup.is_for_block(block_root))
.find(|(_, lookup)| lookup.block_root() == block_root)
else {
// Ok to ignore gossip process events
return;
@@ -1111,18 +1023,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
.iter()
.find(|(_, l)| l.block_root() == parent_root)
{
let peer_type = if awaiting.is_post_gloas() {
let is_full = parent_lookup.is_full_payload(&awaiting);
PeerType {
data: is_full,
payload: is_full,
}
} else {
PeerType {
data: true,
payload: false,
}
};
let peer_type = PeerType::from_awaiting_parent(awaiting);
self.add_peers_to_lookup_and_ancestors(parent_id, peers, &peer_type, cx)
} else {
Err(format!("Lookup references unknown parent {parent_root:?}"))

View File

@@ -43,7 +43,7 @@ use super::range_sync::{EPOCHS_PER_BATCH, RangeSync, RangeSyncType};
use crate::network_beacon_processor::{ChainSegmentProcessId, NetworkBeaconProcessor};
use crate::service::NetworkMessage;
use crate::status::ToStatusMessage;
use crate::sync::block_lookups::{BlockComponent, DownloadResult};
use crate::sync::block_lookups::{AwaitingParent, BlockComponent, DownloadResult};
use crate::sync::custody_backfill_sync::CustodyBackFillSync;
use crate::sync::network_context::{PeerGroup, RpcResponseResult};
use beacon_chain::block_verification_types::AsBlock;
@@ -71,7 +71,7 @@ use strum::IntoStaticStr;
use tokio::sync::mpsc;
use tracing::{debug, error, info, trace};
use types::{
BlobSidecar, DataColumnSidecar, EthSpec, ForkContext, Hash256, SignedBeaconBlock,
BlobSidecar, ChainSpec, DataColumnSidecar, EthSpec, ForkContext, Hash256, SignedBeaconBlock,
SignedExecutionPayloadEnvelope, Slot,
};
@@ -142,14 +142,8 @@ pub enum SyncMessage<E: EthSpec> {
/// A block with an unknown parent has been received.
UnknownParentBlock(PeerId, Arc<SignedBeaconBlock<E>>, Hash256),
/// A blob with an unknown parent has been received.
UnknownParentBlob(PeerId, Arc<BlobSidecar<E>>),
/// A data column with an unknown parent has been received.
UnknownParentDataColumn(PeerId, Arc<DataColumnSidecar<E>>),
/// A partial data column with an unknown parent has been received.
UnknownParentPartialDataColumn {
/// A sidecar with an unknown parent has been received.
UnknownParentSidecarHeader {
peer_id: PeerId,
block_root: Hash256,
parent_root: Hash256,
@@ -874,8 +868,8 @@ impl<T: BeaconChainTypes> SyncManager<T> {
self.handle_unknown_parent(
peer_id,
block_root,
parent_root,
block_slot,
AwaitingParent::from_block(&block),
BlockComponent::Block(DownloadResult {
value: block.block_cloned(),
block_root,
@@ -884,97 +878,34 @@ impl<T: BeaconChainTypes> SyncManager<T> {
}),
);
}
SyncMessage::UnknownParentBlob(peer_id, blob) => {
let blob_slot = blob.slot();
let block_root = blob.block_root();
let parent_root = blob.block_parent_root();
debug!(%block_root, %parent_root, "Received unknown parent blob message");
self.handle_unknown_parent(
peer_id,
block_root,
parent_root,
blob_slot,
BlockComponent::Blob(DownloadResult {
value: parent_root,
block_root,
seen_timestamp: self.chain.slot_clock.now_duration().unwrap_or_default(),
peer_group: PeerGroup::from_single(peer_id),
}),
);
}
SyncMessage::UnknownParentDataColumn(peer_id, data_column) => {
let data_column_slot = data_column.slot();
let block_root = data_column.block_root();
match data_column.as_ref() {
DataColumnSidecar::Fulu(column) => {
let parent_root = column.block_parent_root();
debug!(%block_root, %parent_root, "Received unknown parent data column message");
self.handle_unknown_parent(
peer_id,
block_root,
parent_root,
data_column_slot,
BlockComponent::DataColumn(DownloadResult {
value: parent_root,
block_root,
seen_timestamp: self
.chain
.slot_clock
.now_duration()
.unwrap_or_default(),
peer_group: PeerGroup::from_single(peer_id),
}),
);
}
// In Gloas, data columns identify the beacon block root but do not carry
// parent root. Treat as an unknown block-root trigger (attestation-style).
// The peer is marked as data-capable since it sent us a data column.
DataColumnSidecar::Gloas(_) => {
match self.should_search_for_block(Some(data_column_slot), &peer_id) {
Ok(_) => {
if self.block_lookups.search_unknown_block_with_data_peer(
block_root,
&[peer_id],
&mut self.network,
) {
debug!(
?block_root,
"Created unknown block lookup from Gloas data column"
);
} else {
debug!(?block_root, "No lookup created from Gloas data column");
}
}
Err(reason) => {
debug!(
%block_root,
reason,
"Ignoring Gloas data column unknown block request"
);
}
}
}
}
}
SyncMessage::UnknownParentPartialDataColumn {
SyncMessage::UnknownParentSidecarHeader {
peer_id,
block_root,
parent_root,
slot,
} => {
debug!(%block_root, %parent_root, "Received unknown parent partial column message");
self.handle_unknown_parent(
peer_id,
block_root,
debug!(%block_root, %parent_root, "Received unknown parent sidecar message");
match AwaitingParent::from_block_header::<T::EthSpec>(
parent_root,
slot,
BlockComponent::PartialDataColumn(DownloadResult {
value: parent_root,
block_root,
seen_timestamp: self.chain.slot_clock.now_duration().unwrap_or_default(),
peer_group: PeerGroup::from_single(peer_id),
}),
);
self.spec(),
) {
Ok(awaiting_parent) => {
self.handle_unknown_parent(
peer_id,
block_root,
slot,
awaiting_parent,
BlockComponent::Sidecar,
);
}
Err(e) => {
tracing::warn!(
?e,
"Sent UnknownParentSidecarHeader with post-Gloas sidecar"
);
}
}
}
SyncMessage::UnknownBlockHashFromAttestation(peer_id, block_root) => {
if !self.notified_unknown_roots.contains(&(peer_id, block_root)) {
@@ -1054,8 +985,8 @@ impl<T: BeaconChainTypes> SyncManager<T> {
&mut self,
peer_id: PeerId,
block_root: Hash256,
parent_root: Hash256,
slot: Slot,
awaiting_parent: AwaitingParent,
block_component: BlockComponent<T::EthSpec>,
) {
match self.should_search_for_block(Some(slot), &peer_id) {
@@ -1063,6 +994,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
if self.block_lookups.search_child_and_parent(
block_root,
block_component,
awaiting_parent,
peer_id,
&mut self.network,
) {
@@ -1070,13 +1002,18 @@ impl<T: BeaconChainTypes> SyncManager<T> {
} else {
debug!(
?block_root,
?parent_root,
%awaiting_parent,
"No lookup created for child and parent"
);
}
}
Err(reason) => {
debug!(%block_root, %parent_root, reason, "Ignoring unknown parent request");
debug!(
%block_root,
%awaiting_parent,
reason,
"Ignoring unknown parent request"
);
}
}
}
@@ -1526,6 +1463,10 @@ impl<T: BeaconChainTypes> SyncManager<T> {
}
}
}
fn spec(&self) -> &ChainSpec {
&self.network_globals().spec
}
}
impl From<Result<AvailabilityProcessingStatus, BlockError>> for BlockProcessingResult {

View File

@@ -55,8 +55,9 @@ use tokio::sync::mpsc;
use tracing::{Span, debug, debug_span, error, warn};
use types::data::FixedBlobSidecarList;
use types::{
BlobSidecar, BlockImportSource, ColumnIndex, DataColumnSidecar, DataColumnSidecarList, EthSpec,
ForkContext, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot,
BlobSidecar, BlockImportSource, ChainSpec, ColumnIndex, DataColumnSidecar,
DataColumnSidecarList, EthSpec, ForkContext, Hash256, SignedBeaconBlock,
SignedExecutionPayloadEnvelope, Slot,
};
pub mod custody;
@@ -315,6 +316,10 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
}
}
pub fn spec(&self) -> &ChainSpec {
&self.chain.spec
}
pub fn send_sync_message(&mut self, sync_message: SyncMessage<T::EthSpec>) {
self.network_beacon_processor
.send_sync_message(sync_message);