Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ebe9fe2
Gloas lookup sync
dapplion Apr 21, 2026
e0effdb
Merge branch 'unstable' into gloas-lookup-sync-fixes
pawanjay176 May 7, 2026
e4f4083
Update PR
dapplion May 19, 2026
7739c91
Review
dapplion May 19, 2026
2d2fdf3
Fix correctness issues in single-block lookup state machine
dapplion May 19, 2026
0a6aa5a
Merge remote-tracking branch 'sigp/unstable' into gloas-lookup-sync-f…
dapplion May 19, 2026
6e1ee05
Restore is_for_block helper to reduce diff churn
dapplion May 19, 2026
5c58f7e
Thread typed RPC errors through download response handlers
dapplion May 19, 2026
a98e653
Move processing-result classification to the producer side
dapplion May 19, 2026
f6e4438
Wire payload envelope processing end-to-end
dapplion May 19, 2026
64dae1d
Tighten the three sub-state-machine loops in continue_requests
dapplion May 19, 2026
6408c7f
Move parent-known/envelope-imported check onto AwaitingParent
dapplion May 19, 2026
9f4c14c
Drop unused ExecPayload import after execution_hash removal
dapplion May 19, 2026
701bbfd
Drop useless format! to satisfy clippy
dapplion May 19, 2026
6f89fda
Fix clippy errors from new code (unused method, unnecessary cast)
dapplion May 19, 2026
4c80d82
Fix tests
dapplion May 28, 2026
77935bf
Fix gloas lookup tests
dapplion May 28, 2026
d137620
Merge sigp/unstable into gloas-lookup-sync-fixes
dapplion Jun 1, 2026
a70a120
Fix infinite retry loop on blob/column processing failure in lookup sync
dapplion Jun 1, 2026
efa02ed
Clarify import sequence of child FULL
dapplion Jun 1, 2026
5b6cf04
Update import conditions to consider payload too
dapplion May 31, 2026
706c7e0
Use correct slot in custody request
dapplion May 31, 2026
15808c2
Fix network tests
dapplion May 31, 2026
754684c
Lint
dapplion Jun 1, 2026
033ba64
Fix get_data_peers bogus default
dapplion Jun 1, 2026
21e0af8
Merge remote-tracking branch 'sigp/unstable' into gloas-lookup-sync-f…
dapplion Jun 1, 2026
5754c38
Merge remote-tracking branch 'sigp/unstable' into gloas-lookup-sync-f…
dapplion Jun 1, 2026
ad99451
Remove blob lookup from rewritten arch (align with #9383)
dapplion Jun 1, 2026
5a63010
Merge branch 'unstable' into gloas-lookup-sync-fixes
dapplion Jun 4, 2026
31de95e
Fix gloas lookup-sync custody/parent-chain tests; gate payload proces…
dapplion Jun 4, 2026
646b938
Merge branch 'unstable' into gloas-lookup-sync-fixes
dapplion Jun 4, 2026
b75c64c
Merge branch 'unstable' into gloas-lookup-sync-fixes
dapplion Jun 4, 2026
a99fbde
Derive lookup's bid parent_block_hash from its block; drop ParentUnkn…
dapplion Jun 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions beacon_node/beacon_processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ pub enum Work<E: EthSpec> {
process_fn: AsyncFn,
},
RpcCustodyColumn(AsyncFn),
/// An execution payload envelope fetched via RPC for a single-block lookup. Shares the
/// `rpc_blob_queue` for scheduling (similar latency/priority profile).
RpcEnvelope(AsyncFn),
ColumnReconstruction(AsyncFn),
IgnoredRpcBlock {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ impl From<Result<AvailabilityProcessingStatus, BlockError>> for BlockProcessingR
return Self::Imported(true, "duplicate");
}
BlockError::GenesisBlock => return Self::Imported(true, "genesis"),
BlockError::ParentUnknown { parent_root, .. } => {
BlockError::ParentUnknown { parent_root } => {
return Self::ParentUnknown {
parent_root: *parent_root,
};
Expand Down
8 changes: 8 additions & 0 deletions beacon_node/network/src/sync/backfill_sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,14 @@ mod tests {

#[test]
fn request_batches_should_not_loop_infinitely() {
// Backfill sync doesn't yet support Gloas (the harness can't build a Gloas interop genesis
// here); skip under a Gloas genesis. TODO(gloas): support backfill sync.
if beacon_chain::test_utils::test_spec::<MinimalEthSpec>()
.fork_name_at_epoch(Epoch::new(0))
.gloas_enabled()
{
return;
}
let harness = BeaconChainHarness::builder(MinimalEthSpec)
.default_spec()
.deterministic_keypairs(4)
Expand Down
75 changes: 62 additions & 13 deletions beacon_node/network/src/sync/block_lookups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

use self::parent_chain::{NodeChain, compute_parent_chains};
pub use self::single_block_lookup::DownloadResult;
use self::single_block_lookup::{LookupRequestError, LookupResult, SingleBlockLookup};
use self::single_block_lookup::{LookupRequestError, LookupResult, PeerType, SingleBlockLookup};
use super::manager::{BlockProcessType, SLOT_IMPORT_TOLERANCE};
use super::network_context::{RpcResponseError, SyncNetworkContext};
use crate::metrics;
Expand All @@ -39,7 +39,10 @@ use std::sync::Arc;
use std::time::Duration;
use store::Hash256;
use tracing::{debug, error, warn};
use types::{DataColumnSidecarList, EthSpec, SignedBeaconBlock};
use types::{
DataColumnSidecarList, EthSpec, ExecutionBlockHash, SignedBeaconBlock,
SignedExecutionPayloadEnvelope,
};

pub mod parent_chain;
mod single_block_lookup;
Expand Down Expand Up @@ -73,6 +76,8 @@ const MAX_LOOKUPS: usize = 200;
type BlockDownloadResponse<E> = Result<DownloadResult<Arc<SignedBeaconBlock<E>>>, RpcResponseError>;
type CustodyDownloadResponse<E> =
Result<DownloadResult<DataColumnSidecarList<E>>, RpcResponseError>;
type PayloadDownloadResponse<E> =
Result<DownloadResult<Arc<SignedExecutionPayloadEnvelope<E>>>, RpcResponseError>;

pub enum BlockComponent<E: EthSpec> {
Block(DownloadResult<Arc<SignedBeaconBlock<E>>>),
Expand Down Expand Up @@ -169,11 +174,12 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
block_root: Hash256,
block_component: BlockComponent<T::EthSpec>,
parent_root: Hash256,
parent_block_hash: Option<ExecutionBlockHash>,
peer_id: PeerId,
cx: &mut SyncNetworkContext<T>,
) -> bool {
let parent_lookup_exists =
self.search_parent_of_child(parent_root, block_root, &[peer_id], cx);
self.search_parent_of_child(parent_root, parent_block_hash, 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
Expand All @@ -183,8 +189,11 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
Some(parent_root),
// On a `UnknownParentBlock` or `UnknownParentSidecarHeader` event the peer is not
// required to have the rest of the block components. Create the lookup with zero
// peers to house the block components.
// peers to house the block components. We don't know the child's fork yet, so use
// `PreGloas` conservatively; the correct peer set is established when the child's
// block downloads and its FULL children begin attesting.
&[],
&PeerType::PreGloas,
cx,
)
} else {
Expand All @@ -202,7 +211,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
peer_source: &[PeerId],
cx: &mut SyncNetworkContext<T>,
) -> bool {
self.new_current_lookup(block_root, None, None, peer_source, cx)
self.new_current_lookup(block_root, None, None, peer_source, &PeerType::PreGloas, cx)
}

/// A block or blob triggers the search of a parent.
Expand All @@ -215,10 +224,17 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
pub fn search_parent_of_child(
&mut self,
block_root_to_search: Hash256,
// Post-Gloas only: the child's bid `parent_block_hash` (the parent's execution hash). Peers
// that imported the FULL child can serve the parent's payload envelope and data columns.
parent_block_hash: Option<ExecutionBlockHash>,
child_block_root_trigger: Hash256,
peers: &[PeerId],
cx: &mut SyncNetworkContext<T>,
) -> bool {
let peer_type = match parent_block_hash {
Some(execution_hash) => PeerType::PostGloas(execution_hash),
None => PeerType::PreGloas,
};
let parent_chains = self.active_parent_lookups();

for (chain_idx, parent_chain) in parent_chains.iter().enumerate() {
Expand Down Expand Up @@ -307,7 +323,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
}

// `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, cx)
self.new_current_lookup(block_root_to_search, None, None, peers, &peer_type, cx)
}

/// Searches for a single block hash. If the blocks parent is unknown, a chain of blocks is
Expand All @@ -320,6 +336,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
block_component: Option<BlockComponent<T::EthSpec>>,
awaiting_parent: Option<Hash256>,
peers: &[PeerId],
peer_type: &PeerType,
cx: &mut SyncNetworkContext<T>,
) -> bool {
// If this block or it's parent is part of a known ignored chain, ignore it.
Expand All @@ -341,7 +358,8 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
}
}

if let Err(e) = self.add_peers_to_lookup_and_ancestors(lookup_id, peers, cx) {
if let Err(e) = self.add_peers_to_lookup_and_ancestors(lookup_id, peers, peer_type, cx)
{
warn!(error = ?e, "Error adding peers to ancestor lookup");
}

Expand All @@ -368,7 +386,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, cx.next_id(), awaiting_parent);
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
Expand Down Expand Up @@ -438,6 +457,23 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
self.on_lookup_result(id.lookup_id, result, "custody_download_response", cx);
}

pub fn on_payload_download_response(
&mut self,
id: SingleLookupReqId,
response: PayloadDownloadResponse<T::EthSpec>,
cx: &mut SyncNetworkContext<T>,
) {
let Some(lookup) = self.single_block_lookups.get_mut(&id.lookup_id) else {
debug!(
?id,
"Payload envelope returned for single block lookup not present"
);
return;
};
let result = lookup.on_payload_download_response(id.req_id, response, cx);
self.on_lookup_result(id.lookup_id, result, "payload_download_response", cx);
}

/* Error responses */

pub fn peer_disconnected(&mut self, peer_id: &PeerId) {
Expand Down Expand Up @@ -476,8 +512,9 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
BlockProcessType::SingleCustodyColumn(_) => {
lookup.on_data_processing_result(result, cx)
}
// TODO(gloas): route into the payload envelope lookup state machine.
BlockProcessType::SinglePayloadEnvelope(_) => Ok(LookupResult::Pending),
BlockProcessType::SinglePayloadEnvelope(_) => {
lookup.on_payload_processing_result(result, cx)
}
};
self.on_lookup_result(lookup_id, lookup_result, "processing_result", cx);
}
Expand Down Expand Up @@ -579,10 +616,17 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
Ok(LookupResult::Pending) => true,
Ok(LookupResult::ParentUnknown {
parent_root,
parent_block_hash,
block_root,
peers,
}) => {
if self.search_parent_of_child(parent_root, block_root, &peers, cx) {
if self.search_parent_of_child(
parent_root,
parent_block_hash,
block_root,
&peers,
cx,
) {
true
} else {
self.drop_lookup_and_children(id, "Failed");
Expand Down Expand Up @@ -762,6 +806,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
&mut self,
lookup_id: SingleLookupId,
peers: &[PeerId],
peer_type: &PeerType,
cx: &mut SyncNetworkContext<T>,
) -> Result<(), String> {
let lookup = self
Expand All @@ -771,7 +816,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {

let mut added_some_peer = false;
for peer in peers {
if lookup.add_peer(*peer) {
if lookup.add_peer(*peer, peer_type) {
added_some_peer = true;
debug!(
block_root = ?lookup.block_root(),
Expand All @@ -782,12 +827,16 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
}

if let Some(parent_root) = lookup.awaiting_parent() {
// When recursing from child to parent, the parent's peer set is keyed by the child's
// bid `parent_block_hash` (post-Gloas). A peer that imported this FULL child holds the
// parent's payload + columns.
let parent_peer_type = lookup.awaiting_parent_peer_type();
if let Some((&parent_id, _)) = self
.single_block_lookups
.iter()
.find(|(_, l)| l.block_root() == parent_root)
{
self.add_peers_to_lookup_and_ancestors(parent_id, peers, cx)
self.add_peers_to_lookup_and_ancestors(parent_id, peers, &parent_peer_type, cx)
} else {
Err(format!("Lookup references unknown parent {parent_root:?}"))
}
Expand Down
Loading
Loading