Add testing for beacon node and validator client CLI flags (#2311)

## Issue Addressed

N/A

## Proposed Changes

Add unit tests for the various CLI flags associated with the beacon node and validator client. These changes require the addition of two new flags: `dump-config` and `immediate-shutdown`.

## Additional Info

Both `dump-config` and `immediate-shutdown` are marked as hidden since they should only be used in testing and other advanced use cases.
**Note:** This requires changing `main.rs` so that the flags can adjust the program behavior as necessary.

Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
Mac L
2021-05-06 00:36:22 +00:00
parent 4cc613d644
commit bacc38c3da
16 changed files with 1327 additions and 47 deletions

View File

@@ -58,6 +58,7 @@ use std::sync::Arc;
use std::time::{Duration, Instant};
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
use store::{Error as DBError, HotColdDB, KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp};
use task_executor::ShutdownReason;
use types::beacon_state::CloneConfig;
use types::*;
@@ -254,7 +255,7 @@ pub struct BeaconChain<T: BeaconChainTypes> {
pub disabled_forks: Vec<String>,
/// Sender given to tasks, so that if they encounter a state in which execution cannot
/// continue they can request that everything shuts down.
pub shutdown_sender: Sender<&'static str>,
pub shutdown_sender: Sender<ShutdownReason>,
/// Logging to CLI, etc.
pub(crate) log: Logger,
/// Arbitrary bytes included in the blocks.
@@ -1699,7 +1700,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
"error" => ?e,
);
crit!(self.log, "You must use the `--purge-db` flag to clear the database and restart sync. You may be on a hostile network.");
shutdown_sender.try_send("Weak subjectivity checkpoint verification failed. Provided block root is not a checkpoint.")
shutdown_sender
.try_send(ShutdownReason::Failure(
"Weak subjectivity checkpoint verification failed. Provided block root is not a checkpoint."
))
.map_err(|err| BlockError::BeaconChainError(BeaconChainError::WeakSubjectivtyShutdownError(err)))?;
return Err(BlockError::WeakSubjectivityConflict);
}
@@ -2811,7 +2815,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
/// Get a channel to request shutting down.
pub fn shutdown_sender(&self) -> Sender<&'static str> {
pub fn shutdown_sender(&self) -> Sender<ShutdownReason> {
self.shutdown_sender.clone()
}

View File

@@ -25,6 +25,7 @@ use std::marker::PhantomData;
use std::sync::Arc;
use std::time::Duration;
use store::{HotColdDB, ItemStore};
use task_executor::ShutdownReason;
use types::{
BeaconBlock, BeaconState, ChainSpec, EthSpec, Graffiti, Hash256, PublicKeyBytes, Signature,
SignedBeaconBlock, Slot,
@@ -75,7 +76,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
eth1_chain: Option<Eth1Chain<T::Eth1Chain, T::EthSpec>>,
event_handler: Option<ServerSentEventHandler<T::EthSpec>>,
slot_clock: Option<T::SlotClock>,
shutdown_sender: Option<Sender<&'static str>>,
shutdown_sender: Option<Sender<ShutdownReason>>,
head_tracker: Option<HeadTracker>,
validator_pubkey_cache: Option<ValidatorPubkeyCache<T>>,
spec: ChainSpec,
@@ -349,7 +350,7 @@ where
}
/// Sets a `Sender` to allow the beacon chain to send shutdown signals.
pub fn shutdown_sender(mut self, sender: Sender<&'static str>) -> Self {
pub fn shutdown_sender(mut self, sender: Sender<ShutdownReason>) -> Self {
self.shutdown_sender = Some(sender);
self
}

View File

@@ -21,6 +21,7 @@ use state_processing::{
BlockProcessingError, SlotProcessingError,
};
use std::time::Duration;
use task_executor::ShutdownReason;
use types::*;
macro_rules! easy_from_to {
@@ -96,7 +97,7 @@ pub enum BeaconChainError {
head_block_epoch: Epoch,
},
WeakSubjectivtyVerificationFailure,
WeakSubjectivtyShutdownError(TrySendError<&'static str>),
WeakSubjectivtyShutdownError(TrySendError<ShutdownReason>),
AttestingPriorToHead {
head_slot: Slot,
request_slot: Slot,

View File

@@ -25,6 +25,7 @@ use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::time::Duration;
use store::{config::StoreConfig, BlockReplay, HotColdDB, ItemStore, LevelDB, MemoryStore};
use task_executor::ShutdownReason;
use tempfile::{tempdir, TempDir};
use tree_hash::TreeHash;
use types::{
@@ -115,7 +116,7 @@ pub struct BeaconChainHarness<T: BeaconChainTypes> {
pub chain: BeaconChain<T>,
pub spec: ChainSpec,
pub data_dir: TempDir,
pub shutdown_receiver: Receiver<&'static str>,
pub shutdown_receiver: Receiver<ShutdownReason>,
pub rng: Mutex<StdRng>,
}

View File

@@ -44,7 +44,7 @@ pub fn build_log(level: slog::Level, enabled: bool) -> slog::Logger {
// A bit of hack to find an unused port.
///
/// Does not guarantee that the given port is unused after the function exists, just that it was
/// Does not guarantee that the given port is unused after the function exits, just that it was
/// unused before the function started (i.e., it does not reserve a port).
pub fn unused_port(transport: &str) -> Result<u16, String> {
let local_addr = match transport {

View File

@@ -16,6 +16,7 @@ use futures::prelude::*;
use slog::{debug, error, info, o, trace, warn};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use store::HotColdDB;
use task_executor::ShutdownReason;
use tokio::sync::mpsc;
use tokio::time::Sleep;
use types::{EthSpec, RelativeEpoch, SubnetId, Unsigned, ValidatorSubscription};
@@ -522,10 +523,14 @@ fn spawn_service<T: BeaconChainTypes>(
service.network_globals.listen_multiaddrs.write().push(multiaddr);
}
Libp2pEvent::ZeroListeners => {
let _ = shutdown_sender.send("All listeners are closed. Unable to listen").await.map_err(|e| {
warn!(service.log, "failed to send a shutdown signal"; "error" => %e
)
});
let _ = shutdown_sender
.send(ShutdownReason::Failure("All listeners are closed. Unable to listen"))
.await
.map_err(|e| warn!(
service.log,
"failed to send a shutdown signal";
"error" => %e
));
}
}
}

View File

@@ -643,7 +643,7 @@ pub fn get_eth2_network_config(cli_args: &ArgMatches) -> Result<Eth2NetworkConfi
/// A bit of hack to find an unused port.
///
/// Does not guarantee that the given port is unused after the function exists, just that it was
/// Does not guarantee that the given port is unused after the function exits, just that it was
/// unused before the function started (i.e., it does not reserve a port).
///
/// Used for passing unused ports to libp2 so that lighthouse won't have to update