Replace INTERVALS_PER_SLOT with explicit slot component times (#7944)

https://github.com/ethereum/consensus-specs/pull/4476


  


Co-Authored-By: Barnabas Busa <barnabas.busa@ethereum.org>

Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>

Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>

Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com>

Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Eitan Seri-Levi
2026-02-01 21:58:42 -08:00
committed by GitHub
parent cd8049a696
commit 3ecf964385
56 changed files with 579 additions and 184 deletions

View File

@@ -476,9 +476,9 @@ impl<T: SlotClock> BeaconNodeFallback<T> {
}
let timeouts: Timeouts = if new_list.len() == 1 || use_long_timeouts {
Timeouts::set_all(Duration::from_secs(self.spec.seconds_per_slot))
Timeouts::set_all(self.spec.get_slot_duration())
} else {
Timeouts::use_optimized_timeouts(Duration::from_secs(self.spec.seconds_per_slot))
Timeouts::use_optimized_timeouts(self.spec.get_slot_duration())
};
let new_candidates: Vec<CandidateBeaconNode> = new_list

View File

@@ -268,7 +268,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
let beacon_node_setup = |x: (usize, &SensitiveUrl)| {
let i = x.0;
let url = x.1;
let slot_duration = Duration::from_secs(context.eth2_config.spec.seconds_per_slot);
let slot_duration = context.eth2_config.spec.get_slot_duration();
let mut beacon_node_http_client_builder = ClientBuilder::new();
@@ -389,7 +389,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
let slot_clock = SystemTimeSlotClock::new(
context.eth2_config.spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_secs(context.eth2_config.spec.seconds_per_slot),
context.eth2_config.spec.get_slot_duration(),
);
beacon_nodes.set_slot_clock(slot_clock.clone());

View File

@@ -144,7 +144,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> AttestationService<S,
return Ok(());
}
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let slot_duration = spec.get_slot_duration();
let duration_to_next_slot = self
.slot_clock
.duration_to_next_slot()
@@ -157,12 +157,14 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> AttestationService<S,
let executor = self.executor.clone();
let unaggregated_attestation_due = self.chain_spec.get_unaggregated_attestation_due();
let interval_fut = async move {
loop {
if let Some(duration_to_next_slot) = self.slot_clock.duration_to_next_slot() {
sleep(duration_to_next_slot + slot_duration / 3).await;
sleep(duration_to_next_slot + unaggregated_attestation_due).await;
if let Err(e) = self.spawn_attestation_tasks(slot_duration) {
if let Err(e) = self.spawn_attestation_tasks() {
crit!(error = e, "Failed to spawn attestation tasks")
} else {
trace!("Spawned attestation tasks");
@@ -183,7 +185,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> AttestationService<S,
/// Spawn only one new task for attestation post-Electra
/// For each required aggregates, spawn a new task that downloads, signs and uploads the
/// aggregates to the beacon node.
fn spawn_attestation_tasks(&self, slot_duration: Duration) -> Result<(), String> {
fn spawn_attestation_tasks(&self) -> Result<(), String> {
let slot = self.slot_clock.now().ok_or("Failed to read slot clock")?;
let duration_to_next_slot = self
.slot_clock
@@ -247,7 +249,8 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> AttestationService<S,
// through the slot. This delay triggers at this time
let aggregate_production_instant = Instant::now()
+ duration_to_next_slot
.checked_sub(slot_duration / 3)
.checked_add(self.chain_spec.get_aggregate_attestation_due())
.and_then(|offset| offset.checked_sub(self.chain_spec.get_slot_duration()))
.unwrap_or_else(|| Duration::from_secs(0));
let aggregate_duties_by_committee_index: HashMap<CommitteeIndex, Vec<DutyAndProof>> = self

View File

@@ -2,7 +2,7 @@ use crate::duties_service::DutiesService;
use slot_clock::SlotClock;
use std::sync::Arc;
use task_executor::TaskExecutor;
use tokio::time::{Duration, sleep};
use tokio::time::sleep;
use tracing::{debug, error, info};
use types::{ChainSpec, EthSpec};
use validator_metrics::set_gauge;
@@ -14,7 +14,7 @@ pub fn spawn_notifier<S: ValidatorStore + 'static, T: SlotClock + 'static>(
executor: TaskExecutor,
spec: &ChainSpec,
) -> Result<(), String> {
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let slot_duration = spec.get_slot_duration();
let interval_fut = async move {
loop {

View File

@@ -8,7 +8,7 @@ use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use task_executor::TaskExecutor;
use tokio::time::{Duration, sleep};
use tokio::time::sleep;
use tracing::{debug, error, info, warn};
use types::{
Address, ChainSpec, EthSpec, ProposerPreparationData, SignedValidatorRegistrationData,
@@ -174,7 +174,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> PreparationService<S,
/// Starts the service which periodically produces proposer preparations.
pub fn start_proposer_prepare_service(self, spec: &ChainSpec) -> Result<(), String> {
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let slot_duration = spec.get_slot_duration();
info!("Proposer preparation service started");
let executor = self.executor.clone();
@@ -214,7 +214,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> PreparationService<S,
info!("Validator registration service started");
let spec = spec.clone();
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let slot_duration = spec.get_slot_duration();
let executor = self.executor.clone();

View File

@@ -93,7 +93,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> SyncCommitteeService<S
return Ok(());
}
let slot_duration = Duration::from_secs(spec.seconds_per_slot);
let slot_duration = spec.get_slot_duration();
let duration_to_next_slot = self
.slot_clock
.duration_to_next_slot()
@@ -106,18 +106,20 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> SyncCommitteeService<S
let executor = self.executor.clone();
let sync_message_slot_component = spec.get_sync_message_due();
let interval_fut = async move {
loop {
if let Some(duration_to_next_slot) = self.slot_clock.duration_to_next_slot() {
// Wait for contribution broadcast interval 1/3 of the way through the slot.
sleep(duration_to_next_slot + slot_duration / 3).await;
sleep(duration_to_next_slot + sync_message_slot_component).await;
// Do nothing if the Altair fork has not yet occurred.
if !self.altair_fork_activated() {
continue;
}
if let Err(e) = self.spawn_contribution_tasks(slot_duration).await {
if let Err(e) = self.spawn_contribution_tasks().await {
crit!(
error = ?e,
"Failed to spawn sync contribution tasks"
@@ -140,7 +142,8 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> SyncCommitteeService<S
Ok(())
}
async fn spawn_contribution_tasks(&self, slot_duration: Duration) -> Result<(), String> {
async fn spawn_contribution_tasks(&self) -> Result<(), String> {
let spec = &self.duties_service.spec;
let slot = self.slot_clock.now().ok_or("Failed to read slot clock")?;
let duration_to_next_slot = self
.slot_clock
@@ -151,7 +154,8 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> SyncCommitteeService<S
// through the slot. This delay triggers at this time
let aggregate_production_instant = Instant::now()
+ duration_to_next_slot
.checked_sub(slot_duration / 3)
.checked_add(spec.get_contribution_message_due())
.and_then(|offset| offset.checked_sub(spec.get_slot_duration()))
.unwrap_or_else(|| Duration::from_secs(0));
let Some(slot_duties) = self