add processing and processed caching to the DA checker (#4732)

* add processing and processed caching to the DA checker

* move processing cache out of critical cache

* get it compiling

* fix lints

* add docs to `AvailabilityView`

* some self review

* fix lints

* fix beacon chain tests

* cargo fmt

* make availability view easier to implement, start on testing

* move child component cache and finish test

* cargo fix

* cargo fix

* cargo fix

* fmt and lint

* make blob commitments not optional, rename some caches, add missing blobs struct

* Update beacon_node/beacon_chain/src/data_availability_checker/processing_cache.rs

Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>

* marks review feedback and other general cleanup

* cargo fix

* improve availability view docs

* some renames

* some renames and docs

* fix should delay lookup logic

* get rid of some wrapper methods

* fix up single lookup changes

* add a couple docs

* add single blob merge method and improve process_... docs

* update some names

* lints

* fix merge

* remove blob indices from lookup creation log

* remove blob indices from lookup creation log

* delayed lookup logging improvement

* check fork choice before doing any blob processing

* remove unused dep

* Update beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs

Co-authored-by: Michael Sproul <micsproul@gmail.com>

* Update beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs

Co-authored-by: Michael Sproul <micsproul@gmail.com>

* Update beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs

Co-authored-by: Michael Sproul <micsproul@gmail.com>

* Update beacon_node/beacon_chain/src/data_availability_checker/availability_view.rs

Co-authored-by: Michael Sproul <micsproul@gmail.com>

* Update beacon_node/network/src/sync/block_lookups/delayed_lookup.rs

Co-authored-by: Michael Sproul <micsproul@gmail.com>

* remove duplicate deps

* use gen range in random blobs geneartor

* rename processing cache fields

* require block root in rpc block construction and check block root consistency

* send peers as vec in single message

* spawn delayed lookup service from network beacon processor

* fix tests

---------

Co-authored-by: ethDreamer <37123614+ethDreamer@users.noreply.github.com>
Co-authored-by: Michael Sproul <micsproul@gmail.com>
This commit is contained in:
realbigsean
2023-10-03 09:59:33 -04:00
committed by GitHub
co-authored by ethDreamer Michael Sproul
parent 67aeb6bf6b
commit c7ddf1f0b1
38 changed files with 1894 additions and 1190 deletions
+1
View File
@@ -40,6 +40,7 @@ itertools = { workspace = true }
num_cpus = { workspace = true }
lru_cache = { workspace = true }
if-addrs = "0.6.4"
lru = { workspace = true }
strum = { workspace = true }
tokio-util = { workspace = true }
derivative = { workspace = true }
@@ -4,6 +4,7 @@ use crate::{
service::NetworkMessage,
sync::SyncMessage,
};
use std::collections::HashSet;
use beacon_chain::blob_verification::{GossipBlobError, GossipVerifiedBlob};
use beacon_chain::block_verification_types::AsBlock;
@@ -639,8 +640,8 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.log,
"Successfully verified gossip blob";
"slot" => %slot,
"root" => %root,
"index" => %index
"root" => %root,
"index" => %index
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Accept);
@@ -666,7 +667,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.log,
"Unknown parent hash for blob";
"action" => "requesting parent",
"blob_root" => %blob.block_root,
"block_root" => %blob.block_root,
"parent_root" => %blob.block_parent_root
);
self.send_sync_message(SyncMessage::UnknownParentBlob(peer_id, blob));
@@ -732,10 +733,16 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
// This value is not used presently, but it might come in handy for debugging.
_seen_duration: Duration,
) {
let blob_root = verified_blob.block_root();
let block_root = verified_blob.block_root();
let blob_slot = verified_blob.slot();
let blob_index = verified_blob.id().index;
match self.chain.process_blob(verified_blob).await {
let delay_lookup = self
.chain
.data_availability_checker
.should_delay_lookup(blob_slot);
match self.chain.process_gossip_blob(verified_blob).await {
Ok(AvailabilityProcessingStatus::Imported(hash)) => {
// Note: Reusing block imported metric here
metrics::inc_counter(&metrics::BEACON_PROCESSOR_GOSSIP_BLOCK_IMPORTED_TOTAL);
@@ -746,24 +753,36 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
);
self.chain.recompute_head_at_current_slot().await;
}
Ok(AvailabilityProcessingStatus::MissingComponents(slot, block_hash)) => {
trace!(
self.log,
"Missing block components for gossip verified blob";
"slot" => %blob_slot,
"blob_index" => %blob_index,
"blob_root" => %blob_root,
);
self.send_sync_message(SyncMessage::MissingGossipBlockComponents(
slot, peer_id, block_hash,
));
Ok(AvailabilityProcessingStatus::MissingComponents(_slot, block_root)) => {
if delay_lookup {
self.cache_peer(peer_id, &block_root);
trace!(
self.log,
"Processed blob, delaying lookup for other components";
"slot" => %blob_slot,
"blob_index" => %blob_index,
"block_root" => %block_root,
);
} else {
trace!(
self.log,
"Missing block components for gossip verified blob";
"slot" => %blob_slot,
"blob_index" => %blob_index,
"block_root" => %block_root,
);
self.send_sync_message(SyncMessage::MissingGossipBlockComponents(
vec![peer_id],
block_root,
));
}
}
Err(err) => {
debug!(
self.log,
"Invalid gossip blob";
"outcome" => ?err,
"block root" => ?blob_root,
"block root" => ?block_root,
"block slot" => blob_slot,
"blob index" => blob_index,
);
@@ -780,6 +799,18 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
}
}
/// Cache the peer id for the given block root.
fn cache_peer(self: &Arc<Self>, peer_id: PeerId, block_root: &Hash256) {
let mut guard = self.delayed_lookup_peers.lock();
if let Some(peers) = guard.get_mut(block_root) {
peers.insert(peer_id);
} else {
let mut peers = HashSet::new();
peers.insert(peer_id);
guard.push(*block_root, peers);
}
}
/// Process the beacon block received from the gossip network and:
///
/// - If it passes gossip propagation criteria, tell the network thread to forward it.
@@ -1112,14 +1143,14 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
let block = verified_block.block.block_cloned();
let block_root = verified_block.block_root;
let delay_lookup = self
.chain
.data_availability_checker
.should_delay_lookup(verified_block.block.slot());
let result = self
.chain
.process_block(
block_root,
verified_block,
NotifyExecutionLayer::Yes,
|| Ok(()),
)
.process_block_with_early_caching(block_root, verified_block, NotifyExecutionLayer::Yes)
.await;
match &result {
@@ -1151,12 +1182,26 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
self.chain.recompute_head_at_current_slot().await;
}
Ok(AvailabilityProcessingStatus::MissingComponents(slot, block_root)) => {
// make rpc request for blob
self.send_sync_message(SyncMessage::MissingGossipBlockComponents(
*slot,
peer_id,
*block_root,
));
if delay_lookup {
self.cache_peer(peer_id, block_root);
trace!(
self.log,
"Processed block, delaying lookup for other components";
"slot" => slot,
"block_root" => %block_root,
);
} else {
trace!(
self.log,
"Missing block components for gossip verified block";
"slot" => slot,
"block_root" => %block_root,
);
self.send_sync_message(SyncMessage::MissingGossipBlockComponents(
vec![peer_id],
*block_root,
));
}
}
Err(BlockError::ParentUnknown(block)) => {
// Inform the sync manager to find parents for this block
@@ -1182,6 +1227,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
Err(BlockError::AvailabilityCheck(err)) => {
match err {
AvailabilityCheckError::KzgNotInitialized
| AvailabilityCheckError::Unexpected
| AvailabilityCheckError::SszTypes(_)
| AvailabilityCheckError::MissingBlobs
| AvailabilityCheckError::StoreError(_)
@@ -1194,12 +1240,9 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
}
AvailabilityCheckError::Kzg(_)
| AvailabilityCheckError::KzgVerificationFailed
| AvailabilityCheckError::NumBlobsMismatch { .. }
| AvailabilityCheckError::KzgCommitmentMismatch { .. }
| AvailabilityCheckError::BlobIndexInvalid(_)
| AvailabilityCheckError::UnorderedBlobs { .. }
| AvailabilityCheckError::BlockBlobRootMismatch { .. }
| AvailabilityCheckError::BlockBlobSlotMismatch { .. }
| AvailabilityCheckError::KzgCommitmentMismatch { .. } => {
| AvailabilityCheckError::InconsistentBlobBlockRoots { .. } => {
// Note: we cannot penalize the peer that sent us the block
// over gossip here because these errors imply either an issue
// with:
@@ -18,8 +18,11 @@ use lighthouse_network::{
rpc::{BlocksByRangeRequest, BlocksByRootRequest, LightClientBootstrapRequest, StatusMessage},
Client, MessageId, NetworkGlobals, PeerId, PeerRequestId,
};
use slog::{debug, Logger};
use slot_clock::ManualSlotClock;
use lru::LruCache;
use parking_lot::Mutex;
use slog::{crit, debug, error, trace, Logger};
use slot_clock::{ManualSlotClock, SlotClock};
use std::collections::HashSet;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
@@ -27,6 +30,7 @@ use store::MemoryStore;
use task_executor::test_utils::TestRuntime;
use task_executor::TaskExecutor;
use tokio::sync::mpsc::{self, error::TrySendError};
use tokio::time::{interval_at, Instant};
use types::*;
pub use sync_methods::ChainSegmentProcessId;
@@ -40,6 +44,7 @@ mod sync_methods;
mod tests;
pub(crate) const FUTURE_SLOT_TOLERANCE: u64 = 1;
pub const DELAYED_PEER_CACHE_SIZE: usize = 16;
/// Defines if and where we will store the SSZ files of invalid blocks.
#[derive(Clone)]
@@ -60,6 +65,7 @@ pub struct NetworkBeaconProcessor<T: BeaconChainTypes> {
pub reprocess_tx: mpsc::Sender<ReprocessQueueMessage>,
pub network_globals: Arc<NetworkGlobals<T::EthSpec>>,
pub invalid_block_storage: InvalidBlockStorage,
pub delayed_lookup_peers: Mutex<LruCache<Hash256, HashSet<PeerId>>>,
pub executor: TaskExecutor,
pub log: Logger,
}
@@ -624,6 +630,68 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
"error" => %e)
});
}
/// This service is responsible for collecting lookup messages and sending them back to sync
/// for processing after a short delay.
///
/// We want to delay lookups triggered from gossip for the following reasons:
///
/// - We only want to make one request for components we are unlikely to see on gossip. This means
/// we don't have to repeatedly update our RPC request's state as we receive gossip components.
///
/// - We are likely to receive blocks/blobs over gossip more quickly than we could via an RPC request.
///
/// - Delaying a lookup means we are less likely to simultaneously download the same blocks/blobs
/// over gossip and RPC.
///
/// - We would prefer to request peers based on whether we've seen them attest, because this gives
/// us an idea about whether they *should* have the block/blobs we're missing. This is because a
/// node should not attest to a block unless it has all the blobs for that block. This gives us a
/// stronger basis for peer scoring.
pub fn spawn_delayed_lookup_service(self: &Arc<Self>) {
let processor_clone = self.clone();
let executor = self.executor.clone();
let log = self.log.clone();
let beacon_chain = self.chain.clone();
executor.spawn(
async move {
let slot_duration = beacon_chain.slot_clock.slot_duration();
let delay = beacon_chain.slot_clock.single_lookup_delay();
let interval_start = match (
beacon_chain.slot_clock.duration_to_next_slot(),
beacon_chain.slot_clock.seconds_from_current_slot_start(),
) {
(Some(duration_to_next_slot), Some(seconds_from_current_slot_start)) => {
let duration_until_start = if seconds_from_current_slot_start > delay {
duration_to_next_slot + delay
} else {
delay - seconds_from_current_slot_start
};
Instant::now() + duration_until_start
}
_ => {
crit!(log,
"Failed to read slot clock, delayed lookup service timing will be inaccurate.\
This may degrade performance"
);
Instant::now()
}
};
let mut interval = interval_at(interval_start, slot_duration);
loop {
interval.tick().await;
let Some(slot) = beacon_chain.slot_clock.now_or_genesis() else {
error!(log, "Skipping delayed lookup poll, unable to read slot clock");
continue
};
trace!(log, "Polling delayed lookups for slot: {slot}");
processor_clone.poll_delayed_lookups(slot)
}
},
"delayed_lookups",
);
}
}
type TestBeaconChainType<E> =
@@ -666,6 +734,7 @@ impl<E: EthSpec> NetworkBeaconProcessor<TestBeaconChainType<E>> {
reprocess_tx: work_reprocessing_tx,
network_globals,
invalid_block_storage: InvalidBlockStorage::Disabled,
delayed_lookup_peers: Mutex::new(LruCache::new(DELAYED_PEER_CACHE_SIZE)),
executor: runtime.task_executor.clone(),
log,
};
@@ -18,14 +18,14 @@ use beacon_processor::{
AsyncFn, BlockingFn, DuplicateCache,
};
use lighthouse_network::PeerAction;
use slog::{debug, error, info, warn};
use slog::{debug, error, info, trace, warn};
use slot_clock::SlotClock;
use std::sync::Arc;
use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::mpsc;
use types::blob_sidecar::FixedBlobSidecarList;
use types::{Epoch, Hash256};
use types::{Epoch, Hash256, Slot};
/// Id associated to a batch processing request, either a sync batch or a parent lookup.
#[derive(Clone, Debug, PartialEq)]
@@ -214,7 +214,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
let result = self
.chain
.process_block(block_root, block, NotifyExecutionLayer::Yes, || Ok(()))
.process_block_with_early_caching(block_root, block, NotifyExecutionLayer::Yes)
.await;
metrics::inc_counter(&metrics::BEACON_PROCESSOR_RPC_BLOCK_IMPORTED_TOTAL);
@@ -272,6 +272,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
Box::pin(process_fn)
}
/// Attempt to process a list of blobs received from a direct RPC request.
pub async fn process_rpc_blobs(
self: Arc<NetworkBeaconProcessor<T>>,
block_root: Hash256,
@@ -286,10 +287,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
return;
};
let result = self
.chain
.check_rpc_blob_availability_and_import(slot, block_root, blobs)
.await;
let result = self.chain.process_rpc_blobs(slot, block_root, blobs).await;
// Sync handles these results
self.send_sync_message(SyncMessage::BlockComponentProcessed {
@@ -298,8 +296,25 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
});
}
pub fn send_delayed_lookup(&self, block_root: Hash256) {
self.send_sync_message(SyncMessage::MissingGossipBlockComponentsDelayed(block_root))
/// Poll the beacon chain for any delayed lookups that are now available.
pub fn poll_delayed_lookups(&self, slot: Slot) {
let block_roots = self
.chain
.data_availability_checker
.incomplete_processing_components(slot);
if block_roots.is_empty() {
trace!(self.log, "No delayed lookups found on poll");
} else {
debug!(self.log, "Found delayed lookups on poll"; "lookup_count" => block_roots.len());
}
for block_root in block_roots {
if let Some(peer_ids) = self.delayed_lookup_peers.lock().pop(&block_root) {
self.send_sync_message(SyncMessage::MissingGossipBlockComponents(
peer_ids.into_iter().collect(),
block_root,
));
}
}
}
/// Attempt to import the chain segment (`blocks`) to the beacon chain, informing the sync
@@ -481,7 +496,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
.into_iter()
.filter_map(|maybe_available| match maybe_available {
MaybeAvailableBlock::Available(block) => Some(block),
MaybeAvailableBlock::AvailabilityPending(_) => None,
MaybeAvailableBlock::AvailabilityPending { .. } => None,
})
.collect::<Vec<_>>(),
Err(e) => match e {
@@ -1,6 +1,7 @@
#![cfg(not(debug_assertions))] // Tests are too slow in debug.
#![cfg(test)]
use crate::network_beacon_processor::DELAYED_PEER_CACHE_SIZE;
use crate::{
network_beacon_processor::{
ChainSegmentProcessId, DuplicateCache, InvalidBlockStorage, NetworkBeaconProcessor,
@@ -8,6 +9,7 @@ use crate::{
service::NetworkMessage,
sync::{manager::BlockProcessType, SyncMessage},
};
use beacon_chain::block_verification_types::RpcBlock;
use beacon_chain::test_utils::{
test_spec, AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
};
@@ -22,6 +24,8 @@ use lighthouse_network::{
types::{EnrAttestationBitfield, EnrSyncCommitteeBitfield},
Client, MessageId, NetworkGlobals, PeerId, Response,
};
use lru::LruCache;
use parking_lot::Mutex;
use slot_clock::SlotClock;
use std::iter::Iterator;
use std::sync::Arc;
@@ -217,6 +221,7 @@ impl TestRig {
reprocess_tx: work_reprocessing_tx.clone(),
network_globals: network_globals.clone(),
invalid_block_storage: InvalidBlockStorage::Disabled,
delayed_lookup_peers: Mutex::new(LruCache::new(DELAYED_PEER_CACHE_SIZE)),
executor: executor.clone(),
log: log.clone(),
};
@@ -297,10 +302,11 @@ impl TestRig {
}
pub fn enqueue_rpc_block(&self) {
let block_root = self.next_block.canonical_root();
self.network_beacon_processor
.send_rpc_beacon_block(
self.next_block.canonical_root(),
self.next_block.clone().into(),
block_root,
RpcBlock::new_without_blobs(Some(block_root), self.next_block.clone().into()),
std::time::Duration::default(),
BlockProcessType::ParentLookup {
chain_hash: Hash256::random(),
@@ -310,10 +316,11 @@ impl TestRig {
}
pub fn enqueue_single_lookup_rpc_block(&self) {
let block_root = self.next_block.canonical_root();
self.network_beacon_processor
.send_rpc_beacon_block(
self.next_block.canonical_root(),
self.next_block.clone().into(),
block_root,
RpcBlock::new_without_blobs(Some(block_root), self.next_block.clone().into()),
std::time::Duration::default(),
BlockProcessType::SingleBlock { id: 1 },
)
+6
View File
@@ -21,6 +21,8 @@ use lighthouse_network::{
MessageId, NetworkGlobals, PeerId, PeerRequestId, PubsubMessage, Request, Response,
};
use logging::TimeLatch;
use lru::LruCache;
use parking_lot::Mutex;
use slog::{crit, debug, o, trace};
use slog::{error, warn};
use std::sync::Arc;
@@ -109,10 +111,14 @@ impl<T: BeaconChainTypes> Router<T> {
reprocess_tx: beacon_processor_reprocess_tx,
network_globals: network_globals.clone(),
invalid_block_storage,
delayed_lookup_peers: Mutex::new(LruCache::new(
crate::network_beacon_processor::DELAYED_PEER_CACHE_SIZE,
)),
executor: executor.clone(),
log: log.clone(),
};
let network_beacon_processor = Arc::new(network_beacon_processor);
network_beacon_processor.spawn_delayed_lookup_service();
// spawn the sync thread
crate::sync::manager::spawn(
@@ -8,8 +8,8 @@ use crate::sync::block_lookups::{
};
use crate::sync::manager::{BlockProcessType, Id, SingleLookupReqId};
use crate::sync::network_context::SyncNetworkContext;
use crate::sync::CachedChildComponents;
use beacon_chain::block_verification_types::RpcBlock;
use beacon_chain::data_availability_checker::{AvailabilityView, ChildComponents};
use beacon_chain::{get_block_root, BeaconChainTypes};
use lighthouse_network::rpc::methods::BlobsByRootRequest;
use lighthouse_network::rpc::BlocksByRootRequest;
@@ -19,7 +19,7 @@ use ssz_types::VariableList;
use std::ops::IndexMut;
use std::sync::Arc;
use std::time::Duration;
use types::blob_sidecar::FixedBlobSidecarList;
use types::blob_sidecar::{BlobIdentifier, FixedBlobSidecarList};
use types::{BlobSidecar, EthSpec, Hash256, SignedBeaconBlock};
#[derive(Debug, Copy, Clone)]
@@ -222,11 +222,12 @@ pub trait RequestState<L: Lookup, T: BeaconChainTypes> {
/// triggered by `UnknownParent` errors.
fn add_to_child_components(
verified_response: Self::VerifiedResponseType,
components: &mut CachedChildComponents<T::EthSpec>,
components: &mut ChildComponents<T::EthSpec>,
);
/// Convert a verified response to the type we send to the beacon processor.
fn verified_to_reconstructed(
block_root: Hash256,
verified: Self::VerifiedResponseType,
) -> Self::ReconstructedResponseType;
@@ -326,15 +327,16 @@ impl<L: Lookup, T: BeaconChainTypes> RequestState<L, T> for BlockRequestState<L>
fn add_to_child_components(
verified_response: Arc<SignedBeaconBlock<T::EthSpec>>,
components: &mut CachedChildComponents<T::EthSpec>,
components: &mut ChildComponents<T::EthSpec>,
) {
components.add_cached_child_block(verified_response);
components.merge_block(verified_response);
}
fn verified_to_reconstructed(
block_root: Hash256,
block: Arc<SignedBeaconBlock<T::EthSpec>>,
) -> RpcBlock<T::EthSpec> {
RpcBlock::new_without_blobs(block)
RpcBlock::new_without_blobs(Some(block_root), block)
}
fn send_reconstructed_for_processing(
@@ -375,9 +377,9 @@ impl<L: Lookup, T: BeaconChainTypes> RequestState<L, T> for BlobRequestState<L,
type ReconstructedResponseType = FixedBlobSidecarList<T::EthSpec>;
fn new_request(&self) -> BlobsByRootRequest {
BlobsByRootRequest {
blob_ids: self.requested_ids.clone().into(),
}
let blob_id_vec: Vec<BlobIdentifier> = self.requested_ids.clone().into();
let blob_ids = VariableList::from(blob_id_vec);
BlobsByRootRequest { blob_ids }
}
fn make_request(
@@ -432,12 +434,13 @@ impl<L: Lookup, T: BeaconChainTypes> RequestState<L, T> for BlobRequestState<L,
fn add_to_child_components(
verified_response: FixedBlobSidecarList<T::EthSpec>,
components: &mut CachedChildComponents<T::EthSpec>,
components: &mut ChildComponents<T::EthSpec>,
) {
components.add_cached_child_blobs(verified_response);
components.merge_blobs(verified_response);
}
fn verified_to_reconstructed(
_block_root: Hash256,
blobs: FixedBlobSidecarList<T::EthSpec>,
) -> FixedBlobSidecarList<T::EthSpec> {
blobs
@@ -1,81 +0,0 @@
use crate::network_beacon_processor::NetworkBeaconProcessor;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use slog::crit;
use slot_clock::SlotClock;
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio::time::interval_at;
use tokio::time::Instant;
use types::Hash256;
#[derive(Debug)]
pub enum DelayedLookupMessage {
/// A lookup for all components of a block or blob seen over gossip.
MissingComponents(Hash256),
}
/// This service is responsible for collecting lookup messages and sending them back to sync
/// for processing after a short delay.
///
/// We want to delay lookups triggered from gossip for the following reasons:
///
/// - We only want to make one request for components we are unlikely to see on gossip. This means
/// we don't have to repeatedly update our RPC request's state as we receive gossip components.
///
/// - We are likely to receive blocks/blobs over gossip more quickly than we could via an RPC request.
///
/// - Delaying a lookup means we are less likely to simultaneously download the same blocks/blobs
/// over gossip and RPC.
///
/// - We would prefer to request peers based on whether we've seen them attest, because this gives
/// us an idea about whether they *should* have the block/blobs we're missing. This is because a
/// node should not attest to a block unless it has all the blobs for that block. This gives us a
/// stronger basis for peer scoring.
pub fn spawn_delayed_lookup_service<T: BeaconChainTypes>(
executor: &task_executor::TaskExecutor,
beacon_chain: Arc<BeaconChain<T>>,
mut delayed_lookups_recv: mpsc::Receiver<DelayedLookupMessage>,
beacon_processor: Arc<NetworkBeaconProcessor<T>>,
log: slog::Logger,
) {
executor.spawn(
async move {
let slot_duration = beacon_chain.slot_clock.slot_duration();
let delay = beacon_chain.slot_clock.single_lookup_delay();
let interval_start = match (
beacon_chain.slot_clock.duration_to_next_slot(),
beacon_chain.slot_clock.seconds_from_current_slot_start(),
) {
(Some(duration_to_next_slot), Some(seconds_from_current_slot_start)) => {
let duration_until_start = if seconds_from_current_slot_start > delay {
duration_to_next_slot + delay
} else {
delay - seconds_from_current_slot_start
};
Instant::now() + duration_until_start
}
_ => {
crit!(log,
"Failed to read slot clock, delayed lookup service timing will be inaccurate.\
This may degrade performance"
);
Instant::now()
}
};
let mut interval = interval_at(interval_start, slot_duration);
loop {
interval.tick().await;
while let Ok(msg) = delayed_lookups_recv.try_recv() {
match msg {
DelayedLookupMessage::MissingComponents(block_root) => {
beacon_processor
.send_delayed_lookup(block_root)
}
}
}
}
},
"delayed_lookups",
);
}
+34 -144
View File
@@ -12,6 +12,7 @@ use crate::sync::block_lookups::single_block_lookup::{
};
use crate::sync::manager::{Id, SingleLookupReqId};
use beacon_chain::block_verification_types::{AsBlock, RpcBlock};
pub use beacon_chain::data_availability_checker::ChildComponents;
use beacon_chain::data_availability_checker::{AvailabilityCheckError, DataAvailabilityChecker};
use beacon_chain::validator_monitor::timestamp_now;
use beacon_chain::{AvailabilityProcessingStatus, BeaconChainTypes, BlockError};
@@ -23,7 +24,6 @@ use fnv::FnvHashMap;
use lighthouse_network::rpc::RPCError;
use lighthouse_network::{PeerAction, PeerId};
use lru_cache::LRUTimeCache;
pub use single_block_lookup::CachedChildComponents;
pub use single_block_lookup::{BlobRequestState, BlockRequestState};
use slog::{debug, error, trace, warn, Logger};
use smallvec::SmallVec;
@@ -37,7 +37,6 @@ use types::blob_sidecar::FixedBlobSidecarList;
use types::Slot;
pub mod common;
pub(crate) mod delayed_lookup;
mod parent_lookup;
mod single_block_lookup;
#[cfg(test)]
@@ -122,34 +121,10 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
pub fn search_block(
&mut self,
block_root: Hash256,
peer_source: PeerShouldHave,
peer_source: &[PeerShouldHave],
cx: &mut SyncNetworkContext<T>,
) {
let lookup = self.new_current_lookup(block_root, None, &[peer_source], cx);
if let Some(lookup) = lookup {
let msg = "Searching for block";
lookup_creation_logging(msg, &lookup, peer_source, &self.log);
self.trigger_single_lookup(lookup, cx);
}
}
/// Creates a lookup for the block with the given `block_root`.
///
/// The request is not immediately triggered, and should be triggered by a call to
/// `trigger_lookup_by_root`.
pub fn search_block_delayed(
&mut self,
block_root: Hash256,
peer_source: PeerShouldHave,
cx: &mut SyncNetworkContext<T>,
) {
let lookup = self.new_current_lookup(block_root, None, &[peer_source], cx);
if let Some(lookup) = lookup {
let msg = "Initialized delayed lookup for block";
lookup_creation_logging(msg, &lookup, peer_source, &self.log);
self.add_single_lookup(lookup)
}
self.new_current_lookup(block_root, None, peer_source, cx)
}
/// Creates a lookup for the block with the given `block_root`, while caching other block
@@ -161,44 +136,11 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
pub fn search_child_block(
&mut self,
block_root: Hash256,
child_components: CachedChildComponents<T::EthSpec>,
peer_source: PeerShouldHave,
child_components: ChildComponents<T::EthSpec>,
peer_source: &[PeerShouldHave],
cx: &mut SyncNetworkContext<T>,
) {
if child_components.is_missing_components() {
let lookup =
self.new_current_lookup(block_root, Some(child_components), &[peer_source], cx);
if let Some(lookup) = lookup {
let msg = "Searching for components of a block with unknown parent";
lookup_creation_logging(msg, &lookup, peer_source, &self.log);
self.trigger_single_lookup(lookup, cx);
}
}
}
/// Creates a lookup for the block with the given `block_root`, while caching other block
/// components we've already received. The block components are cached here because we haven't
/// imported it's parent and therefore can't fully validate it and store it in the data
/// availability cache.
///
/// The request is not immediately triggered, and should be triggered by a call to
/// `trigger_lookup_by_root`.
pub fn search_child_delayed(
&mut self,
block_root: Hash256,
child_components: CachedChildComponents<T::EthSpec>,
peer_source: PeerShouldHave,
cx: &mut SyncNetworkContext<T>,
) {
if child_components.is_missing_components() {
let lookup =
self.new_current_lookup(block_root, Some(child_components), &[peer_source], cx);
if let Some(lookup) = lookup {
let msg = "Initialized delayed lookup for block with unknown parent";
lookup_creation_logging(msg, &lookup, peer_source, &self.log);
self.add_single_lookup(lookup)
}
}
self.new_current_lookup(block_root, Some(child_components), peer_source, cx)
}
/// Attempts to trigger the request matching the given `block_root`.
@@ -230,47 +172,15 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
);
}
/// Trigger any lookups that are waiting for the given `block_root`.
pub fn trigger_lookup_by_root(&mut self, block_root: Hash256, cx: &SyncNetworkContext<T>) {
self.single_block_lookups.retain(|_id, lookup| {
if lookup.block_root() == block_root {
if lookup.da_checker.is_deneb() {
let blob_indices = lookup.blob_request_state.requested_ids.indices();
debug!(
self.log,
"Triggering delayed single lookup";
"block" => ?block_root,
"blob_indices" => ?blob_indices
);
} else {
debug!(
self.log,
"Triggering delayed single lookup";
"block" => ?block_root,
);
}
if let Err(e) = lookup.request_block_and_blobs(cx) {
debug!(self.log, "Delayed single block lookup failed";
"error" => ?e,
"block_root" => ?block_root,
);
return false;
}
}
true
});
}
/// Searches for a single block hash. If the blocks parent is unknown, a chain of blocks is
/// constructed.
pub fn new_current_lookup(
&mut self,
block_root: Hash256,
child_components: Option<CachedChildComponents<T::EthSpec>>,
child_components: Option<ChildComponents<T::EthSpec>>,
peers: &[PeerShouldHave],
cx: &mut SyncNetworkContext<T>,
) -> Option<SingleBlockLookup<Current, T>> {
) {
// Do not re-request a block that is already being requested
if let Some((_, lookup)) = self
.single_block_lookups
@@ -281,7 +191,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
if let Some(components) = child_components {
lookup.add_child_components(components);
}
return None;
return;
}
if let Some(parent_lookup) = self.parent_lookups.iter_mut().find(|parent_req| {
@@ -291,7 +201,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
// If the block was already downloaded, or is being downloaded in this moment, do not
// request it.
return None;
return;
}
if self
@@ -300,16 +210,30 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
.any(|(hashes, _last_parent_request)| hashes.contains(&block_root))
{
// we are already processing this block, ignore it.
return None;
return;
}
Some(SingleBlockLookup::new(
let msg = if child_components.is_some() {
"Searching for components of a block with unknown parent"
} else {
"Searching for block components"
};
let lookup = SingleBlockLookup::new(
block_root,
child_components,
peers,
self.da_checker.clone(),
cx.next_id(),
))
);
debug!(
self.log,
"{}", msg;
"peer_ids" => ?peers,
"block" => ?block_root,
);
self.trigger_single_lookup(lookup, cx);
}
/// If a block is attempted to be processed but we do not know its parent, this function is
@@ -337,7 +261,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
if let Some(parent_lookup) = self.parent_lookups.iter_mut().find(|parent_req| {
parent_req.contains_block(&block_root) || parent_req.is_for_block(block_root)
}) {
parent_lookup.add_peers(&[peer_source]);
parent_lookup.add_peer(peer_source);
// we are already searching for this block, ignore it
return;
}
@@ -540,7 +464,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
id,
self,
block_root,
R::verified_to_reconstructed(verified_response),
R::verified_to_reconstructed(block_root, verified_response),
seen_timestamp,
cx,
)?,
@@ -975,9 +899,9 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
AvailabilityCheckError::KzgNotInitialized
| AvailabilityCheckError::SszTypes(_)
| AvailabilityCheckError::MissingBlobs
| AvailabilityCheckError::UnorderedBlobs { .. }
| AvailabilityCheckError::StoreError(_)
| AvailabilityCheckError::DecodeError(_) => {
| AvailabilityCheckError::DecodeError(_)
| AvailabilityCheckError::Unexpected => {
warn!(self.log, "Internal availability check failure"; "root" => %root, "peer_id" => %peer_id, "error" => ?e);
lookup
.block_request_state
@@ -990,20 +914,12 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
lookup.request_block_and_blobs(cx)?
}
// Invalid block and blob comparison.
AvailabilityCheckError::NumBlobsMismatch { .. }
| AvailabilityCheckError::KzgCommitmentMismatch { .. }
| AvailabilityCheckError::BlockBlobRootMismatch { .. }
| AvailabilityCheckError::BlockBlobSlotMismatch { .. } => {
warn!(self.log, "Availability check failure in consistency"; "root" => %root, "peer_id" => %peer_id, "error" => ?e);
lookup.handle_consistency_failure(cx);
lookup.request_block_and_blobs(cx)?
}
// Malicious errors.
AvailabilityCheckError::Kzg(_)
| AvailabilityCheckError::BlobIndexInvalid(_)
| AvailabilityCheckError::KzgVerificationFailed => {
| AvailabilityCheckError::KzgCommitmentMismatch { .. }
| AvailabilityCheckError::KzgVerificationFailed
| AvailabilityCheckError::InconsistentBlobBlockRoots { .. } => {
warn!(self.log, "Availability check failure"; "root" => %root, "peer_id" => %peer_id, "error" => ?e);
lookup.handle_availability_check_failure(cx);
lookup.request_block_and_blobs(cx)?
@@ -1480,29 +1396,3 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
self.parent_lookups.drain(..).len()
}
}
fn lookup_creation_logging<L: Lookup, T: BeaconChainTypes>(
msg: &str,
lookup: &SingleBlockLookup<L, T>,
peer_source: PeerShouldHave,
log: &Logger,
) {
let block_root = lookup.block_root();
if lookup.da_checker.is_deneb() {
let blob_indices = lookup.blob_request_state.requested_ids.indices();
debug!(
log,
"{}", msg;
"peer_id" => ?peer_source,
"block" => ?block_root,
"blob_indices" => ?blob_indices
);
} else {
debug!(
log,
"{}", msg;
"peer_id" => ?peer_source,
"block" => ?block_root,
);
}
}
@@ -5,7 +5,7 @@ use crate::sync::block_lookups::common::RequestState;
use crate::sync::{manager::SLOT_IMPORT_TOLERANCE, network_context::SyncNetworkContext};
use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::block_verification_types::RpcBlock;
use beacon_chain::data_availability_checker::DataAvailabilityChecker;
use beacon_chain::data_availability_checker::{ChildComponents, DataAvailabilityChecker};
use beacon_chain::BeaconChainTypes;
use itertools::Itertools;
use lighthouse_network::PeerId;
@@ -67,7 +67,7 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
) -> Self {
let current_parent_request = SingleBlockLookup::new(
parent_root,
Some(<_>::default()),
Some(ChildComponents::empty(block_root)),
&[peer_id],
da_checker,
cx.next_id(),
@@ -179,7 +179,7 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
.blob_request_state
.state
.register_failure_processing();
if let Some(components) = self.current_parent_request.cached_child_components.as_mut() {
if let Some(components) = self.current_parent_request.child_components.as_mut() {
components.downloaded_block = None;
components.downloaded_blobs = <_>::default();
}
@@ -211,8 +211,13 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
Ok(root_and_verified)
}
pub fn add_peers(&mut self, peer_source: &[PeerShouldHave]) {
self.current_parent_request.add_peers(peer_source)
pub fn add_peer(&mut self, peer: PeerShouldHave) {
self.current_parent_request.add_peer(peer)
}
/// Adds a list of peers to the parent request.
pub fn add_peers(&mut self, peers: &[PeerShouldHave]) {
self.current_parent_request.add_peers(peers)
}
pub fn used_peers(&self) -> impl Iterator<Item = &PeerId> + '_ {
@@ -3,20 +3,21 @@ use crate::sync::block_lookups::common::{Lookup, RequestState};
use crate::sync::block_lookups::Id;
use crate::sync::network_context::SyncNetworkContext;
use beacon_chain::block_verification_types::RpcBlock;
use beacon_chain::data_availability_checker::{AvailabilityCheckError, DataAvailabilityChecker};
use beacon_chain::data_availability_checker::{
AvailabilityCheckError, DataAvailabilityChecker, MissingBlobs,
};
use beacon_chain::data_availability_checker::{AvailabilityView, ChildComponents};
use beacon_chain::BeaconChainTypes;
use lighthouse_network::rpc::methods::MaxRequestBlobSidecars;
use lighthouse_network::{PeerAction, PeerId};
use slog::{trace, Logger};
use ssz_types::VariableList;
use std::collections::HashSet;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::Arc;
use store::Hash256;
use strum::IntoStaticStr;
use types::blob_sidecar::{BlobIdentifier, FixedBlobSidecarList};
use types::{EthSpec, SignedBeaconBlock};
use types::blob_sidecar::FixedBlobSidecarList;
use types::EthSpec;
#[derive(Debug, PartialEq, Eq)]
pub enum State {
@@ -58,23 +59,24 @@ pub struct SingleBlockLookup<L: Lookup, T: BeaconChainTypes> {
pub da_checker: Arc<DataAvailabilityChecker<T>>,
/// Only necessary for requests triggered by an `UnknownBlockParent` or `UnknownBlockParent`
/// because any blocks or blobs without parents won't hit the data availability cache.
pub cached_child_components: Option<CachedChildComponents<T::EthSpec>>,
pub child_components: Option<ChildComponents<T::EthSpec>>,
}
impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
pub fn new(
requested_block_root: Hash256,
unknown_parent_components: Option<CachedChildComponents<T::EthSpec>>,
child_components: Option<ChildComponents<T::EthSpec>>,
peers: &[PeerShouldHave],
da_checker: Arc<DataAvailabilityChecker<T>>,
id: Id,
) -> Self {
let is_deneb = da_checker.is_deneb();
Self {
id,
block_request_state: BlockRequestState::new(requested_block_root, peers),
blob_request_state: BlobRequestState::new(peers),
blob_request_state: BlobRequestState::new(requested_block_root, peers, is_deneb),
da_checker,
cached_child_components: unknown_parent_components,
child_components,
}
}
@@ -94,7 +96,7 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
self.block_request_state.requested_block_root = block_root;
self.block_request_state.state.state = State::AwaitingDownload;
self.blob_request_state.state.state = State::AwaitingDownload;
self.cached_child_components = Some(CachedChildComponents::default());
self.child_components = Some(ChildComponents::empty(block_root));
}
/// Get all unique peers across block and blob requests.
@@ -134,7 +136,7 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
/// 3. `Ok`: The child is required and we have downloaded it.
/// 4. `Err`: The child is required, but has failed consistency checks.
pub fn get_cached_child_block(&self) -> CachedChild<T::EthSpec> {
if let Some(components) = self.cached_child_components.as_ref() {
if let Some(components) = self.child_components.as_ref() {
let Some(block) = components.downloaded_block.as_ref() else {
return CachedChild::DownloadIncomplete;
};
@@ -143,7 +145,11 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
return CachedChild::DownloadIncomplete;
}
match RpcBlock::new_from_fixed(block.clone(), components.downloaded_blobs.clone()) {
match RpcBlock::new_from_fixed(
self.block_request_state.requested_block_root,
block.clone(),
components.downloaded_blobs.clone(),
) {
Ok(rpc_block) => CachedChild::Ok(rpc_block),
Err(e) => CachedChild::Err(e),
}
@@ -159,8 +165,8 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
&mut self,
verified_response: R::VerifiedResponseType,
) -> CachedChild<T::EthSpec> {
if let Some(cached_child_components) = self.cached_child_components.as_mut() {
R::add_to_child_components(verified_response, cached_child_components);
if let Some(child_components) = self.child_components.as_mut() {
R::add_to_child_components(verified_response, child_components);
self.get_cached_child_block()
} else {
CachedChild::NotRequired
@@ -168,34 +174,40 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
}
/// Add a child component to the lookup request. Merges with any existing child components.
pub fn add_child_components(&mut self, components: CachedChildComponents<T::EthSpec>) {
if let Some(ref mut existing_components) = self.cached_child_components {
let CachedChildComponents {
pub fn add_child_components(&mut self, components: ChildComponents<T::EthSpec>) {
if let Some(ref mut existing_components) = self.child_components {
let ChildComponents {
block_root: _,
downloaded_block,
downloaded_blobs,
} = components;
if let Some(block) = downloaded_block {
existing_components.add_cached_child_block(block);
existing_components.merge_block(block);
}
existing_components.add_cached_child_blobs(downloaded_blobs);
existing_components.merge_blobs(downloaded_blobs);
} else {
self.cached_child_components = Some(components);
self.child_components = Some(components);
}
}
/// Add all given peers to both block and blob request states.
pub fn add_peer(&mut self, peer: PeerShouldHave) {
match peer {
PeerShouldHave::BlockAndBlobs(peer_id) => {
self.block_request_state.state.add_peer(&peer_id);
self.blob_request_state.state.add_peer(&peer_id);
}
PeerShouldHave::Neither(peer_id) => {
self.block_request_state.state.add_potential_peer(&peer_id);
self.blob_request_state.state.add_potential_peer(&peer_id);
}
}
}
/// Add all given peers to both block and blob request states.
pub fn add_peers(&mut self, peers: &[PeerShouldHave]) {
for peer in peers {
match peer {
PeerShouldHave::BlockAndBlobs(peer_id) => {
self.block_request_state.state.add_peer(peer_id);
self.blob_request_state.state.add_peer(peer_id);
}
PeerShouldHave::Neither(peer_id) => {
self.block_request_state.state.add_potential_peer(peer_id);
self.blob_request_state.state.add_potential_peer(peer_id);
}
}
self.add_peer(*peer);
}
}
@@ -243,8 +255,8 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
/// Returns `true` if the block has already been downloaded.
pub(crate) fn block_already_downloaded(&self) -> bool {
if let Some(components) = self.cached_child_components.as_ref() {
components.downloaded_block.is_some()
if let Some(components) = self.child_components.as_ref() {
components.block_exists()
} else {
self.da_checker.has_block(&self.block_root())
}
@@ -260,26 +272,24 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
/// Updates this request with the most recent picture of which blobs still need to be requested.
pub fn update_blobs_request(&mut self) {
self.blob_request_state.requested_ids = self.missing_blob_ids().into()
self.blob_request_state.requested_ids = self.missing_blob_ids();
}
/// If `unknown_parent_components` is `Some`, we know block components won't hit the data
/// availability cache, so we don't check it. In either case we use the data availability
/// checker to get a picture of outstanding blob requirements for the block root.
pub(crate) fn missing_blob_ids(&self) -> Vec<BlobIdentifier> {
if let Some(components) = self.cached_child_components.as_ref() {
let blobs = components.downloaded_indices();
self.da_checker
.get_missing_blob_ids(
self.block_root(),
components.downloaded_block.as_ref(),
Some(blobs),
)
.unwrap_or_default()
/// If `child_components` is `Some`, we know block components won't hit the data
/// availability cache, so we don't check its processing cache unless `child_components`
/// is `None`.
pub(crate) fn missing_blob_ids(&self) -> MissingBlobs {
let block_root = self.block_root();
if let Some(components) = self.child_components.as_ref() {
self.da_checker.get_missing_blob_ids(block_root, components)
} else {
let Some(processing_availability_view) =
self.da_checker.get_processing_components(block_root)
else {
return MissingBlobs::new_without_block(block_root, self.da_checker.is_deneb());
};
self.da_checker
.get_missing_blob_ids_checking_cache(self.block_root())
.unwrap_or_default()
.get_missing_blob_ids(block_root, &processing_availability_view)
}
}
@@ -305,7 +315,7 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
/// necessary and clear the blob cache.
pub fn handle_consistency_failure(&mut self, cx: &SyncNetworkContext<T>) {
self.penalize_blob_peer(false, cx);
if let Some(cached_child) = self.cached_child_components.as_mut() {
if let Some(cached_child) = self.child_components.as_mut() {
cached_child.clear_blobs();
}
self.blob_request_state.state.register_failure_downloading()
@@ -315,49 +325,19 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
/// necessary and clear the blob cache.
pub fn handle_availability_check_failure(&mut self, cx: &SyncNetworkContext<T>) {
self.penalize_blob_peer(true, cx);
if let Some(cached_child) = self.cached_child_components.as_mut() {
if let Some(cached_child) = self.child_components.as_mut() {
cached_child.clear_blobs();
}
self.blob_request_state.state.register_failure_processing()
}
}
#[derive(Clone, Default)]
pub struct RequestedBlobIds(Vec<BlobIdentifier>);
impl From<Vec<BlobIdentifier>> for RequestedBlobIds {
fn from(value: Vec<BlobIdentifier>) -> Self {
Self(value)
}
}
impl Into<VariableList<BlobIdentifier, MaxRequestBlobSidecars>> for RequestedBlobIds {
fn into(self) -> VariableList<BlobIdentifier, MaxRequestBlobSidecars> {
VariableList::from(self.0)
}
}
impl RequestedBlobIds {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn contains(&self, blob_id: &BlobIdentifier) -> bool {
self.0.contains(blob_id)
}
pub fn remove(&mut self, blob_id: &BlobIdentifier) {
self.0.retain(|id| id != blob_id)
}
pub fn indices(&self) -> Vec<u64> {
self.0.iter().map(|id| id.index).collect()
}
}
/// The state of the blob request component of a `SingleBlockLookup`.
pub struct BlobRequestState<L: Lookup, T: EthSpec> {
/// The latest picture of which blobs still need to be requested. This includes information
/// from both block/blobs downloaded in the network layer and any blocks/blobs that exist in
/// the data availability checker.
pub requested_ids: RequestedBlobIds,
pub requested_ids: MissingBlobs,
/// Where we store blobs until we receive the stream terminator.
pub blob_download_queue: FixedBlobSidecarList<T>,
pub state: SingleLookupRequestState,
@@ -365,9 +345,10 @@ pub struct BlobRequestState<L: Lookup, T: EthSpec> {
}
impl<L: Lookup, E: EthSpec> BlobRequestState<L, E> {
pub fn new(peer_source: &[PeerShouldHave]) -> Self {
pub fn new(block_root: Hash256, peer_source: &[PeerShouldHave], is_deneb: bool) -> Self {
let default_ids = MissingBlobs::new_without_block(block_root, is_deneb);
Self {
requested_ids: <_>::default(),
requested_ids: default_ids,
blob_download_queue: <_>::default(),
state: SingleLookupRequestState::new(peer_source),
_phantom: PhantomData,
@@ -408,73 +389,6 @@ pub enum CachedChild<E: EthSpec> {
/// There was an error during consistency checks between block and blobs.
Err(AvailabilityCheckError),
}
/// For requests triggered by an `UnknownBlockParent` or `UnknownBlobParent`, this struct
/// is used to cache components as they are sent to the network service. We can't use the
/// data availability cache currently because any blocks or blobs without parents
/// won't pass validation and therefore won't make it into the cache.
#[derive(Default)]
pub struct CachedChildComponents<E: EthSpec> {
pub downloaded_block: Option<Arc<SignedBeaconBlock<E>>>,
pub downloaded_blobs: FixedBlobSidecarList<E>,
}
impl<E: EthSpec> From<RpcBlock<E>> for CachedChildComponents<E> {
fn from(value: RpcBlock<E>) -> Self {
let (block, blobs) = value.deconstruct();
let fixed_blobs = blobs.map(|blobs| {
FixedBlobSidecarList::from(blobs.into_iter().map(Some).collect::<Vec<_>>())
});
Self::new(Some(block), fixed_blobs)
}
}
impl<E: EthSpec> CachedChildComponents<E> {
pub fn new(
block: Option<Arc<SignedBeaconBlock<E>>>,
blobs: Option<FixedBlobSidecarList<E>>,
) -> Self {
Self {
downloaded_block: block,
downloaded_blobs: blobs.unwrap_or_default(),
}
}
pub fn clear_blobs(&mut self) {
self.downloaded_blobs = FixedBlobSidecarList::default();
}
pub fn add_cached_child_block(&mut self, block: Arc<SignedBeaconBlock<E>>) {
self.downloaded_block = Some(block);
}
pub fn add_cached_child_blobs(&mut self, blobs: FixedBlobSidecarList<E>) {
for (index, blob_opt) in self.downloaded_blobs.iter_mut().enumerate() {
if let Some(Some(downloaded_blob)) = blobs.get(index) {
*blob_opt = Some(downloaded_blob.clone());
}
}
}
pub fn downloaded_indices(&self) -> HashSet<usize> {
self.downloaded_blobs
.iter()
.enumerate()
.filter_map(|(i, blob_opt)| blob_opt.as_ref().map(|_| i))
.collect::<HashSet<_>>()
}
pub fn is_missing_components(&self) -> bool {
self.downloaded_block
.as_ref()
.map(|block| {
block.num_expected_blobs()
!= self.downloaded_blobs.iter().filter(|b| b.is_some()).count()
})
.unwrap_or(true)
}
}
/// Object representing the state of a single block or blob lookup request.
#[derive(PartialEq, Eq, Debug)]
pub struct SingleLookupRequestState {
@@ -516,6 +430,7 @@ impl SingleLookupRequestState {
}
}
}
Self {
state: State::AwaitingDownload,
available_peers,
@@ -703,10 +618,11 @@ mod tests {
Duration::from_secs(spec.seconds_per_slot),
);
let log = NullLoggerBuilder.build().expect("logger should build");
let store = HotColdDB::open_ephemeral(StoreConfig::default(), ChainSpec::minimal(), log)
.expect("store");
let store =
HotColdDB::open_ephemeral(StoreConfig::default(), ChainSpec::minimal(), log.clone())
.expect("store");
let da_checker = Arc::new(
DataAvailabilityChecker::new(slot_clock, None, store.into(), spec)
DataAvailabilityChecker::new(slot_clock, None, store.into(), &log, spec)
.expect("data availability checker"),
);
let mut sl = SingleBlockLookup::<TestLookup1, T>::new(
@@ -742,11 +658,12 @@ mod tests {
Duration::from_secs(spec.seconds_per_slot),
);
let log = NullLoggerBuilder.build().expect("logger should build");
let store = HotColdDB::open_ephemeral(StoreConfig::default(), ChainSpec::minimal(), log)
.expect("store");
let store =
HotColdDB::open_ephemeral(StoreConfig::default(), ChainSpec::minimal(), log.clone())
.expect("store");
let da_checker = Arc::new(
DataAvailabilityChecker::new(slot_clock, None, store.into(), spec)
DataAvailabilityChecker::new(slot_clock, None, store.into(), &log, spec)
.expect("data availability checker"),
);
@@ -10,19 +10,18 @@ use super::*;
use crate::sync::block_lookups::common::ResponseType;
use beacon_chain::builder::Witness;
use beacon_chain::eth1_chain::CachingEth1Backend;
use beacon_chain::test_utils::{build_log, BeaconChainHarness, EphemeralHarnessType};
use beacon_chain::test_utils::{
build_log, generate_rand_block_and_blobs, BeaconChainHarness, EphemeralHarnessType, NumBlobs,
};
use beacon_processor::WorkEvent;
use lighthouse_network::rpc::RPCResponseErrorCode;
use lighthouse_network::{NetworkGlobals, Request};
use rand::Rng;
use slot_clock::{ManualSlotClock, SlotClock, TestingSlotClock};
use store::MemoryStore;
use tokio::sync::mpsc;
use types::{
map_fork_name, map_fork_name_with,
test_utils::{SeedableRng, TestRandom, XorShiftRng},
BeaconBlock, BlobSidecar, EthSpec, ForkName, FullPayloadDeneb, MinimalEthSpec as E,
SignedBeaconBlock,
test_utils::{SeedableRng, XorShiftRng},
BlobSidecar, EthSpec, ForkName, MinimalEthSpec as E, SignedBeaconBlock,
};
type T = Witness<ManualSlotClock, CachingEth1Backend<E>, E, MemoryStore<E>, MemoryStore<E>>;
@@ -36,11 +35,6 @@ struct TestRig {
const D: Duration = Duration::new(0, 0);
enum NumBlobs {
Random,
None,
}
impl TestRig {
fn test_setup(enable_log: bool) -> (BlockLookups<T>, SyncNetworkContext<T>, Self) {
let log = build_log(slog::Level::Debug, enable_log);
@@ -97,59 +91,10 @@ impl TestRig {
fork_name: ForkName,
num_blobs: NumBlobs,
) -> (SignedBeaconBlock<E>, Vec<BlobSidecar<E>>) {
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(&mut self.rng));
let mut block =
SignedBeaconBlock::from_block(inner, types::Signature::random_for_test(&mut self.rng));
let mut blob_sidecars = vec![];
if let Ok(message) = block.message_deneb_mut() {
// get random number between 0 and Max Blobs
let payload: &mut FullPayloadDeneb<E> = &mut message.body.execution_payload;
let num_blobs = match num_blobs {
NumBlobs::Random => 1 + self.rng.gen::<usize>() % E::max_blobs_per_block(),
NumBlobs::None => 0,
};
let (bundle, transactions) =
execution_layer::test_utils::generate_random_blobs::<E, _>(
num_blobs,
self.harness.chain.kzg.as_ref().unwrap(),
&mut self.rng,
)
.unwrap();
let kzg = self.harness.chain.kzg.as_ref().unwrap();
let rng = &mut self.rng;
payload.execution_payload.transactions = <_>::default();
for tx in Vec::from(transactions) {
payload.execution_payload.transactions.push(tx).unwrap();
}
message.body.blob_kzg_commitments = bundle.commitments.clone();
let eth2::types::BlobsBundle {
commitments,
proofs,
blobs,
} = bundle;
let block_root = block.canonical_root();
for (index, ((blob, kzg_commitment), kzg_proof)) in blobs
.into_iter()
.zip(commitments.into_iter())
.zip(proofs.into_iter())
.enumerate()
{
blob_sidecars.push(BlobSidecar {
block_root,
index: index as u64,
slot: block.slot(),
block_parent_root: block.parent_root(),
proposer_index: block.message().proposer_index(),
blob: blob.clone(),
kzg_commitment,
kzg_proof,
});
}
}
(block, blob_sidecars)
generate_rand_block_and_blobs::<E>(fork_name, num_blobs, kzg.as_ref(), rng)
}
#[track_caller]
@@ -292,7 +237,11 @@ fn test_single_block_lookup_happy_path() {
let peer_id = PeerId::random();
let block_root = block.canonical_root();
// Trigger the request
bl.search_block(block_root, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
bl.search_block(
block_root,
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
@@ -340,7 +289,11 @@ fn test_single_block_lookup_empty_response() {
let peer_id = PeerId::random();
// Trigger the request
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
bl.search_block(
block_hash,
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
@@ -368,7 +321,11 @@ fn test_single_block_lookup_wrong_response() {
let peer_id = PeerId::random();
// Trigger the request
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
bl.search_block(
block_hash,
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
@@ -406,7 +363,11 @@ fn test_single_block_lookup_failure() {
let peer_id = PeerId::random();
// Trigger the request
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
bl.search_block(
block_hash,
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
// If we're in deneb, a blob request should have been triggered as well,
// we don't require a response because we're generateing 0-blob blocks in this test.
@@ -440,7 +401,7 @@ fn test_single_block_lookup_becomes_parent_request() {
// Trigger the request
bl.search_block(
block.canonical_root(),
PeerShouldHave::BlockAndBlobs(peer_id),
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
@@ -469,7 +430,7 @@ fn test_single_block_lookup_becomes_parent_request() {
// parent request after processing.
bl.single_block_component_processed::<BlockRequestState<Current>>(
id.id,
BlockError::ParentUnknown(block.into()).into(),
BlockError::ParentUnknown(RpcBlock::new_without_blobs(None, block)).into(),
&mut cx,
);
assert_eq!(bl.single_block_lookups.len(), 1);
@@ -978,7 +939,7 @@ fn test_parent_lookup_too_deep() {
// the processing result
bl.parent_block_processed(
chain_hash,
BlockError::ParentUnknown(block.into()).into(),
BlockError::ParentUnknown(RpcBlock::new_without_blobs(None, block)).into(),
&mut cx,
)
}
@@ -1026,7 +987,7 @@ fn test_single_block_lookup_ignored_response() {
// Trigger the request
bl.search_block(
block.canonical_root(),
PeerShouldHave::BlockAndBlobs(peer_id),
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let id = rig.expect_lookup_request(response_type);
@@ -1188,7 +1149,7 @@ fn test_same_chain_race_condition() {
} else {
bl.parent_block_processed(
chain_hash,
BlockError::ParentUnknown(block.into()).into(),
BlockError::ParentUnknown(RpcBlock::new_without_blobs(None, block)).into(),
&mut cx,
)
}
@@ -1223,6 +1184,7 @@ mod deneb_only {
use super::*;
use crate::sync::block_lookups::common::ResponseType;
use beacon_chain::data_availability_checker::AvailabilityCheckError;
use beacon_chain::test_utils::NumBlobs;
use std::ops::IndexMut;
use std::str::FromStr;
@@ -1278,7 +1240,7 @@ mod deneb_only {
RequestTrigger::AttestationUnknownBlock => {
bl.search_block(
block_root,
PeerShouldHave::BlockAndBlobs(peer_id),
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut cx,
);
let block_req_id = rig.expect_lookup_request(ResponseType::Block);
@@ -1302,8 +1264,8 @@ mod deneb_only {
block_root = child_root;
bl.search_child_block(
child_root,
CachedChildComponents::new(Some(child_block), None),
PeerShouldHave::Neither(peer_id),
ChildComponents::new(child_root, Some(child_block), None),
&[PeerShouldHave::Neither(peer_id)],
&mut cx,
);
@@ -1340,8 +1302,8 @@ mod deneb_only {
*blobs.index_mut(0) = Some(child_blob);
bl.search_child_block(
child_root,
CachedChildComponents::new(None, Some(blobs)),
PeerShouldHave::Neither(peer_id),
ChildComponents::new(child_root, None, Some(blobs)),
&[PeerShouldHave::Neither(peer_id)],
&mut cx,
);
@@ -1359,7 +1321,7 @@ mod deneb_only {
)
}
RequestTrigger::GossipUnknownBlockOrBlob => {
bl.search_block(block_root, PeerShouldHave::Neither(peer_id), &mut cx);
bl.search_block(block_root, &[PeerShouldHave::Neither(peer_id)], &mut cx);
let block_req_id = rig.expect_lookup_request(ResponseType::Block);
let blob_req_id = rig.expect_lookup_request(ResponseType::Blob);
(Some(block_req_id), Some(blob_req_id), None, None)
@@ -1563,6 +1525,7 @@ mod deneb_only {
self.bl.parent_block_processed(
self.block_root,
BlockProcessingResult::Err(BlockError::ParentUnknown(RpcBlock::new_without_blobs(
Some(self.block_root),
self.parent_block.clone().expect("parent block"),
))),
&mut self.cx,
@@ -66,7 +66,7 @@ impl<T: EthSpec> BlocksAndBlobsRequestInfo<T> {
}
}
let blobs = VariableList::from(blobs_buffer.into_iter().flatten().collect::<Vec<_>>());
responses.push(RpcBlock::new(block, Some(blobs))?)
responses.push(RpcBlock::new(None, block, Some(blobs))?)
}
// if accumulated sidecars is not empty, throw an error.
+37 -108
View File
@@ -42,12 +42,11 @@ use crate::network_beacon_processor::{ChainSegmentProcessId, NetworkBeaconProces
use crate::service::NetworkMessage;
use crate::status::ToStatusMessage;
use crate::sync::block_lookups::common::{Current, Parent};
use crate::sync::block_lookups::delayed_lookup;
use crate::sync::block_lookups::delayed_lookup::DelayedLookupMessage;
use crate::sync::block_lookups::{BlobRequestState, BlockRequestState, CachedChildComponents};
use crate::sync::block_lookups::{BlobRequestState, BlockRequestState};
use crate::sync::range_sync::ByRangeRequestType;
use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::block_verification_types::RpcBlock;
use beacon_chain::data_availability_checker::ChildComponents;
use beacon_chain::{
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, BlockError, EngineState,
};
@@ -58,7 +57,6 @@ use lighthouse_network::types::{NetworkGlobals, SyncState};
use lighthouse_network::SyncInfo;
use lighthouse_network::{PeerAction, PeerId};
use slog::{crit, debug, error, info, trace, warn, Logger};
use slot_clock::SlotClock;
use std::boxed::Box;
use std::ops::IndexMut;
use std::ops::Sub;
@@ -76,9 +74,6 @@ use types::{BlobSidecar, EthSpec, Hash256, SignedBeaconBlock, Slot};
/// gossip if no peers are further than this range ahead of us that we have not already downloaded
/// blocks for.
pub const SLOT_IMPORT_TOLERANCE: usize = 32;
/// The maximum number of messages the delay queue can handle in a single slot before messages are
/// dropped.
pub const DELAY_QUEUE_CHANNEL_SIZE: usize = 128;
pub type Id = u32;
@@ -148,10 +143,7 @@ pub enum SyncMessage<T: EthSpec> {
///
/// We will either attempt to find the block matching the unknown hash immediately or queue a lookup,
/// which will then trigger the request when we receive `MissingGossipBlockComponentsDelayed`.
MissingGossipBlockComponents(Slot, PeerId, Hash256),
/// This message triggers a request for missing block components after a delay.
MissingGossipBlockComponentsDelayed(Hash256),
MissingGossipBlockComponents(Vec<PeerId>, Hash256),
/// A peer has disconnected.
Disconnect(PeerId),
@@ -228,8 +220,6 @@ pub struct SyncManager<T: BeaconChainTypes> {
block_lookups: BlockLookups<T>,
delayed_lookups: mpsc::Sender<DelayedLookupMessage>,
/// The logger for the import manager.
log: Logger,
}
@@ -249,8 +239,6 @@ pub fn spawn<T: BeaconChainTypes>(
MAX_REQUEST_BLOCKS >= T::EthSpec::slots_per_epoch() * EPOCHS_PER_BATCH,
"Max blocks that can be requested in a single batch greater than max allowed blocks in a single request"
);
let (delayed_lookups_send, delayed_lookups_recv) =
mpsc::channel::<DelayedLookupMessage>(DELAY_QUEUE_CHANNEL_SIZE);
// create an instance of the SyncManager
let network_globals = beacon_processor.network_globals.clone();
@@ -269,21 +257,11 @@ pub fn spawn<T: BeaconChainTypes>(
beacon_chain.data_availability_checker.clone(),
log.clone(),
),
delayed_lookups: delayed_lookups_send,
log: log.clone(),
};
let log_clone = log.clone();
delayed_lookup::spawn_delayed_lookup_service(
&executor,
beacon_chain,
delayed_lookups_recv,
beacon_processor,
log,
);
// spawn the sync manager thread
debug!(log_clone, "Sync Manager started");
debug!(log, "Sync Manager started");
executor.spawn(async move { Box::pin(sync_manager.main()).await }, "sync");
}
@@ -673,7 +651,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
block_root,
parent_root,
blob_slot,
CachedChildComponents::new(None, Some(blobs)),
ChildComponents::new(block_root, None, Some(blobs)),
);
}
SyncMessage::UnknownBlockHashFromAttestation(peer_id, block_hash) => {
@@ -681,39 +659,31 @@ impl<T: BeaconChainTypes> SyncManager<T> {
if self.synced_and_connected(&peer_id) {
self.block_lookups.search_block(
block_hash,
PeerShouldHave::BlockAndBlobs(peer_id),
&[PeerShouldHave::BlockAndBlobs(peer_id)],
&mut self.network,
);
}
}
SyncMessage::MissingGossipBlockComponents(slot, peer_id, block_root) => {
// If we are not synced, ignore this block.
if self.synced_and_connected(&peer_id) {
if self.should_delay_lookup(slot) {
self.block_lookups.search_block_delayed(
block_root,
PeerShouldHave::Neither(peer_id),
&mut self.network,
);
if let Err(e) = self
.delayed_lookups
.try_send(DelayedLookupMessage::MissingComponents(block_root))
{
warn!(self.log, "Delayed lookup dropped for block referenced by a blob";
"block_root" => ?block_root, "error" => ?e);
SyncMessage::MissingGossipBlockComponents(peer_id, block_root) => {
let peers_guard = self.network_globals().peers.read();
let connected_peers = peer_id
.into_iter()
.filter_map(|peer_id| {
if peers_guard.is_connected(&peer_id) {
Some(PeerShouldHave::Neither(peer_id))
} else {
None
}
} else {
self.block_lookups.search_block(
block_root,
PeerShouldHave::Neither(peer_id),
&mut self.network,
)
}
})
.collect::<Vec<_>>();
drop(peers_guard);
// If we are not synced, ignore this block.
if self.synced() && !connected_peers.is_empty() {
self.block_lookups
.search_block(block_root, &connected_peers, &mut self.network)
}
}
SyncMessage::MissingGossipBlockComponentsDelayed(block_root) => self
.block_lookups
.trigger_lookup_by_root(block_root, &self.network),
SyncMessage::Disconnect(peer_id) => {
self.peer_disconnect(&peer_id);
}
@@ -782,7 +752,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
block_root: Hash256,
parent_root: Hash256,
slot: Slot,
child_components: CachedChildComponents<T::EthSpec>,
child_components: ChildComponents<T::EthSpec>,
) {
if self.should_search_for_block(slot, &peer_id) {
self.block_lookups.search_parent(
@@ -792,56 +762,12 @@ impl<T: BeaconChainTypes> SyncManager<T> {
peer_id,
&mut self.network,
);
if self.should_delay_lookup(slot) {
self.block_lookups.search_child_delayed(
block_root,
child_components,
PeerShouldHave::Neither(peer_id),
&mut self.network,
);
if let Err(e) = self
.delayed_lookups
.try_send(DelayedLookupMessage::MissingComponents(block_root))
{
warn!(self.log, "Delayed lookups dropped for block"; "block_root" => ?block_root, "error" => ?e);
}
} else {
self.block_lookups.search_child_block(
block_root,
child_components,
PeerShouldHave::Neither(peer_id),
&mut self.network,
);
}
}
}
fn should_delay_lookup(&mut self, slot: Slot) -> bool {
if !self.block_lookups.da_checker.is_deneb() {
return false;
}
let maximum_gossip_clock_disparity = self.chain.spec.maximum_gossip_clock_disparity();
let earliest_slot = self
.chain
.slot_clock
.now_with_past_tolerance(maximum_gossip_clock_disparity);
let latest_slot = self
.chain
.slot_clock
.now_with_future_tolerance(maximum_gossip_clock_disparity);
if let (Some(earliest_slot), Some(latest_slot)) = (earliest_slot, latest_slot) {
let msg_for_current_slot = slot >= earliest_slot && slot <= latest_slot;
let delay_threshold_unmet = self
.chain
.slot_clock
.millis_from_current_slot_start()
.map_or(false, |millis_into_slot| {
millis_into_slot < self.chain.slot_clock.single_lookup_delay()
});
msg_for_current_slot && delay_threshold_unmet
} else {
false
self.block_lookups.search_child_block(
block_root,
child_components,
&[PeerShouldHave::Neither(peer_id)],
&mut self.network,
);
}
}
@@ -864,12 +790,15 @@ impl<T: BeaconChainTypes> SyncManager<T> {
&& self.network.is_execution_engine_online()
}
fn synced_and_connected(&mut self, peer_id: &PeerId) -> bool {
fn synced(&mut self) -> bool {
self.network_globals().sync_state.read().is_synced()
&& self.network_globals().peers.read().is_connected(peer_id)
&& self.network.is_execution_engine_online()
}
fn synced_and_connected(&mut self, peer_id: &PeerId) -> bool {
self.synced() && self.network_globals().peers.read().is_connected(peer_id)
}
fn handle_new_execution_engine_state(&mut self, engine_state: EngineState) {
self.network.update_execution_engine_state(engine_state);
@@ -968,7 +897,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
batch_id,
&peer_id,
id,
block.map(Into::into),
block.map(|b| RpcBlock::new_without_blobs(None, b)),
) {
Ok(ProcessResult::SyncCompleted) => self.update_sync_state(),
Ok(ProcessResult::Successful) => {}
@@ -992,7 +921,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
chain_id,
batch_id,
id,
block.map(Into::into),
block.map(|b| RpcBlock::new_without_blobs(None, b)),
);
self.update_sync_state();
}
-1
View File
@@ -9,6 +9,5 @@ mod network_context;
mod peer_sync_info;
mod range_sync;
pub use block_lookups::CachedChildComponents;
pub use manager::{BatchProcessResult, SyncMessage};
pub use range_sync::{BatchOperationOutcome, ChainId};