Allow validator client to start before genesis

This commit is contained in:
Paul Hauner 2019-09-06 10:03:45 +10:00
parent 940ddd0d13
commit 8b69a48fc5
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
5 changed files with 48 additions and 37 deletions

View File

@ -178,7 +178,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
genesis_state.genesis_time, genesis_state.genesis_time,
Duration::from_millis(spec.milliseconds_per_slot), Duration::from_millis(spec.milliseconds_per_slot),
) )
.ok_or_else(|| Error::SlotClockDidNotStart)?; .map_err(|_| Error::SlotClockDidNotStart)?;
info!(log, "Beacon chain initialized from genesis"; info!(log, "Beacon chain initialized from genesis";
"validator_count" => genesis_state.validators.len(), "validator_count" => genesis_state.validators.len(),
@ -220,7 +220,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
state.genesis_time, state.genesis_time,
Duration::from_millis(spec.milliseconds_per_slot), Duration::from_millis(spec.milliseconds_per_slot),
) )
.ok_or_else(|| Error::SlotClockDidNotStart)?; .map_err(|_| Error::SlotClockDidNotStart)?;
let last_finalized_root = p.canonical_head.beacon_state.finalized_checkpoint.root; let last_finalized_root = p.canonical_head.beacon_state.finalized_checkpoint.root;
let last_finalized_block = &p.canonical_head.beacon_block; let last_finalized_block = &p.canonical_head.beacon_block;

View File

@ -16,7 +16,7 @@ use slog::{crit, error, info, o};
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use tokio::runtime::TaskExecutor; use tokio::runtime::TaskExecutor;
use tokio::timer::Interval; use tokio::timer::Interval;
use types::EthSpec; use types::EthSpec;
@ -177,8 +177,18 @@ where
.map_err(error::Error::from)?, .map_err(error::Error::from)?,
); );
if beacon_chain.slot().is_err() { let since_epoch = SystemTime::now()
panic!("Cannot start client before genesis!") .duration_since(UNIX_EPOCH)
.map_err(|e| format!("Unable to read system time: {}", e))?;
let since_genesis = Duration::from_secs(beacon_chain.head().beacon_state.genesis_time);
if since_genesis > since_epoch {
info!(
log,
"Starting node prior to genesis";
"now" => since_epoch.as_secs(),
"genesis_seconds" => since_genesis.as_secs(),
);
} }
let network_config = &client_config.network; let network_config = &client_config.network;

View File

@ -5,7 +5,7 @@ mod metrics;
mod system_time_slot_clock; mod system_time_slot_clock;
mod testing_slot_clock; mod testing_slot_clock;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use std::time::{Duration, Instant, SystemTime, SystemTimeError, UNIX_EPOCH};
pub use crate::system_time_slot_clock::SystemTimeSlotClock; pub use crate::system_time_slot_clock::SystemTimeSlotClock;
pub use crate::testing_slot_clock::TestingSlotClock; pub use crate::testing_slot_clock::TestingSlotClock;
@ -17,18 +17,21 @@ pub trait SlotClock: Send + Sync + Sized {
genesis_slot: Slot, genesis_slot: Slot,
genesis_seconds: u64, genesis_seconds: u64,
slot_duration: Duration, slot_duration: Duration,
) -> Option<Self> { ) -> Result<Self, SystemTimeError> {
let duration_between_now_and_unix_epoch = let duration_between_now_and_unix_epoch = SystemTime::now().duration_since(UNIX_EPOCH)?;
SystemTime::now().duration_since(UNIX_EPOCH).ok()?;
let duration_between_unix_epoch_and_genesis = Duration::from_secs(genesis_seconds); let duration_between_unix_epoch_and_genesis = Duration::from_secs(genesis_seconds);
if duration_between_now_and_unix_epoch < duration_between_unix_epoch_and_genesis { let genesis_instant = if duration_between_now_and_unix_epoch
None < duration_between_unix_epoch_and_genesis
{
Instant::now()
+ (duration_between_unix_epoch_and_genesis - duration_between_now_and_unix_epoch)
} else { } else {
let genesis_instant = Instant::now() Instant::now()
- (duration_between_now_and_unix_epoch - duration_between_unix_epoch_and_genesis); - (duration_between_now_and_unix_epoch - duration_between_unix_epoch_and_genesis)
Some(Self::new(genesis_slot, genesis_instant, slot_duration)) };
}
Ok(Self::new(genesis_slot, genesis_instant, slot_duration))
} }
fn new(genesis_slot: Slot, genesis: Instant, slot_duration: Duration) -> Self; fn new(genesis_slot: Slot, genesis: Instant, slot_duration: Duration) -> Self;

View File

@ -42,7 +42,7 @@ impl SlotClock for SystemTimeSlotClock {
fn duration_to_next_slot(&self) -> Option<Duration> { fn duration_to_next_slot(&self) -> Option<Duration> {
let now = Instant::now(); let now = Instant::now();
if now < self.genesis { if now < self.genesis {
None Some(self.genesis - now)
} else { } else {
let duration_since_genesis = now - self.genesis; let duration_since_genesis = now - self.genesis;
let millis_since_genesis = duration_since_genesis.as_millis(); let millis_since_genesis = duration_since_genesis.as_millis();

View File

@ -27,7 +27,7 @@ use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use std::sync::RwLock; use std::sync::RwLock;
use std::time::{Duration, Instant, SystemTime}; use std::time::{Duration, Instant};
use tokio::prelude::*; use tokio::prelude::*;
use tokio::runtime::Builder; use tokio::runtime::Builder;
use tokio::timer::Interval; use tokio::timer::Interval;
@ -100,19 +100,6 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B,
continue; continue;
} }
Ok(info) => { Ok(info) => {
// verify the node's genesis time
if SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
< info.genesis_time
{
error!(
log,
"Beacon Node's genesis time is in the future. No work to do.\n Exiting"
);
return Err("Genesis time in the future".into());
}
// verify the node's network id // verify the node's network id
if eth2_config.spec.network_id != info.network_id as u8 { if eth2_config.spec.network_id != info.network_id as u8 {
error!( error!(
@ -177,13 +164,11 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B,
genesis_time, genesis_time,
Duration::from_millis(eth2_config.spec.milliseconds_per_slot), Duration::from_millis(eth2_config.spec.milliseconds_per_slot),
) )
.ok_or_else::<error_chain::Error, _>(|| { .map_err::<error_chain::Error, _>(|e| {
"Unable to start slot clock. Genesis may not have occurred yet. Exiting.".into() format!("Unable to start slot clock: {}.", e).into()
})?; })?;
let current_slot = slot_clock.now().ok_or_else::<error_chain::Error, _>(|| { let current_slot = slot_clock.now().unwrap_or_else(|| Slot::new(0));
"Genesis has not yet occurred. Exiting.".into()
})?;
/* Generate the duties manager */ /* Generate the duties manager */
@ -237,7 +222,7 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B,
let mut service = Service::<ValidatorServiceClient, Keypair, E>::initialize_service( let mut service = Service::<ValidatorServiceClient, Keypair, E>::initialize_service(
client_config, client_config,
eth2_config, eth2_config,
log, log.clone(),
)?; )?;
// we have connected to a node and established its parameters. Spin up the core service // we have connected to a node and established its parameters. Spin up the core service
@ -253,7 +238,7 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B,
.slot_clock .slot_clock
.duration_to_next_slot() .duration_to_next_slot()
.ok_or_else::<error_chain::Error, _>(|| { .ok_or_else::<error_chain::Error, _>(|| {
"Genesis is not in the past. Exiting.".into() "Unable to determine duration to next slot. Exiting.".into()
})?; })?;
// set up the validator work interval - start at next slot and proceed every slot // set up the validator work interval - start at next slot and proceed every slot
@ -264,6 +249,19 @@ impl<B: BeaconNodeDuties + 'static, S: Signer + 'static, E: EthSpec> Service<B,
Interval::new(Instant::now() + duration_to_next_slot, slot_duration) Interval::new(Instant::now() + duration_to_next_slot, slot_duration)
}; };
if service.slot_clock.now().is_none() {
warn!(
log,
"Starting node prior to genesis";
);
}
info!(
log,
"Waiting for next slot";
"seconds_to_wait" => duration_to_next_slot.as_secs()
);
/* kick off the core service */ /* kick off the core service */
runtime.block_on( runtime.block_on(
interval interval