Represent slots in secs instead of millisecs (#2163)

## Issue Addressed

NA

## Proposed Changes

Copied from #2083, changes the config milliseconds_per_slot to seconds_per_slot to avoid errors when slot duration is not a multiple of a second. To avoid deserializing old serialized data (with milliseconds instead of seconds) the Serialize and Deserialize derive got removed from the Spec struct (isn't currently used anyway).

This PR replaces #2083 for the purpose of fixing a merge conflict without requiring the input of @blacktemplar.

## Additional Info

NA


Co-authored-by: blacktemplar <blacktemplar@a1.net>
This commit is contained in:
Paul Hauner 2021-01-19 09:39:51 +00:00
parent 46cb6e204c
commit d9f940613f
24 changed files with 58 additions and 132 deletions

1
Cargo.lock generated
View File

@ -1913,7 +1913,6 @@ version = "0.2.0"
dependencies = [
"serde",
"serde_derive",
"toml",
"types",
]

View File

@ -257,7 +257,7 @@ fn get_current_epoch<E: EthSpec>(genesis_time: u64, spec: &ChainSpec) -> Option<
let slot_clock = SystemTimeSlotClock::new(
spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_millis(spec.milliseconds_per_slot),
Duration::from_secs(spec.seconds_per_slot),
);
slot_clock.now().map(|s| s.epoch(E::slots_per_epoch()))
}

View File

@ -639,7 +639,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let start_slot = head_state.slot;
let task_start = Instant::now();
let max_task_runtime = Duration::from_millis(self.spec.milliseconds_per_slot);
let max_task_runtime = Duration::from_secs(self.spec.seconds_per_slot);
let head_state_slot = head_state.slot;
let mut state = head_state;

View File

@ -90,7 +90,7 @@ fn get_sync_status<T: EthSpec>(
let period_start = slot_start_seconds::<T>(
genesis_time,
spec.milliseconds_per_slot,
spec.seconds_per_slot,
voting_period_start_slot,
);
@ -98,7 +98,7 @@ fn get_sync_status<T: EthSpec>(
} else {
// The number of seconds in an eth1 voting period.
let voting_period_duration =
T::slots_per_eth1_voting_period() as u64 * (spec.milliseconds_per_slot / 1_000);
T::slots_per_eth1_voting_period() as u64 * spec.seconds_per_slot;
let now = SystemTime::now().duration_since(UNIX_EPOCH).ok()?.as_secs();
@ -454,7 +454,7 @@ impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
let voting_period_start_slot = (state.slot / period) * period;
let voting_period_start_seconds = slot_start_seconds::<T>(
state.genesis_time,
spec.milliseconds_per_slot,
spec.seconds_per_slot,
voting_period_start_slot,
);
@ -645,10 +645,10 @@ fn int_to_bytes32(int: u64) -> Vec<u8> {
/// Returns the unix-epoch seconds at the start of the given `slot`.
fn slot_start_seconds<T: EthSpec>(
genesis_unix_seconds: u64,
milliseconds_per_slot: u64,
seconds_per_slot: u64,
slot: Slot,
) -> u64 {
genesis_unix_seconds + slot.as_u64() * milliseconds_per_slot / 1_000
genesis_unix_seconds + slot.as_u64() * seconds_per_slot
}
/// Returns a boolean denoting if a given `Eth1Block` is a candidate for `Eth1Data` calculation
@ -686,7 +686,7 @@ mod test {
let voting_period_start_slot = (state.slot / period) * period;
slot_start_seconds::<E>(
state.genesis_time,
spec.milliseconds_per_slot,
spec.seconds_per_slot,
voting_period_start_slot,
)
}
@ -696,21 +696,21 @@ mod test {
let zero_sec = 0;
assert_eq!(slot_start_seconds::<E>(100, zero_sec, Slot::new(2)), 100);
let half_sec = 500;
assert_eq!(slot_start_seconds::<E>(100, half_sec, Slot::new(0)), 100);
assert_eq!(slot_start_seconds::<E>(100, half_sec, Slot::new(1)), 100);
assert_eq!(slot_start_seconds::<E>(100, half_sec, Slot::new(2)), 101);
assert_eq!(slot_start_seconds::<E>(100, half_sec, Slot::new(3)), 101);
let one_sec = 1_000;
let one_sec = 1;
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(0)), 100);
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(1)), 101);
assert_eq!(slot_start_seconds::<E>(100, one_sec, Slot::new(2)), 102);
let three_sec = 3_000;
let three_sec = 3;
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(0)), 100);
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(1)), 103);
assert_eq!(slot_start_seconds::<E>(100, three_sec, Slot::new(2)), 106);
let five_sec = 5;
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(0)), 100);
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(1)), 105);
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(2)), 110);
assert_eq!(slot_start_seconds::<E>(100, five_sec, Slot::new(3)), 115);
}
fn get_eth1_block(timestamp: u64, number: u64) -> Eth1Block {

View File

@ -322,13 +322,13 @@ where
.beacon_chain
.clone()
.ok_or("node timer requires a beacon chain")?;
let milliseconds_per_slot = self
let seconds_per_slot = self
.chain_spec
.as_ref()
.ok_or("node timer requires a chain spec")?
.milliseconds_per_slot;
.seconds_per_slot;
spawn_timer(context.executor, beacon_chain, milliseconds_per_slot)
spawn_timer(context.executor, beacon_chain, seconds_per_slot)
.map_err(|e| format!("Unable to start node timer: {}", e))?;
Ok(self)
@ -381,17 +381,17 @@ where
.network_globals
.clone()
.ok_or("slot_notifier requires a libp2p network")?;
let milliseconds_per_slot = self
let seconds_per_slot = self
.chain_spec
.as_ref()
.ok_or("slot_notifier requires a chain spec")?
.milliseconds_per_slot;
.seconds_per_slot;
spawn_notifier(
context.executor,
beacon_chain,
network_globals,
milliseconds_per_slot,
seconds_per_slot,
)
.map_err(|e| format!("Unable to start slot notifier: {}", e))?;
@ -685,7 +685,7 @@ where
let slot_clock = SystemTimeSlotClock::new(
spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_millis(spec.milliseconds_per_slot),
Duration::from_secs(spec.seconds_per_slot),
);
self.slot_clock = Some(slot_clock);

View File

@ -25,9 +25,9 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
executor: task_executor::TaskExecutor,
beacon_chain: Arc<BeaconChain<T>>,
network: Arc<NetworkGlobals<T::EthSpec>>,
milliseconds_per_slot: u64,
seconds_per_slot: u64,
) -> Result<(), String> {
let slot_duration = Duration::from_millis(milliseconds_per_slot);
let slot_duration = Duration::from_secs(seconds_per_slot);
let duration_to_next_slot = beacon_chain
.slot_clock
.duration_to_next_slot()

View File

@ -360,7 +360,7 @@ impl Config {
pub fn set_block_cache_truncation<E: EthSpec>(&mut self, spec: &ChainSpec) {
// Compute the number of eth1 blocks in an eth1 voting period.
let seconds_per_voting_period =
E::SlotsPerEth1VotingPeriod::to_u64() * spec.milliseconds_per_slot / 1000;
E::SlotsPerEth1VotingPeriod::to_u64() * spec.seconds_per_slot;
let eth1_blocks_per_voting_period = seconds_per_voting_period / spec.seconds_per_eth1_block;
// Compute the number of extra blocks we store prior to the voting period start blocks.
@ -1200,8 +1200,7 @@ mod tests {
let len = config.block_cache_truncation.unwrap();
let seconds_per_voting_period =
<MainnetEthSpec as EthSpec>::SlotsPerEth1VotingPeriod::to_u64()
* (spec.milliseconds_per_slot / 1000);
<MainnetEthSpec as EthSpec>::SlotsPerEth1VotingPeriod::to_u64() * spec.seconds_per_slot;
let eth1_blocks_per_voting_period = seconds_per_voting_period / spec.seconds_per_eth1_block;
let reduce_follow_distance_blocks =
config.follow_distance / ETH1_BLOCK_TIME_TOLERANCE_FACTOR;

View File

@ -37,7 +37,7 @@ pub struct PeerScoreSettings<TSpec: EthSpec> {
impl<TSpec: EthSpec> PeerScoreSettings<TSpec> {
pub fn new(chain_spec: &ChainSpec, gs_config: &GossipsubConfig) -> PeerScoreSettings<TSpec> {
let slot = Duration::from_millis(chain_spec.milliseconds_per_slot);
let slot = Duration::from_millis(chain_spec.seconds_per_slot);
let beacon_attestation_subnet_weight = 1.0 / chain_spec.attestation_subnet_count as f64;
let max_positive_score = (MAX_IN_MESH_SCORE + MAX_FIRST_MESSAGE_DELIVERIES_SCORE)
* (BEACON_BLOCK_WEIGHT

View File

@ -32,7 +32,7 @@ const LAST_SEEN_VALIDATOR_TIMEOUT: u32 = 150;
// 30 mins at a 12s slot time
/// The fraction of a slot that we subscribe to a subnet before the required slot.
///
/// Note: The time is calculated as `time = milliseconds_per_slot / ADVANCE_SUBSCRIPTION_TIME`.
/// Note: The time is calculated as `time = seconds_per_slot / ADVANCE_SUBSCRIPTION_TIME`.
const ADVANCE_SUBSCRIBE_TIME: u32 = 3;
/// The default number of slots before items in hash delay sets used by this class should expire.
/// 36s at 12s slot time

View File

@ -269,7 +269,7 @@ fn spawn_service<T: BeaconChainTypes>(
_ = service.metrics_update.next() => {
// update various network metrics
metric_update_counter +=1;
if metric_update_counter* 1000 % T::EthSpec::default_spec().milliseconds_per_slot == 0 {
if metric_update_counter % T::EthSpec::default_spec().seconds_per_slot == 0 {
// if a slot has occurred, reset the metrics
let _ = metrics::ATTESTATIONS_PUBLISHED_PER_SUBNET_PER_SLOT
.as_ref()

View File

@ -14,7 +14,7 @@ use tokio::time::{interval_at, Instant};
pub fn spawn_timer<T: BeaconChainTypes>(
executor: task_executor::TaskExecutor,
beacon_chain: Arc<BeaconChain<T>>,
milliseconds_per_slot: u64,
seconds_per_slot: u64,
) -> Result<(), &'static str> {
let log = executor.log();
let start_instant = Instant::now()
@ -23,8 +23,8 @@ pub fn spawn_timer<T: BeaconChainTypes>(
.duration_to_next_slot()
.ok_or("slot_notifier unable to determine time to next slot")?;
// Warning: `interval_at` panics if `milliseconds_per_slot` = 0.
let mut interval = interval_at(start_instant, Duration::from_millis(milliseconds_per_slot));
// Warning: `interval_at` panics if `seconds_per_slot` = 0.
let mut interval = interval_at(start_instant, Duration::from_secs(seconds_per_slot));
let timer_future = async move {
while interval.next().await.is_some() {
beacon_chain.per_slot_task();

View File

@ -7,5 +7,4 @@ edition = "2018"
[dependencies]
serde = "1.0.116"
serde_derive = "1.0.116"
toml = "0.5.6"
types = { path = "../../consensus/types" }

View File

@ -1,4 +1,3 @@
use serde_derive::{Deserialize, Serialize};
use std::env;
use std::path::PathBuf;
use types::{ChainSpec, EthSpecId};
@ -16,8 +15,7 @@ pub const GENESIS_FILE_NAME: &str = "genesis.ssz";
pub const GENESIS_ZIP_FILE_NAME: &str = "genesis.ssz.zip";
/// The core configuration of a Lighthouse beacon node.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
#[derive(Debug, Clone)]
pub struct Eth2Config {
pub eth_spec_id: EthSpecId,
pub spec: ChainSpec,
@ -125,15 +123,3 @@ define_net!(pyrmont, include_pyrmont_file, "pyrmont", true);
define_net!(mainnet, include_mainnet_file, "mainnet", true);
define_net!(toledo, include_toledo_file, "toledo", true);
#[cfg(test)]
mod tests {
use super::*;
use toml;
#[test]
fn serde_serialize() {
let _ =
toml::to_string(&Eth2Config::default()).expect("Should serde encode default config");
}
}

View File

@ -9,9 +9,9 @@ lazy_static! {
try_create_int_gauge("slotclock_present_epoch", "The present wall-clock epoch");
pub static ref SLOTS_PER_EPOCH: Result<IntGauge> =
try_create_int_gauge("slotclock_slots_per_epoch", "Slots per epoch (constant)");
pub static ref MILLISECONDS_PER_SLOT: Result<IntGauge> = try_create_int_gauge(
"slotclock_slot_time_milliseconds",
"The duration in milliseconds between each slot"
pub static ref SECONDS_PER_SLOT: Result<IntGauge> = try_create_int_gauge(
"slotclock_slot_time_seconds",
"The duration in seconds between each slot"
);
}
@ -28,8 +28,5 @@ pub fn scrape_for_metrics<T: EthSpec, U: SlotClock>(clock: &U) {
present_slot.epoch(T::slots_per_epoch()).as_u64() as i64,
);
set_gauge(&SLOTS_PER_EPOCH, T::slots_per_epoch() as i64);
set_gauge(
&MILLISECONDS_PER_SLOT,
clock.slot_duration().as_millis() as i64,
);
set_gauge(&SECONDS_PER_SLOT, clock.slot_duration().as_secs() as i64);
}

View File

@ -23,14 +23,12 @@ pub enum Domain {
///
/// Spec v0.12.1
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
#[derive(PartialEq, Debug, Clone)]
pub struct ChainSpec {
/*
* Constants
*/
pub genesis_slot: Slot,
#[serde(skip_serializing)] // skipped because Serde TOML has trouble with u64::max
pub far_future_epoch: Epoch,
pub base_rewards_per_epoch: u64,
pub deposit_contract_tree_depth: u64,
@ -61,16 +59,14 @@ pub struct ChainSpec {
/*
* Initial Values
*/
#[serde(with = "serde_utils::bytes_4_hex")]
pub genesis_fork_version: [u8; 4],
#[serde(with = "serde_utils::u8_hex")]
pub bls_withdrawal_prefix_byte: u8,
/*
* Time parameters
*/
pub genesis_delay: u64,
pub milliseconds_per_slot: u64,
pub seconds_per_slot: u64,
pub min_attestation_inclusion_delay: u64,
pub min_seed_lookahead: Epoch,
pub max_seed_lookahead: Epoch,
@ -283,7 +279,7 @@ impl ChainSpec {
* Time parameters
*/
genesis_delay: 604800, // 7 days
milliseconds_per_slot: 12_000,
seconds_per_slot: 12,
min_attestation_inclusion_delay: 1,
min_seed_lookahead: Epoch::new(1),
max_seed_lookahead: Epoch::new(4),
@ -359,7 +355,7 @@ impl ChainSpec {
genesis_fork_version: [0x00, 0x00, 0x00, 0x01],
shard_committee_period: 64,
genesis_delay: 300,
milliseconds_per_slot: 6_000,
seconds_per_slot: 6,
inactivity_penalty_quotient: u64::pow(2, 25),
min_slashing_penalty_quotient: 64,
proportional_slashing_multiplier: 2,
@ -588,11 +584,6 @@ impl Default for YamlConfig {
}
}
#[allow(clippy::integer_arithmetic)] // Arith cannot overflow or panic.
fn milliseconds_to_seconds(millis: u64) -> u64 {
millis / 1000
}
/// Spec v0.12.1
impl YamlConfig {
/// Maps `self.config_name` to an identifier for an `EthSpec` instance.
@ -632,7 +623,7 @@ impl YamlConfig {
hysteresis_upward_multiplier: spec.hysteresis_upward_multiplier,
proportional_slashing_multiplier: spec.proportional_slashing_multiplier,
bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte,
seconds_per_slot: milliseconds_to_seconds(spec.milliseconds_per_slot),
seconds_per_slot: spec.seconds_per_slot,
min_attestation_inclusion_delay: spec.min_attestation_inclusion_delay,
min_seed_lookahead: spec.min_seed_lookahead.into(),
max_seed_lookahead: spec.max_seed_lookahead.into(),
@ -754,7 +745,7 @@ impl YamlConfig {
* Time parameters
*/
genesis_delay: self.genesis_delay,
milliseconds_per_slot: self.seconds_per_slot.saturating_mul(1000),
seconds_per_slot: self.seconds_per_slot,
min_attestation_inclusion_delay: self.min_attestation_inclusion_delay,
min_seed_lookahead: Epoch::from(self.min_seed_lookahead),
max_seed_lookahead: Epoch::from(self.max_seed_lookahead),

View File

@ -1,42 +0,0 @@
spec_constants = "minimal" # for testing
[spec]
genesis_slot = 0
base_rewards_per_epoch = 4
deposit_contract_tree_depth = 32
max_committees_per_slot = 64
target_committee_size = 128
min_per_epoch_churn_limit = 4
churn_limit_quotient = 65536
shuffle_round_count = 90
min_genesis_active_validator_count = 16384
min_genesis_time = 1578009600
min_deposit_amount = 1000000000
max_effective_balance = 32000000000
ejection_balance = 16000000000
effective_balance_increment = 1000000000
genesis_fork_version = "0x00000000"
bls_withdrawal_prefix_byte = "0x00"
genesis_delay = 300
milliseconds_per_slot = 12000
min_attestation_inclusion_delay = 1
min_seed_lookahead = 1
max_seed_lookahead = 4
min_epochs_to_inactivity_penalty = 4
min_validator_withdrawability_delay = 256
shard_committee_period = 2048
base_reward_factor = 64
whistleblower_reward_quotient = 512
proposer_reward_quotient = 8
inactivity_penalty_quotient = 33554432
min_slashing_penalty_quotient = 32
domain_beacon_proposer = 0
domain_beacon_attester = 1
domain_randao = 2
domain_deposit = 3
domain_voluntary_exit = 4
safe_slots_to_update_justified = 8
eth1_follow_distance = 1024
seconds_per_eth1_block = 14
boot_nodes = []
network_id = 1

View File

@ -58,16 +58,15 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
let total_validator_count = validators_per_node * node_count;
spec.milliseconds_per_slot /= speed_up_factor;
//currently lighthouse only supports slot lengths that are multiples of seconds
spec.milliseconds_per_slot = max(1000, spec.milliseconds_per_slot / 1000 * 1000);
spec.seconds_per_slot /= speed_up_factor;
spec.seconds_per_slot = max(1, spec.seconds_per_slot);
spec.eth1_follow_distance = 16;
spec.genesis_delay = eth1_block_time.as_secs() * spec.eth1_follow_distance * 2;
spec.min_genesis_time = 0;
spec.min_genesis_active_validator_count = total_validator_count as u64;
spec.seconds_per_eth1_block = 1;
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let initial_validator_count = spec.min_genesis_active_validator_count as usize;
let deposit_amount = env.eth2_config.spec.max_effective_balance;

View File

@ -55,9 +55,8 @@ pub fn run_no_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
let total_validator_count = validators_per_node * node_count;
spec.milliseconds_per_slot /= speed_up_factor;
//currently lighthouse only supports slot lengths that are multiples of seconds
spec.milliseconds_per_slot = max(1000, spec.milliseconds_per_slot / 1000 * 1000);
spec.seconds_per_slot /= speed_up_factor;
spec.seconds_per_slot = max(1, spec.seconds_per_slot);
spec.eth1_follow_distance = 16;
spec.genesis_delay = eth1_block_time.as_secs() * spec.eth1_follow_distance * 2;
spec.min_genesis_time = 0;
@ -71,7 +70,7 @@ pub fn run_no_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
+ genesis_delay;
let genesis_instant = Instant::now() + genesis_delay;
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let context = env.core_context();

View File

@ -53,9 +53,8 @@ fn syncing_sim(
let end_after_checks = true;
let eth1_block_time = Duration::from_millis(15_000 / speed_up_factor);
spec.milliseconds_per_slot /= speed_up_factor;
//currently lighthouse only supports slot lengths that are multiples of seconds
spec.milliseconds_per_slot = max(1000, spec.milliseconds_per_slot / 1000 * 1000);
spec.seconds_per_slot /= speed_up_factor;
spec.seconds_per_slot = max(1, spec.seconds_per_slot);
spec.eth1_follow_distance = 16;
spec.genesis_delay = eth1_block_time.as_secs() * spec.eth1_follow_distance * 2;
spec.min_genesis_time = 0;
@ -63,7 +62,7 @@ fn syncing_sim(
spec.seconds_per_eth1_block = 1;
let num_validators = 8;
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let context = env.core_context();
let mut beacon_config = testing_client_config();

View File

@ -126,7 +126,7 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
pub fn start_update_service(self, spec: &ChainSpec) -> Result<(), String> {
let log = self.context.log().clone();
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let duration_to_next_slot = self
.slot_clock
.duration_to_next_slot()

View File

@ -466,7 +466,7 @@ impl<T: SlotClock + 'static, E: EthSpec> DutiesService<T, E> {
.ok_or("Unable to determine duration to next slot")?;
let mut interval = {
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
// Note: `interval_at` panics if `slot_duration` is 0
interval_at(
Instant::now() + duration_to_next_slot + TIME_DELAY_FROM_SLOT,

View File

@ -148,7 +148,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ForkService<T, E> {
.ok_or("Unable to determine duration to next epoch")?;
let mut interval = {
let slot_duration = Duration::from_millis(spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
// Note: interval_at panics if `slot_duration * E::slots_per_epoch()` = 0
interval_at(
Instant::now() + duration_to_next_epoch + TIME_DELAY_FROM_SLOT,

View File

@ -248,7 +248,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
let slot_clock = SystemTimeSlotClock::new(
context.eth2_config.spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot),
Duration::from_secs(context.eth2_config.spec.seconds_per_slot),
);
beacon_nodes.set_slot_clock(slot_clock.clone());

View File

@ -11,7 +11,7 @@ pub fn spawn_notifier<T: EthSpec>(client: &ProductionValidatorClient<T>) -> Resu
let executor = context.executor.clone();
let duties_service = client.duties_service.clone();
let slot_duration = Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot);
let slot_duration = Duration::from_secs(context.eth2_config.spec.seconds_per_slot);
let duration_to_next_slot = duties_service
.slot_clock
.duration_to_next_slot()