Skip to content

Commit a53307c

Browse files
authored
Merge pull request #787 from openmina/fix/vrf-next-epoch-seed
Add next epoch seed finality check in VRF evalutor
2 parents 1d3d155 + f9e443b commit a53307c

File tree

6 files changed

+51
-2
lines changed

6 files changed

+51
-2
lines changed

node/src/block_producer/block_producer_effects.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use mina_p2p_messages::v2::{
33
MinaStateSnarkTransitionValueStableV2, ProverExtendBlockchainInputStableV2,
44
};
55
use openmina_core::bug_condition;
6+
use openmina_core::consensus::in_seed_update_range;
67

78
use crate::account::AccountSecretKey;
89
use crate::ledger::write::{LedgerWriteAction, LedgerWriteRequest};
@@ -56,6 +57,7 @@ pub fn block_producer_effects<S: crate::Service>(
5657
};
5758
let next_epoch_first_slot = next_epoch_first_slot(&global_slot);
5859
let current_epoch = store.state().current_epoch();
60+
let current_slot = store.state().current_slot();
5961

6062
store.dispatch(BlockProducerVrfEvaluatorAction::InitializeEvaluator {
6163
best_tip: best_tip.clone(),
@@ -77,8 +79,15 @@ pub fn block_producer_effects<S: crate::Service>(
7779
}
7880
}
7981

82+
let is_next_epoch_seed_finalized = if let Some(current_slot) = current_slot {
83+
!in_seed_update_range(current_slot, best_tip.constants())
84+
} else {
85+
false
86+
};
87+
8088
store.dispatch(BlockProducerVrfEvaluatorAction::CheckEpochEvaluability {
8189
current_epoch,
90+
is_next_epoch_seed_finalized,
8291
root_block_epoch,
8392
best_tip_epoch,
8493
best_tip_slot,

node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_actions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub enum BlockProducerVrfEvaluatorAction {
4646
#[action_event(level = info, fields(current_epoch, best_tip_epoch, best_tip_slot, best_tip_global_slot))]
4747
CheckEpochEvaluability {
4848
current_epoch: Option<u32>,
49+
is_next_epoch_seed_finalized: bool,
4950
best_tip_epoch: u32,
5051
root_block_epoch: u32,
5152
best_tip_slot: u32,

node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_effects.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ impl BlockProducerVrfEvaluatorAction {
110110
best_tip_slot,
111111
next_epoch_first_slot,
112112
current_epoch: _,
113+
is_next_epoch_seed_finalized: _,
113114
staking_epoch_data: _,
114115
next_epoch_data: _,
115116
} => {

node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_reducer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl BlockProducerVrfEvaluatorState {
6565
}
6666
BlockProducerVrfEvaluatorAction::CheckEpochEvaluability {
6767
current_epoch,
68+
is_next_epoch_seed_finalized,
6869
best_tip_epoch,
6970
root_block_epoch,
7071
staking_epoch_data,
@@ -76,6 +77,7 @@ impl BlockProducerVrfEvaluatorState {
7677
self.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck {
7778
time: meta.time(),
7879
current_epoch: *current_epoch,
80+
is_next_epoch_seed_finalized: *is_next_epoch_seed_finalized,
7981
best_tip_epoch: *best_tip_epoch,
8082
root_block_epoch: *root_block_epoch,
8183
is_current_epoch_evaluated: self.is_epoch_evaluated(*best_tip_epoch),

node/src/block_producer/vrf_evaluator/block_producer_vrf_evaluator_state.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl BlockProducerVrfEvaluatorState {
9191
best_tip_epoch,
9292
root_block_epoch,
9393
current_epoch,
94+
is_next_epoch_seed_finalized,
9495
staking_epoch_data,
9596
next_epoch_data,
9697
..
@@ -111,7 +112,7 @@ impl BlockProducerVrfEvaluatorState {
111112
if !self.is_epoch_evaluated(best_tip_epoch) {
112113
self.epoch_context = EpochContext::Current((*staking_epoch_data).into())
113114
} else if !self.is_epoch_evaluated(best_tip_epoch + 1) {
114-
if root_block_epoch == best_tip_epoch {
115+
if root_block_epoch == best_tip_epoch && is_next_epoch_seed_finalized {
115116
self.epoch_context = EpochContext::Next((*next_epoch_data).into())
116117
} else {
117118
self.epoch_context = EpochContext::Waiting
@@ -495,6 +496,7 @@ pub enum BlockProducerVrfEvaluatorStatus {
495496
ReadinessCheck {
496497
time: redux::Timestamp,
497498
current_epoch: Option<u32>,
499+
is_next_epoch_seed_finalized: bool,
498500
best_tip_epoch: u32,
499501
root_block_epoch: u32,
500502
is_current_epoch_evaluated: bool,
@@ -658,6 +660,7 @@ mod test {
658660
best_tip_epoch: 0,
659661
is_current_epoch_evaluated: false,
660662
is_next_epoch_evaluated: false,
663+
is_next_epoch_seed_finalized: false,
661664
last_evaluated_epoch: None,
662665
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
663666
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
@@ -680,6 +683,7 @@ mod test {
680683
best_tip_epoch: 0,
681684
is_current_epoch_evaluated: true,
682685
is_next_epoch_evaluated: false,
686+
is_next_epoch_seed_finalized: true,
683687
last_evaluated_epoch: Some(0),
684688
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
685689
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
@@ -702,6 +706,7 @@ mod test {
702706
best_tip_epoch: 0,
703707
is_current_epoch_evaluated: true,
704708
is_next_epoch_evaluated: true,
709+
is_next_epoch_seed_finalized: true,
705710
last_evaluated_epoch: Some(1),
706711
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
707712
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
@@ -724,6 +729,7 @@ mod test {
724729
best_tip_epoch: 2,
725730
is_current_epoch_evaluated: false,
726731
is_next_epoch_evaluated: false,
732+
is_next_epoch_seed_finalized: false,
727733
last_evaluated_epoch: None,
728734
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
729735
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
@@ -747,6 +753,7 @@ mod test {
747753
is_current_epoch_evaluated: true,
748754
is_next_epoch_evaluated: false,
749755
last_evaluated_epoch: Some(2),
756+
is_next_epoch_seed_finalized: false,
750757
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
751758
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
752759
},
@@ -804,6 +811,7 @@ mod test {
804811
#[test]
805812
fn generic_epoch_correctly_switch_to_next_epoch() {
806813
// Staking ledger not yet materialized (wait k=290 blocks)
814+
// The epoch seed is not finalized yet
807815
let mut vrf_evaluator_state = SECOND_EPOCH_CURRENT_EPOCH_EVALUATED_WAIT_FOR_NEXT
808816
.lock()
809817
.unwrap();
@@ -815,13 +823,15 @@ mod test {
815823

816824
// Epoch has changed but the root is still from the previous epoch.
817825
// Next epoch must not be evaluated yet.
826+
// The epoch seed is not finalized yet.
818827
vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck {
819828
time: redux::Timestamp::global_now(),
820829
current_epoch: Some(2), // TODO(adonagy)
821830
root_block_epoch: 1,
822831
best_tip_epoch: 2,
823832
is_current_epoch_evaluated: true,
824833
is_next_epoch_evaluated: false,
834+
is_next_epoch_seed_finalized: false,
825835
last_evaluated_epoch: Some(2),
826836
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
827837
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
@@ -834,14 +844,36 @@ mod test {
834844
));
835845

836846
// Epoch has changed, and the root is already at that epoch too.
837-
// Next epoch must be evaluated now.
847+
// The epoch seed is still not finalized.
838848
vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck {
839849
time: redux::Timestamp::global_now(),
840850
current_epoch: Some(2), // TODO(adonagy)
841851
root_block_epoch: 2,
842852
best_tip_epoch: 2,
843853
is_current_epoch_evaluated: true,
844854
is_next_epoch_evaluated: false,
855+
is_next_epoch_seed_finalized: false,
856+
last_evaluated_epoch: Some(2),
857+
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
858+
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),
859+
};
860+
861+
vrf_evaluator_state.set_epoch_context();
862+
assert!(matches!(
863+
vrf_evaluator_state.epoch_context(),
864+
EpochContext::Waiting
865+
));
866+
867+
// Epoch has changed, and the root is already at that epoch too.
868+
// The epoch seed is also finalized.
869+
vrf_evaluator_state.status = BlockProducerVrfEvaluatorStatus::ReadinessCheck {
870+
time: redux::Timestamp::global_now(),
871+
current_epoch: Some(2), // TODO(adonagy)
872+
root_block_epoch: 2,
873+
best_tip_epoch: 2,
874+
is_current_epoch_evaluated: true,
875+
is_next_epoch_evaluated: false,
876+
is_next_epoch_seed_finalized: true,
845877
last_evaluated_epoch: Some(2),
846878
staking_epoch_data: Box::new(DUMMY_STAKING_EPOCH_DATA.to_owned()),
847879
next_epoch_data: Box::new(DUMMY_NEXT_EPOCH_DATA.to_owned()),

node/src/state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ impl State {
281281
self.cur_slot(|b| b.global_slot())
282282
}
283283

284+
pub fn current_slot(&self) -> Option<u32> {
285+
self.cur_slot(|b| b.global_slot() % b.constants().slots_per_epoch.as_u32())
286+
}
287+
284288
pub fn cur_global_slot_since_genesis(&self) -> Option<u32> {
285289
self.cur_slot(|b| b.global_slot_since_genesis())
286290
}

0 commit comments

Comments
 (0)