mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 18:32:42 +00:00
Pause sync when EE is offline (#3428)
## Issue Addressed #3032 ## Proposed Changes Pause sync when ee is offline. Changes include three main parts: - Online/offline notification system - Pause sync - Resume sync #### Online/offline notification system - The engine state is now guarded behind a new struct `State` that ensures every change is correctly notified. Notifications are only sent if the state changes. The new `State` is behind a `RwLock` (as before) as the synchronization mechanism. - The actual notification channel is a [tokio::sync::watch](https://docs.rs/tokio/latest/tokio/sync/watch/index.html) which ensures only the last value is in the receiver channel. This way we don't need to worry about message order etc. - Sync waits for state changes concurrently with normal messages. #### Pause Sync Sync has four components, pausing is done differently in each: - **Block lookups**: Disabled while in this state. We drop current requests and don't search for new blocks. Block lookups are infrequent and I don't think it's worth the extra logic of keeping these and delaying processing. If we later see that this is required, we can add it. - **Parent lookups**: Disabled while in this state. We drop current requests and don't search for new parents. Parent lookups are even less frequent and I don't think it's worth the extra logic of keeping these and delaying processing. If we later see that this is required, we can add it. - **Range**: Chains don't send batches for processing to the beacon processor. This is easily done by guarding the channel to the beacon processor and giving it access only if the ee is responsive. I find this the simplest and most powerful approach since we don't need to deal with new sync states and chain segments that are added while the ee is offline will follow the same logic without needing to synchronize a shared state among those. Another advantage of passive pause vs active pause is that we can still keep track of active advertised chain segments so that on resume we don't need to re-evaluate all our peers. - **Backfill**: Not affected by ee states, we don't pause. #### Resume Sync - **Block lookups**: Enabled again. - **Parent lookups**: Enabled again. - **Range**: Active resume. Since the only real pause range does is not sending batches for processing, resume makes all chains that are holding read-for-processing batches send them. - **Backfill**: Not affected by ee states, no need to resume. ## Additional Info **QUESTION**: Originally I made this to notify and change on synced state, but @pawanjay176 on talks with @paulhauner concluded we only need to check online/offline states. The upcheck function mentions extra checks to have a very up to date sync status to aid the networking stack. However, the only need the networking stack would have is this one. I added a TODO to review if the extra check can be removed Next gen of #3094 Will work best with #3439 Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
@@ -11,7 +11,6 @@ use slog::{crit, debug, o, warn};
|
||||
use std::collections::{btree_map::Entry, BTreeMap, HashSet};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
|
||||
|
||||
/// Blocks are downloaded in batches from peers. This constant specifies how many epochs worth of
|
||||
@@ -102,9 +101,6 @@ pub struct SyncingChain<T: BeaconChainTypes> {
|
||||
/// Batches validated by this chain.
|
||||
validated_batches: u64,
|
||||
|
||||
/// A multi-threaded, non-blocking processor for applying messages to the beacon chain.
|
||||
beacon_processor_send: Sender<BeaconWorkEvent<T>>,
|
||||
|
||||
is_finalized_segment: bool,
|
||||
|
||||
/// The chain's log.
|
||||
@@ -132,7 +128,6 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
target_head_slot: Slot,
|
||||
target_head_root: Hash256,
|
||||
peer_id: PeerId,
|
||||
beacon_processor_send: Sender<BeaconWorkEvent<T>>,
|
||||
is_finalized_segment: bool,
|
||||
log: &slog::Logger,
|
||||
) -> Self {
|
||||
@@ -155,7 +150,6 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
state: ChainSyncingState::Stopped,
|
||||
current_processing_batch: None,
|
||||
validated_batches: 0,
|
||||
beacon_processor_send,
|
||||
is_finalized_segment,
|
||||
log: log.new(o!("chain" => id)),
|
||||
}
|
||||
@@ -186,7 +180,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
pub fn remove_peer(
|
||||
&mut self,
|
||||
peer_id: &PeerId,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
) -> ProcessingResult {
|
||||
if let Some(batch_ids) = self.peers.remove(peer_id) {
|
||||
// fail the batches
|
||||
@@ -227,7 +221,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// If the block correctly completes the batch it will be processed if possible.
|
||||
pub fn on_block_response(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
peer_id: &PeerId,
|
||||
request_id: Id,
|
||||
@@ -296,7 +290,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// The batch must exist and be ready for processing
|
||||
fn process_batch(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
) -> ProcessingResult {
|
||||
// Only process batches if this chain is Syncing, and only one at a time
|
||||
@@ -304,6 +298,11 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
return Ok(KeepChain);
|
||||
}
|
||||
|
||||
let beacon_processor_send = match network.processor_channel_if_enabled() {
|
||||
Some(channel) => channel,
|
||||
None => return Ok(KeepChain),
|
||||
};
|
||||
|
||||
let batch = match self.batches.get_mut(&batch_id) {
|
||||
Some(batch) => batch,
|
||||
None => {
|
||||
@@ -327,9 +326,8 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
let process_id = ChainSegmentProcessId::RangeBatchId(self.id, batch_id, count_unrealized);
|
||||
self.current_processing_batch = Some(batch_id);
|
||||
|
||||
if let Err(e) = self
|
||||
.beacon_processor_send
|
||||
.try_send(BeaconWorkEvent::chain_segment(process_id, blocks))
|
||||
if let Err(e) =
|
||||
beacon_processor_send.try_send(BeaconWorkEvent::chain_segment(process_id, blocks))
|
||||
{
|
||||
crit!(self.log, "Failed to send chain segment to processor."; "msg" => "process_batch",
|
||||
"error" => %e, "batch" => self.processing_target);
|
||||
@@ -346,7 +344,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// Processes the next ready batch, prioritizing optimistic batches over the processing target.
|
||||
fn process_completed_batches(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
) -> ProcessingResult {
|
||||
// Only process batches if this chain is Syncing and only process one batch at a time
|
||||
if self.state != ChainSyncingState::Syncing || self.current_processing_batch.is_some() {
|
||||
@@ -447,7 +445,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// of the batch processor.
|
||||
pub fn on_batch_process_result(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
result: &BatchProcessResult,
|
||||
) -> ProcessingResult {
|
||||
@@ -580,7 +578,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
|
||||
fn reject_optimistic_batch(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
redownload: bool,
|
||||
reason: &str,
|
||||
) -> ProcessingResult {
|
||||
@@ -611,11 +609,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
///
|
||||
/// If a previous batch has been validated and it had been re-processed, penalize the original
|
||||
/// peer.
|
||||
fn advance_chain(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
validating_epoch: Epoch,
|
||||
) {
|
||||
fn advance_chain(&mut self, network: &mut SyncNetworkContext<T>, validating_epoch: Epoch) {
|
||||
// make sure this epoch produces an advancement
|
||||
if validating_epoch <= self.start_epoch {
|
||||
return;
|
||||
@@ -719,7 +713,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// intended and can result in downvoting a peer.
|
||||
fn handle_invalid_batch(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
) -> ProcessingResult {
|
||||
// The current batch could not be processed, indicating either the current or previous
|
||||
@@ -778,7 +772,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// This could be new chain, or an old chain that is being resumed.
|
||||
pub fn start_syncing(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
local_finalized_epoch: Epoch,
|
||||
optimistic_start_epoch: Epoch,
|
||||
) -> ProcessingResult {
|
||||
@@ -816,7 +810,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// If the chain is active, this starts requesting batches from this peer.
|
||||
pub fn add_peer(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
peer_id: PeerId,
|
||||
) -> ProcessingResult {
|
||||
// add the peer without overwriting its active requests
|
||||
@@ -833,7 +827,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// If the batch exists it is re-requested.
|
||||
pub fn inject_error(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
peer_id: &PeerId,
|
||||
request_id: Id,
|
||||
@@ -865,7 +859,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// Sends and registers the request of a batch awaiting download.
|
||||
pub fn retry_batch_download(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
) -> ProcessingResult {
|
||||
let batch = match self.batches.get_mut(&batch_id) {
|
||||
@@ -898,7 +892,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
/// Requests the batch assigned to the given id from a given peer.
|
||||
pub fn send_batch(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
batch_id: BatchId,
|
||||
peer: PeerId,
|
||||
) -> ProcessingResult {
|
||||
@@ -967,12 +961,21 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Kickstarts the chain by sending for processing batches that are ready and requesting more
|
||||
/// batches if needed.
|
||||
pub fn resume(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
) -> Result<KeepChain, RemoveChain> {
|
||||
// Request more batches if needed.
|
||||
self.request_batches(network)?;
|
||||
// If there is any batch ready for processing, send it.
|
||||
self.process_completed_batches(network)
|
||||
}
|
||||
|
||||
/// Attempts to request the next required batches from the peer pool if the chain is syncing. It will exhaust the peer
|
||||
/// pool and left over batches until the batch buffer is reached or all peers are exhausted.
|
||||
fn request_batches(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
) -> ProcessingResult {
|
||||
fn request_batches(&mut self, network: &mut SyncNetworkContext<T>) -> ProcessingResult {
|
||||
if !matches!(self.state, ChainSyncingState::Syncing) {
|
||||
return Ok(KeepChain);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
use super::block_storage::BlockStorage;
|
||||
use super::chain::{ChainId, ProcessingResult, RemoveChain, SyncingChain};
|
||||
use super::sync_type::RangeSyncType;
|
||||
use crate::beacon_processor::WorkEvent as BeaconWorkEvent;
|
||||
use crate::metrics;
|
||||
use crate::sync::network_context::SyncNetworkContext;
|
||||
use beacon_chain::BeaconChainTypes;
|
||||
@@ -18,7 +17,6 @@ use smallvec::SmallVec;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
use types::EthSpec;
|
||||
use types::{Epoch, Hash256, Slot};
|
||||
|
||||
@@ -193,10 +191,9 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
/// do so.
|
||||
pub fn update(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
local: &SyncInfo,
|
||||
awaiting_head_peers: &mut HashMap<PeerId, SyncInfo>,
|
||||
beacon_processor_send: &mpsc::Sender<BeaconWorkEvent<T>>,
|
||||
) {
|
||||
// Remove any outdated finalized/head chains
|
||||
self.purge_outdated_chains(local, awaiting_head_peers);
|
||||
@@ -212,7 +209,6 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
local.finalized_epoch,
|
||||
local_head_epoch,
|
||||
awaiting_head_peers,
|
||||
beacon_processor_send,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -257,7 +253,7 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
/// or not.
|
||||
fn update_finalized_chains(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
local_epoch: Epoch,
|
||||
local_head_epoch: Epoch,
|
||||
) {
|
||||
@@ -326,11 +322,10 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
/// Start syncing any head chains if required.
|
||||
fn update_head_chains(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
local_epoch: Epoch,
|
||||
local_head_epoch: Epoch,
|
||||
awaiting_head_peers: &mut HashMap<PeerId, SyncInfo>,
|
||||
beacon_processor_send: &mpsc::Sender<BeaconWorkEvent<T>>,
|
||||
) {
|
||||
// Include the awaiting head peers
|
||||
for (peer_id, peer_sync_info) in awaiting_head_peers.drain() {
|
||||
@@ -341,7 +336,6 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
peer_sync_info.head_slot,
|
||||
peer_id,
|
||||
RangeSyncType::Head,
|
||||
beacon_processor_send,
|
||||
network,
|
||||
);
|
||||
}
|
||||
@@ -468,8 +462,7 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
target_head_slot: Slot,
|
||||
peer: PeerId,
|
||||
sync_type: RangeSyncType,
|
||||
beacon_processor_send: &mpsc::Sender<BeaconWorkEvent<T>>,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
) {
|
||||
let id = SyncingChain::<T>::id(&target_head_root, &target_head_slot);
|
||||
let (collection, is_finalized) = if let RangeSyncType::Finalized = sync_type {
|
||||
@@ -500,7 +493,6 @@ impl<T: BeaconChainTypes, C: BlockStorage> ChainCollection<T, C> {
|
||||
target_head_slot,
|
||||
target_head_root,
|
||||
peer,
|
||||
beacon_processor_send.clone(),
|
||||
is_finalized,
|
||||
&self.log,
|
||||
);
|
||||
|
||||
@@ -43,7 +43,6 @@ use super::block_storage::BlockStorage;
|
||||
use super::chain::{BatchId, ChainId, RemoveChain, SyncingChain};
|
||||
use super::chain_collection::ChainCollection;
|
||||
use super::sync_type::RangeSyncType;
|
||||
use crate::beacon_processor::WorkEvent as BeaconWorkEvent;
|
||||
use crate::status::ToStatusMessage;
|
||||
use crate::sync::manager::Id;
|
||||
use crate::sync::network_context::SyncNetworkContext;
|
||||
@@ -56,7 +55,6 @@ use lru_cache::LRUTimeCache;
|
||||
use slog::{crit, debug, trace, warn};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
|
||||
|
||||
/// For how long we store failed finalized chains to prevent retries.
|
||||
@@ -76,8 +74,6 @@ pub struct RangeSync<T: BeaconChainTypes, C = BeaconChain<T>> {
|
||||
chains: ChainCollection<T, C>,
|
||||
/// Chains that have failed and are stored to prevent being retried.
|
||||
failed_chains: LRUTimeCache<Hash256>,
|
||||
/// A multi-threaded, non-blocking processor for applying messages to the beacon chain.
|
||||
beacon_processor_send: mpsc::Sender<BeaconWorkEvent<T>>,
|
||||
/// The syncing logger.
|
||||
log: slog::Logger,
|
||||
}
|
||||
@@ -87,11 +83,7 @@ where
|
||||
C: BlockStorage + ToStatusMessage,
|
||||
T: BeaconChainTypes,
|
||||
{
|
||||
pub fn new(
|
||||
beacon_chain: Arc<C>,
|
||||
beacon_processor_send: mpsc::Sender<BeaconWorkEvent<T>>,
|
||||
log: slog::Logger,
|
||||
) -> Self {
|
||||
pub fn new(beacon_chain: Arc<C>, log: slog::Logger) -> Self {
|
||||
RangeSync {
|
||||
beacon_chain: beacon_chain.clone(),
|
||||
chains: ChainCollection::new(beacon_chain, log.clone()),
|
||||
@@ -99,7 +91,6 @@ where
|
||||
FAILED_CHAINS_EXPIRY_SECONDS,
|
||||
)),
|
||||
awaiting_head_peers: HashMap::new(),
|
||||
beacon_processor_send,
|
||||
log,
|
||||
}
|
||||
}
|
||||
@@ -117,7 +108,7 @@ where
|
||||
/// prioritised by peer-pool size.
|
||||
pub fn add_peer(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
local_info: SyncInfo,
|
||||
peer_id: PeerId,
|
||||
remote_info: SyncInfo,
|
||||
@@ -159,16 +150,11 @@ where
|
||||
remote_finalized_slot,
|
||||
peer_id,
|
||||
RangeSyncType::Finalized,
|
||||
&self.beacon_processor_send,
|
||||
network,
|
||||
);
|
||||
|
||||
self.chains.update(
|
||||
network,
|
||||
&local_info,
|
||||
&mut self.awaiting_head_peers,
|
||||
&self.beacon_processor_send,
|
||||
);
|
||||
self.chains
|
||||
.update(network, &local_info, &mut self.awaiting_head_peers);
|
||||
}
|
||||
RangeSyncType::Head => {
|
||||
// This peer requires a head chain sync
|
||||
@@ -197,15 +183,10 @@ where
|
||||
remote_info.head_slot,
|
||||
peer_id,
|
||||
RangeSyncType::Head,
|
||||
&self.beacon_processor_send,
|
||||
network,
|
||||
);
|
||||
self.chains.update(
|
||||
network,
|
||||
&local_info,
|
||||
&mut self.awaiting_head_peers,
|
||||
&self.beacon_processor_send,
|
||||
);
|
||||
self.chains
|
||||
.update(network, &local_info, &mut self.awaiting_head_peers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +197,7 @@ where
|
||||
/// This request could complete a chain or simply add to its progress.
|
||||
pub fn blocks_by_range_response(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
peer_id: PeerId,
|
||||
chain_id: ChainId,
|
||||
batch_id: BatchId,
|
||||
@@ -246,7 +227,7 @@ where
|
||||
|
||||
pub fn handle_block_process_result(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
chain_id: ChainId,
|
||||
batch_id: Epoch,
|
||||
result: BatchProcessResult,
|
||||
@@ -276,11 +257,7 @@ where
|
||||
|
||||
/// A peer has disconnected. This removes the peer from any ongoing chains and mappings. A
|
||||
/// disconnected peer could remove a chain
|
||||
pub fn peer_disconnect(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
peer_id: &PeerId,
|
||||
) {
|
||||
pub fn peer_disconnect(&mut self, network: &mut SyncNetworkContext<T>, peer_id: &PeerId) {
|
||||
// if the peer is in the awaiting head mapping, remove it
|
||||
self.awaiting_head_peers.remove(peer_id);
|
||||
|
||||
@@ -292,7 +269,7 @@ where
|
||||
/// which pool the peer is in. The chain may also have a batch or batches awaiting
|
||||
/// for this peer. If so we mark the batch as failed. The batch may then hit it's maximum
|
||||
/// retries. In this case, we need to remove the chain.
|
||||
fn remove_peer(&mut self, network: &mut SyncNetworkContext<T::EthSpec>, peer_id: &PeerId) {
|
||||
fn remove_peer(&mut self, network: &mut SyncNetworkContext<T>, peer_id: &PeerId) {
|
||||
for (removed_chain, sync_type, remove_reason) in self
|
||||
.chains
|
||||
.call_all(|chain| chain.remove_peer(peer_id, network))
|
||||
@@ -304,8 +281,6 @@ where
|
||||
network,
|
||||
"peer removed",
|
||||
);
|
||||
|
||||
// update the state of the collection
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +290,7 @@ where
|
||||
/// been too many failed attempts for the batch, remove the chain.
|
||||
pub fn inject_error(
|
||||
&mut self,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
peer_id: PeerId,
|
||||
batch_id: BatchId,
|
||||
chain_id: ChainId,
|
||||
@@ -347,7 +322,7 @@ where
|
||||
chain: SyncingChain<T>,
|
||||
sync_type: RangeSyncType,
|
||||
remove_reason: RemoveChain,
|
||||
network: &mut SyncNetworkContext<T::EthSpec>,
|
||||
network: &mut SyncNetworkContext<T>,
|
||||
op: &'static str,
|
||||
) {
|
||||
if remove_reason.is_critical() {
|
||||
@@ -374,12 +349,23 @@ where
|
||||
};
|
||||
|
||||
// update the state of the collection
|
||||
self.chains.update(
|
||||
network,
|
||||
&local,
|
||||
&mut self.awaiting_head_peers,
|
||||
&self.beacon_processor_send,
|
||||
);
|
||||
self.chains
|
||||
.update(network, &local, &mut self.awaiting_head_peers);
|
||||
}
|
||||
|
||||
/// Kickstarts sync.
|
||||
pub fn resume(&mut self, network: &mut SyncNetworkContext<T>) {
|
||||
for (removed_chain, sync_type, remove_reason) in
|
||||
self.chains.call_all(|chain| chain.resume(network))
|
||||
{
|
||||
self.on_chain_removed(
|
||||
removed_chain,
|
||||
sync_type,
|
||||
remove_reason,
|
||||
network,
|
||||
"chain resumed",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,13 +375,16 @@ mod tests {
|
||||
use crate::NetworkMessage;
|
||||
|
||||
use super::*;
|
||||
use crate::beacon_processor::WorkEvent as BeaconWorkEvent;
|
||||
use beacon_chain::builder::Witness;
|
||||
use beacon_chain::eth1_chain::CachingEth1Backend;
|
||||
use beacon_chain::parking_lot::RwLock;
|
||||
use beacon_chain::EngineState;
|
||||
use lighthouse_network::rpc::BlocksByRangeRequest;
|
||||
use lighthouse_network::Request;
|
||||
use lighthouse_network::{rpc::StatusMessage, NetworkGlobals};
|
||||
use slog::{o, Drain};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use slot_clock::SystemTimeSlotClock;
|
||||
use std::collections::HashSet;
|
||||
@@ -470,7 +459,7 @@ mod tests {
|
||||
/// To set up different scenarios where sync is told about known/unkown blocks.
|
||||
chain: Arc<FakeStorage>,
|
||||
/// Needed by range to handle communication with the network.
|
||||
cx: SyncNetworkContext<E>,
|
||||
cx: SyncNetworkContext<TestBeaconChainType>,
|
||||
/// To check what the network receives from Range.
|
||||
network_rx: mpsc::UnboundedReceiver<NetworkMessage<E>>,
|
||||
/// To modify what the network declares about various global variables, in particular about
|
||||
@@ -516,12 +505,13 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Reads an BlocksByRange request to a given peer from the network receiver channel.
|
||||
#[track_caller]
|
||||
fn grab_request(&mut self, expected_peer: &PeerId) -> (RequestId, BlocksByRangeRequest) {
|
||||
if let Some(NetworkMessage::SendRequest {
|
||||
if let Ok(NetworkMessage::SendRequest {
|
||||
peer_id,
|
||||
request: Request::BlocksByRange(request),
|
||||
request_id,
|
||||
}) = self.network_rx.blocking_recv()
|
||||
}) = self.network_rx.try_recv()
|
||||
{
|
||||
assert_eq!(&peer_id, expected_peer);
|
||||
(request_id, request)
|
||||
@@ -575,6 +565,29 @@ mod tests {
|
||||
let peer_id = PeerId::random();
|
||||
(peer_id, local_info, remote_info)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_empty_processor(&mut self) {
|
||||
match self.beacon_processor_rx.try_recv() {
|
||||
Ok(work) => {
|
||||
panic!("Expected empty processor. Instead got {}", work.work_type());
|
||||
}
|
||||
Err(e) => match e {
|
||||
mpsc::error::TryRecvError::Empty => {}
|
||||
mpsc::error::TryRecvError::Disconnected => unreachable!("bad coded test?"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_chain_segment(&mut self) {
|
||||
match self.beacon_processor_rx.try_recv() {
|
||||
Ok(work) => {
|
||||
assert_eq!(work.work_type(), crate::beacon_processor::CHAIN_SEGMENT);
|
||||
}
|
||||
other => panic!("Expected chain segment process, found {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn range(log_enabled: bool) -> (TestRig, RangeSync<TestBeaconChainType, FakeStorage>) {
|
||||
@@ -583,7 +596,6 @@ mod tests {
|
||||
let (beacon_processor_tx, beacon_processor_rx) = mpsc::channel(10);
|
||||
let range_sync = RangeSync::<TestBeaconChainType, FakeStorage>::new(
|
||||
chain.clone(),
|
||||
beacon_processor_tx,
|
||||
log.new(o!("component" => "range")),
|
||||
);
|
||||
let (network_tx, network_rx) = mpsc::unbounded_channel();
|
||||
@@ -591,6 +603,7 @@ mod tests {
|
||||
let cx = SyncNetworkContext::new(
|
||||
network_tx,
|
||||
globals.clone(),
|
||||
beacon_processor_tx,
|
||||
log.new(o!("component" => "network_context")),
|
||||
);
|
||||
let test_rig = TestRig {
|
||||
@@ -661,4 +674,53 @@ mod tests {
|
||||
let (finalized_peer, local_info, remote_info) = rig.finalized_peer();
|
||||
range.add_peer(&mut rig.cx, local_info, finalized_peer, remote_info);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pause_and_resume_on_ee_offline() {
|
||||
let (mut rig, mut range) = range(true);
|
||||
|
||||
// add some peers
|
||||
let (peer1, local_info, head_info) = rig.head_peer();
|
||||
range.add_peer(&mut rig.cx, local_info, peer1, head_info);
|
||||
let ((chain1, batch1), id1) = match rig.grab_request(&peer1).0 {
|
||||
RequestId::Sync(crate::sync::manager::RequestId::RangeSync { id }) => {
|
||||
(rig.cx.range_sync_response(id, true).unwrap(), id)
|
||||
}
|
||||
other => panic!("unexpected request {:?}", other),
|
||||
};
|
||||
|
||||
// make the ee offline
|
||||
rig.cx.update_execution_engine_state(EngineState::Offline);
|
||||
|
||||
// send the response to the request
|
||||
range.blocks_by_range_response(&mut rig.cx, peer1, chain1, batch1, id1, None);
|
||||
|
||||
// the beacon processor shouldn't have received any work
|
||||
rig.expect_empty_processor();
|
||||
|
||||
// while the ee is offline, more peers might arrive. Add a new finalized peer.
|
||||
let (peer2, local_info, finalized_info) = rig.finalized_peer();
|
||||
range.add_peer(&mut rig.cx, local_info, peer2, finalized_info);
|
||||
let ((chain2, batch2), id2) = match rig.grab_request(&peer2).0 {
|
||||
RequestId::Sync(crate::sync::manager::RequestId::RangeSync { id }) => {
|
||||
(rig.cx.range_sync_response(id, true).unwrap(), id)
|
||||
}
|
||||
other => panic!("unexpected request {:?}", other),
|
||||
};
|
||||
|
||||
// send the response to the request
|
||||
range.blocks_by_range_response(&mut rig.cx, peer2, chain2, batch2, id2, None);
|
||||
|
||||
// the beacon processor shouldn't have received any work
|
||||
rig.expect_empty_processor();
|
||||
|
||||
// make the beacon processor available again.
|
||||
rig.cx.update_execution_engine_state(EngineState::Online);
|
||||
|
||||
// now resume range, we should have two processing requests in the beacon processor.
|
||||
range.resume(&mut rig.cx);
|
||||
|
||||
rig.expect_chain_segment();
|
||||
rig.expect_chain_segment();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user