-
Notifications
You must be signed in to change notification settings - Fork 26
refactor: represent slot intervals with enum #496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||||||
| use std::collections::{HashMap, HashSet, VecDeque}; | ||||||||||
| use std::fmt; | ||||||||||
| use std::time::{Duration, Instant, SystemTime}; | ||||||||||
|
|
||||||||||
| use ethlambda_network_api::{BlockChainToP2PRef, InitP2P}; | ||||||||||
|
|
@@ -59,6 +60,44 @@ pub use ethlambda_types::block::MAX_ATTESTATIONS_DATA; | |||||||||
| /// See: leanSpec PR #682. | ||||||||||
| pub const GOSSIP_DISPARITY_INTERVALS: u64 = 1; | ||||||||||
|
|
||||||||||
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||||||||||
| pub(crate) enum SlotInterval { | ||||||||||
| BlockPublication, | ||||||||||
| AttestationProduction, | ||||||||||
| Aggregation, | ||||||||||
| SafeTargetUpdate, | ||||||||||
| EndOfSlot, | ||||||||||
| } | ||||||||||
|
|
||||||||||
| impl SlotInterval { | ||||||||||
| pub(crate) fn from_slot_index(index: u64) -> Self { | ||||||||||
| match index { | ||||||||||
| 0 => Self::BlockPublication, | ||||||||||
| 1 => Self::AttestationProduction, | ||||||||||
| 2 => Self::Aggregation, | ||||||||||
| 3 => Self::SafeTargetUpdate, | ||||||||||
| 4 => Self::EndOfSlot, | ||||||||||
| _ => unreachable!("slots only have 5 intervals"), | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| fn as_slot_index(self) -> u64 { | ||||||||||
| match self { | ||||||||||
| Self::BlockPublication => 0, | ||||||||||
| Self::AttestationProduction => 1, | ||||||||||
| Self::Aggregation => 2, | ||||||||||
| Self::SafeTargetUpdate => 3, | ||||||||||
| Self::EndOfSlot => 4, | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| impl fmt::Display for SlotInterval { | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is unused, we should just remove it |
||||||||||
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||||||
| self.as_slot_index().fmt(f) | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /// Milliseconds until the next interval boundary, measured relative to genesis. | ||||||||||
| fn ms_until_next_interval(now_ms: u64, genesis_time_ms: u64) -> u64 { | ||||||||||
| // Before genesis: wait until genesis itself. | ||||||||||
|
|
@@ -192,7 +231,9 @@ impl BlockChainServer { | |||||||||
| // Calculate current slot and interval from milliseconds | ||||||||||
| let time_since_genesis_ms = timestamp_ms.saturating_sub(genesis_time_ms); | ||||||||||
| let slot = time_since_genesis_ms / MILLISECONDS_PER_SLOT; | ||||||||||
| let interval = (time_since_genesis_ms % MILLISECONDS_PER_SLOT) / MILLISECONDS_PER_INTERVAL; | ||||||||||
| let interval = SlotInterval::from_slot_index( | ||||||||||
| (time_since_genesis_ms % MILLISECONDS_PER_SLOT) / MILLISECONDS_PER_INTERVAL, | ||||||||||
| ); | ||||||||||
|
Comment on lines
+234
to
+236
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, for example, we could do:
Suggested change
|
||||||||||
|
|
||||||||||
| // Idempotency guard | ||||||||||
| // | ||||||||||
|
|
@@ -252,15 +293,15 @@ impl BlockChainServer { | |||||||||
| // needs (those stragglers surface in the `late` section instead). Skip | ||||||||||
| // empty snapshots so a missed round keeps the last set we saw. Pure | ||||||||||
| // observability. | ||||||||||
| if interval == 4 | ||||||||||
| if interval == SlotInterval::EndOfSlot | ||||||||||
| && let Some(snapshot) = coverage::snapshot_new_payloads(&self.store) | ||||||||||
| { | ||||||||||
| self.pre_merge_coverage = Some(snapshot); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Whether one of our validators proposes this slot. Drives the store's | ||||||||||
| // interval-0 attestation acceptance. | ||||||||||
| let is_proposer = (interval == 0 && slot > 0) | ||||||||||
| let is_proposer = (interval == SlotInterval::BlockPublication && slot > 0) | ||||||||||
| .then(|| self.get_our_proposer(slot)) | ||||||||||
| .flatten() | ||||||||||
| .is_some(); | ||||||||||
|
|
@@ -280,14 +321,14 @@ impl BlockChainServer { | |||||||||
| // advances the store to this slot's interval 0 before building (see | ||||||||||
| // `propose_block`). The real interval-0 tick is then skipped by the | ||||||||||
| // idempotency guard above, since the store clock is already here. | ||||||||||
| 0 => {} | ||||||||||
| SlotInterval::BlockPublication => {} | ||||||||||
|
|
||||||||||
| // ==== interval 1 ==== | ||||||||||
| // | ||||||||||
| // Produce attestations at interval 1 (all validators including | ||||||||||
| // proposer). Reuse the same snapshot so self-delivery decisions | ||||||||||
| // match the rest of the tick. | ||||||||||
| 1 => { | ||||||||||
| SlotInterval::AttestationProduction => { | ||||||||||
| // Emit the post-block coverage report for the previous slot. | ||||||||||
| // Fired at interval 1 (not 0) so the block carrying `slot - 1`'s | ||||||||||
| // votes β proposed at interval 0 of this slot β has typically | ||||||||||
|
|
@@ -309,7 +350,7 @@ impl BlockChainServer { | |||||||||
| } | ||||||||||
|
|
||||||||||
| // ==== interval 2 ==== | ||||||||||
| 2 => { | ||||||||||
| SlotInterval::Aggregation => { | ||||||||||
| if is_aggregator { | ||||||||||
| coverage::emit_agg_start_new_coverage( | ||||||||||
| &self.store, | ||||||||||
|
|
@@ -324,7 +365,7 @@ impl BlockChainServer { | |||||||||
| // ==== interval 3 ==== | ||||||||||
| // | ||||||||||
| // Safe-target update is handled inside `store::on_tick`. | ||||||||||
| 3 => {} | ||||||||||
| SlotInterval::SafeTargetUpdate => {} | ||||||||||
|
|
||||||||||
| // ==== interval 4 ==== | ||||||||||
| // | ||||||||||
|
|
@@ -335,7 +376,7 @@ impl BlockChainServer { | |||||||||
| // rather than stashing it for the interval-0 tick β keeps it robust: | ||||||||||
| // `on_tick` skips the interval-0 tick whenever this build overruns | ||||||||||
| // its interval. | ||||||||||
| 4 => { | ||||||||||
| SlotInterval::EndOfSlot => { | ||||||||||
| let next_slot = slot + 1; | ||||||||||
| let next_proposer = self | ||||||||||
| .get_our_proposer(next_slot) | ||||||||||
|
|
@@ -345,8 +386,6 @@ impl BlockChainServer { | |||||||||
| self.propose_block(next_slot, validator_id).await; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| _ => {} | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Update safe target slot metric (updated by store.on_tick at interval 3) | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,7 +18,7 @@ use tracing::{info, trace, warn}; | |||||
|
|
||||||
| use crate::{ | ||||||
| GOSSIP_DISPARITY_INTERVALS, INTERVALS_PER_SLOT, MAX_ATTESTATIONS_DATA, | ||||||
| MILLISECONDS_PER_INTERVAL, MILLISECONDS_PER_SLOT, | ||||||
| MILLISECONDS_PER_INTERVAL, MILLISECONDS_PER_SLOT, SlotInterval, | ||||||
| block_builder::{PostBlockCheckpoints, ProposerConfig, build_block}, | ||||||
| metrics, | ||||||
| }; | ||||||
|
|
@@ -278,7 +278,7 @@ pub fn on_tick(store: &mut Store, timestamp_ms: u64, has_proposal: bool) { | |||||
| .expect("set_time should succeed"); | ||||||
|
|
||||||
| let slot = store.time() / INTERVALS_PER_SLOT; | ||||||
| let interval = store.time() % INTERVALS_PER_SLOT; | ||||||
| let interval = SlotInterval::from_slot_index(store.time() % INTERVALS_PER_SLOT); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And here:
Suggested change
|
||||||
|
|
||||||
| trace!(%slot, %interval, "processing tick"); | ||||||
|
|
||||||
|
|
@@ -292,27 +292,26 @@ pub fn on_tick(store: &mut Store, timestamp_ms: u64, has_proposal: bool) { | |||||
| // the actor's message loop stays unblocked during the expensive XMSS | ||||||
| // proofs. See `BlockChainServer::start_aggregation_session` in `lib.rs`. | ||||||
| match interval { | ||||||
| 0 => { | ||||||
| SlotInterval::BlockPublication => { | ||||||
| // Start of slot - process attestations if proposal exists | ||||||
| if should_signal_proposal { | ||||||
| accept_new_attestations(store, false); | ||||||
| } | ||||||
| } | ||||||
| 1 => { | ||||||
| SlotInterval::AttestationProduction => { | ||||||
| // Vote propagation β no action | ||||||
| } | ||||||
| 2 => { | ||||||
| SlotInterval::Aggregation => { | ||||||
| // Aggregation is driven by the actor (off-thread); nothing to do here. | ||||||
| } | ||||||
| 3 => { | ||||||
| SlotInterval::SafeTargetUpdate => { | ||||||
| // Update safe target for validators | ||||||
| update_safe_target(store); | ||||||
| } | ||||||
| 4 => { | ||||||
| SlotInterval::EndOfSlot => { | ||||||
| // End of slot - accept accumulated attestations and log tree | ||||||
| accept_new_attestations(store, true); | ||||||
| } | ||||||
| _ => unreachable!("slots only have 5 intervals"), | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If possible, we should give only
current time in ms -> SlotIntervalandcurrent time in intervals -> SlotIntervalconstructors, so that callers don't have to compute the interval themselves. That way we centralize the logic in this enum