Transition block lookup sync to range sync (#6122)

* Transition block lookup sync to range sync

* Log unexpected state

* Merge remote-tracking branch 'sigp/unstable' into lookup-to-range

* Add docs

* Merge remote-tracking branch 'sigp/unstable' into lookup-to-range
This commit is contained in:
Lion - dapplion
2024-10-09 00:18:41 +03:00
committed by GitHub
parent 48dd3f385c
commit 71c5388461
8 changed files with 206 additions and 30 deletions

View File

@@ -94,6 +94,15 @@ pub enum SyncMessage<E: EthSpec> {
/// A useful peer has been discovered.
AddPeer(PeerId, SyncInfo),
/// Force trigger range sync for a set of peers given a head they claim to have imported. Used
/// by block lookup to trigger range sync if a parent chain grows too large.
AddPeersForceRangeSync {
peers: Vec<PeerId>,
head_root: Hash256,
/// Sync lookup may not know the Slot of this head. However this situation is very rare.
head_slot: Option<Slot>,
},
/// A block has been received from the RPC.
RpcBlock {
request_id: SyncRequestId,
@@ -322,6 +331,13 @@ impl<T: BeaconChainTypes> SyncManager<T> {
.collect()
}
#[cfg(test)]
pub(crate) fn get_range_sync_chains(
&self,
) -> Result<Option<(RangeSyncType, Slot, Slot)>, &'static str> {
self.range_sync.state()
}
#[cfg(test)]
pub(crate) fn get_failed_chains(&mut self) -> Vec<Hash256> {
self.block_lookups.get_failed_chains()
@@ -376,11 +392,30 @@ impl<T: BeaconChainTypes> SyncManager<T> {
let sync_type = remote_sync_type(&local, &remote, &self.chain);
// update the state of the peer.
let should_add = self.update_peer_sync_state(&peer_id, &local, &remote, &sync_type);
if matches!(sync_type, PeerSyncType::Advanced) && should_add {
self.range_sync
.add_peer(&mut self.network, local, peer_id, remote);
let is_still_connected = self.update_peer_sync_state(&peer_id, &local, &remote, &sync_type);
if is_still_connected {
match sync_type {
PeerSyncType::Behind => {} // Do nothing
PeerSyncType::Advanced => {
self.range_sync
.add_peer(&mut self.network, local, peer_id, remote);
}
PeerSyncType::FullySynced => {
// Sync considers this peer close enough to the head to not trigger range sync.
// Range sync handles well syncing large ranges of blocks, of a least a few blocks.
// However this peer may be in a fork that we should sync but we have not discovered
// yet. If the head of the peer is unknown, attempt block lookup first. If the
// unknown head turns out to be on a longer fork, it will trigger range sync.
//
// A peer should always be considered `Advanced` if its finalized root is
// unknown and ahead of ours, so we don't check for that root here.
//
// TODO: This fork-choice check is potentially duplicated, review code
if !self.chain.block_is_known_to_fork_choice(&remote.head_root) {
self.handle_unknown_block_root(peer_id, remote.head_root);
}
}
}
}
self.update_sync_state();
@@ -391,6 +426,44 @@ impl<T: BeaconChainTypes> SyncManager<T> {
}
}
/// Trigger range sync for a set of peers that claim to have imported a head unknown to us.
fn add_peers_force_range_sync(
&mut self,
peers: &[PeerId],
head_root: Hash256,
head_slot: Option<Slot>,
) {
let status = self.chain.status_message();
let local = SyncInfo {
head_slot: status.head_slot,
head_root: status.head_root,
finalized_epoch: status.finalized_epoch,
finalized_root: status.finalized_root,
};
let head_slot = head_slot.unwrap_or_else(|| {
debug!(self.log,
"On add peers force range sync assuming local head_slot";
"local_head_slot" => local.head_slot,
"head_root" => ?head_root
);
local.head_slot
});
let remote = SyncInfo {
head_slot,
head_root,
// Set finalized to same as local to trigger Head sync
finalized_epoch: local.finalized_epoch,
finalized_root: local.finalized_root,
};
for peer_id in peers {
self.range_sync
.add_peer(&mut self.network, local.clone(), *peer_id, remote.clone());
}
}
/// Handles RPC errors related to requests that were emitted from the sync manager.
fn inject_error(&mut self, peer_id: PeerId, request_id: SyncRequestId, error: RPCError) {
trace!(self.log, "Sync manager received a failed RPC");
@@ -476,8 +549,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
}
/// Updates the syncing state of a peer.
/// Return whether the peer should be used for range syncing or not, according to its
/// connection status.
/// Return true if the peer is still connected and known to the peers DB
fn update_peer_sync_state(
&mut self,
peer_id: &PeerId,
@@ -686,6 +758,13 @@ impl<T: BeaconChainTypes> SyncManager<T> {
SyncMessage::AddPeer(peer_id, info) => {
self.add_peer(peer_id, info);
}
SyncMessage::AddPeersForceRangeSync {
peers,
head_root,
head_slot,
} => {
self.add_peers_force_range_sync(&peers, head_root, head_slot);
}
SyncMessage::RpcBlock {
request_id,
peer_id,