diff --git a/node/src/block_producer/block_producer_effects.rs b/node/src/block_producer/block_producer_effects.rs index a48d27106b..66bca390a4 100644 --- a/node/src/block_producer/block_producer_effects.rs +++ b/node/src/block_producer/block_producer_effects.rs @@ -3,6 +3,7 @@ use mina_p2p_messages::v2::{ MinaStateSnarkTransitionValueStableV2, ProverExtendBlockchainInputStableV2, }; use openmina_core::bug_condition; +use openmina_core::consensus::in_seed_update_range; use crate::account::AccountSecretKey; use crate::ledger::write::{LedgerWriteAction, LedgerWriteRequest}; @@ -56,6 +57,7 @@ pub fn block_producer_effects( }; let next_epoch_first_slot = next_epoch_first_slot(&global_slot); let current_epoch = store.state().current_epoch(); + let current_slot = store.state().current_slot(); store.dispatch(BlockProducerVrfEvaluatorAction::InitializeEvaluator { best_tip: best_tip.clone(), @@ -77,8 +79,15 @@ pub fn block_producer_effects( } } + let is_next_epoch_seed_finalized = if let Some(current_slot) = current_slot { + !in_seed_update_range(current_slot, best_tip.constants()) + } else { + false + }; + store.dispatch(BlockProducerVrfEvaluatorAction::CheckEpochEvaluability { current_epoch, + is_next_epoch_seed_finalized, root_block_epoch, best_tip_epoch, best_tip_slot, diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs index 6d2f337b1a..9a1afb2c6d 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs @@ -46,6 +46,7 @@ pub enum BlockProducerVrfEvaluatorAction { #[action_event(level = info, fields(current_epoch, best_tip_epoch, best_tip_slot, best_tip_global_slot))] CheckEpochEvaluability { current_epoch: Option, + is_next_epoch_seed_finalized: bool, best_tip_epoch: u32, root_block_epoch: u32, best_tip_slot: u32, diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs index 181fafe410..f174780c41 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs @@ -110,6 +110,7 @@ impl BlockProducerVrfEvaluatorAction { best_tip_slot, next_epoch_first_slot, current_epoch: _, + is_next_epoch_seed_finalized: _, staking_epoch_data: _, next_epoch_data: _, } => { diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs index 7a36d7948f..37b53fb660 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs @@ -65,6 +65,7 @@ impl BlockProducerVrfEvaluatorState { } BlockProducerVrfEvaluatorAction::CheckEpochEvaluability { current_epoch, + is_next_epoch_seed_finalized, best_tip_epoch, root_block_epoch, staking_epoch_data, @@ -76,6 +77,7 @@ impl BlockProducerVrfEvaluatorState { self.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: meta.time(), current_epoch: *current_epoch, + is_next_epoch_seed_finalized: *is_next_epoch_seed_finalized, best_tip_epoch: *best_tip_epoch, root_block_epoch: *root_block_epoch, is_current_epoch_evaluated: self.is_epoch_evaluated(*best_tip_epoch), diff --git a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs index fefb7fc24a..78c0b34b32 100644 --- a/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs +++ b/node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs @@ -91,6 +91,7 @@ impl BlockProducerVrfEvaluatorState { best_tip_epoch, root_block_epoch, current_epoch, + is_next_epoch_seed_finalized, staking_epoch_data, next_epoch_data, .. @@ -111,7 +112,7 @@ impl BlockProducerVrfEvaluatorState { if !self.is_epoch_evaluated(best_tip_epoch) { self.epoch_context = EpochContext::Current((*staking_epoch_data).into()) } else if !self.is_epoch_evaluated(best_tip_epoch + 1) { - if root_block_epoch == best_tip_epoch { + if root_block_epoch == best_tip_epoch && is_next_epoch_seed_finalized { self.epoch_context = EpochContext::Next((*next_epoch_data).into()) } else { self.epoch_context = EpochContext::Waiting @@ -495,6 +496,7 @@ pub enum BlockProducerVrfEvaluatorStatus { ReadinessCheck { time: redux::Timestamp, current_epoch: Option, + is_next_epoch_seed_finalized: bool, best_tip_epoch: u32, root_block_epoch: u32, is_current_epoch_evaluated: bool, @@ -658,6 +660,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: false, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: None, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -680,6 +683,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(0), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -702,6 +706,7 @@ mod test { best_tip_epoch: 0, is_current_epoch_evaluated: true, is_next_epoch_evaluated: true, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(1), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -724,6 +729,7 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: false, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: None, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -747,6 +753,7 @@ mod test { is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, last_evaluated_epoch: Some(2), + is_next_epoch_seed_finalized: false, staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), }, @@ -804,6 +811,7 @@ mod test { #[test] fn generic_epoch_correctly_switch_to_next_epoch() { // Staking ledger not yet materialized (wait k=290 blocks) + // The epoch seed is not finalized yet let mut vrf_evaluator_state = SECOND_EPOCH_CURRENT_EPOCH_EVALUATED_WAIT_FOR_NEXT .lock() .unwrap(); @@ -815,6 +823,7 @@ mod test { // Epoch has changed but the root is still from the previous epoch. // Next epoch must not be evaluated yet. + // The epoch seed is not finalized yet. vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: redux::Timestamp::global_now(), current_epoch: Some(2), // TODO(adonagy) @@ -822,6 +831,7 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, last_evaluated_epoch: Some(2), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), @@ -834,7 +844,7 @@ mod test { )); // Epoch has changed, and the root is already at that epoch too. - // Next epoch must be evaluated now. + // The epoch seed is still not finalized. vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { time: redux::Timestamp::global_now(), current_epoch: Some(2), // TODO(adonagy) @@ -842,6 +852,28 @@ mod test { best_tip_epoch: 2, is_current_epoch_evaluated: true, is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: false, + last_evaluated_epoch: Some(2), + staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), + next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), + }; + + vrf_evaluator_state.set_epoch_context(); + assert!(matches!( + vrf_evaluator_state.epoch_context(), + EpochContext::Waiting + )); + + // Epoch has changed, and the root is already at that epoch too. + // The epoch seed is also finalized. + vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck { + time: redux::Timestamp::global_now(), + current_epoch: Some(2), // TODO(adonagy) + root_block_epoch: 2, + best_tip_epoch: 2, + is_current_epoch_evaluated: true, + is_next_epoch_evaluated: false, + is_next_epoch_seed_finalized: true, last_evaluated_epoch: Some(2), staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()), next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()), diff --git a/node/src/state.rs b/node/src/state.rs index 4430b42fd4..97ba9984e7 100644 --- a/node/src/state.rs +++ b/node/src/state.rs @@ -256,6 +256,10 @@ impl State { self.cur_slot(|b| b.global_slot()) } + pub fn current_slot(&self) -> Option { + self.cur_slot(|b| b.global_slot() % b.constants().slots_per_epoch.as_u32()) + } + pub fn cur_global_slot_since_genesis(&self) -> Option { self.cur_slot(|b| b.global_slot_since_genesis()) }