Skip to content

Commit 21f4ffd

Browse files
committed
fix(block_producer)
re: #124
1 parent 8b7f38f commit 21f4ffd

File tree

7 files changed

+93
-74
lines changed

7 files changed

+93
-74
lines changed

node/native/src/block_producer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod vrf_evaluator;
22

33
use mina_signer::Keypair;
4-
use node::{core::channels::mpsc, block_producer::vrf_evaluator::VrfEvaluatorInput};
4+
use node::{block_producer::vrf_evaluator::VrfEvaluatorInput, core::channels::mpsc};
55

66
use crate::NodeService;
77

node/native/src/block_producer/vrf_evaluator.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use mina_signer::Keypair;
2-
use node::{block_producer::{BlockProducerEvent, vrf_evaluator::VrfEvaluatorInput}, event_source::Event};
2+
use node::{
3+
block_producer::{vrf_evaluator::VrfEvaluatorInput, BlockProducerEvent},
4+
event_source::Event,
5+
};
36
use openmina_core::channels::mpsc::{UnboundedReceiver, UnboundedSender};
47
use vrf::{VrfEvaluationInput, VrfEvaluationOutput};
58

node/src/block_producer/block_producer_actions.rs

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -66,32 +66,10 @@ impl redux::EnablingCondition<crate::State> for BlockProducerWonSlotAction {
6666
let Some(best_tip) = state.transition_frontier.best_tip() else {
6767
return false;
6868
};
69-
let is_won_slot_old = |won_slot: &BlockProducerWonSlot| {
70-
best_tip.global_slot() > won_slot.global_slot_since_genesis.as_u32()
71-
};
7269

73-
state.time() < self.won_slot.next_slot_time()
74-
&& is_won_slot_old(&self.won_slot)
75-
&& this
76-
.current
77-
.won_slot()
78-
.filter(|won_slot| !is_won_slot_old(won_slot))
79-
.map_or(true, |won_slot| {
80-
match self
81-
.won_slot
82-
.global_slot_since_genesis
83-
.as_u32()
84-
.cmp(&won_slot.global_slot_since_genesis.as_u32())
85-
{
86-
// old won_slot is further in the future, pick new one instead.
87-
Ordering::Less => true,
88-
Ordering::Equal => &self.won_slot > won_slot,
89-
// new won_slot is further in the future. Ignore it.
90-
Ordering::Greater => false,
91-
}
92-
})
93-
// TODO(binier): do we need to check if staking epoch ledger for an
94-
// existing won slot is still current best tip's staking epoch ledger.
70+
this.current.won_slot_should_search()
71+
&& state.time() < self.won_slot.next_slot_time()
72+
&& self.won_slot.global_slot_since_genesis.as_u32() >= best_tip.global_slot()
9573
})
9674
}
9775
}
@@ -113,7 +91,7 @@ pub struct BlockProducerWonSlotProduceInitAction {}
11391
impl redux::EnablingCondition<crate::State> for BlockProducerWonSlotProduceInitAction {
11492
fn is_enabled(&self, state: &crate::State) -> bool {
11593
state.block_producer.with(false, |this| {
116-
this.current.won_slot().is_some() && !this.current.won_slot_should_wait(state.time())
94+
this.current.won_slot_should_produce(state.time())
11795
})
11896
}
11997
}
@@ -199,10 +177,7 @@ pub struct BlockProducerBlockInjectAction {}
199177
impl redux::EnablingCondition<crate::State> for BlockProducerBlockInjectAction {
200178
fn is_enabled(&self, state: &crate::State) -> bool {
201179
state.block_producer.with(false, |this| {
202-
matches!(
203-
this.current,
204-
BlockProducerCurrentState::BlockUnprovenBuilt { .. }
205-
)
180+
matches!(this.current, BlockProducerCurrentState::Produced { .. })
206181
})
207182
}
208183
}
@@ -213,10 +188,7 @@ pub struct BlockProducerBlockInjectedAction {}
213188
impl redux::EnablingCondition<crate::State> for BlockProducerBlockInjectedAction {
214189
fn is_enabled(&self, state: &crate::State) -> bool {
215190
state.block_producer.with(false, |this| {
216-
matches!(
217-
this.current,
218-
BlockProducerCurrentState::BlockUnprovenBuilt { .. }
219-
)
191+
matches!(this.current, BlockProducerCurrentState::Produced { .. })
220192
})
221193
}
222194
}
@@ -228,7 +200,11 @@ pub struct BlockProducerWonSlotDiscardAction {
228200

229201
impl redux::EnablingCondition<crate::State> for BlockProducerWonSlotDiscardAction {
230202
fn is_enabled(&self, state: &crate::State) -> bool {
231-
todo!("validate reason")
203+
let reason = state.block_producer.with(None, |bp| {
204+
let best_tip = state.transition_frontier.best_tip()?;
205+
bp.current.won_slot_should_discard(best_tip)
206+
});
207+
Some(&self.reason) == reason.as_ref()
232208
}
233209
}
234210

node/src/block_producer/block_producer_effects.rs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use super::{
1414
BlockProducerStagedLedgerDiffCreatePendingAction,
1515
BlockProducerStagedLedgerDiffCreateSuccessAction, BlockProducerWonSlot,
1616
BlockProducerWonSlotAction, BlockProducerWonSlotDiscardAction,
17-
BlockProducerWonSlotProduceInitAction, BlockProducerWonSlotSearchAction,
18-
BlockProducerWonSlotWaitAction,
17+
BlockProducerWonSlotDiscardReason, BlockProducerWonSlotProduceInitAction,
18+
BlockProducerWonSlotSearchAction, BlockProducerWonSlotWaitAction,
1919
};
2020

2121
pub fn block_producer_effects<S: crate::Service>(
@@ -92,29 +92,31 @@ impl BlockProducerBestTipUpdateAction {
9292
pub fn effects<S: redux::Service>(self, _: &ActionMeta, store: &mut Store<S>) {
9393
let protocol_state = &self.best_tip.block.header.protocol_state.body;
9494

95-
let current_epoch = store
96-
.state()
97-
.block_producer
98-
.with(None, |this| this.vrf_evaluator.current_epoch);
95+
let vrf_evaluator_epoch = store.state().block_producer.with(None, |this| {
96+
Some(&this.vrf_evaluator.current_epoch_data.ledger)
97+
});
9998

100-
// on new run when no current_epoch is set
101-
if current_epoch.is_none() {
99+
if vrf_evaluator_epoch.cloned()
100+
!= Some(
101+
protocol_state
102+
.consensus_state
103+
.staking_epoch_data
104+
.ledger
105+
.hash
106+
.to_string(),
107+
)
108+
{
102109
store.dispatch(BlockProducerVrfEvaluatorEpochDataUpdateAction {
103110
new_epoch_number: protocol_state.consensus_state.epoch_count.as_u32(),
104111
epoch_data: protocol_state.consensus_state.staking_epoch_data.clone(),
105112
next_epoch_data: protocol_state.consensus_state.next_epoch_data.clone(),
106113
});
107114
}
108115

109-
// on epoch change
110-
if let Some(current_epoch) = current_epoch {
111-
if current_epoch != protocol_state.consensus_state.epoch_count.as_u32() {
112-
store.dispatch(BlockProducerVrfEvaluatorEpochDataUpdateAction {
113-
new_epoch_number: protocol_state.consensus_state.epoch_count.as_u32(),
114-
epoch_data: protocol_state.consensus_state.staking_epoch_data.clone(),
115-
next_epoch_data: protocol_state.consensus_state.next_epoch_data.clone(),
116-
});
117-
}
116+
if let Some(reason) = store.state().block_producer.with(None, |bp| {
117+
bp.current.won_slot_should_discard(&self.best_tip)
118+
}) {
119+
store.dispatch(BlockProducerWonSlotDiscardAction { reason });
118120
}
119121
}
120122
}

node/src/block_producer/block_producer_reducer.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,8 @@ impl BlockProducerEnabled {
171171
let global_slot_since_genesis = won_slot.global_slot_since_genesis.clone();
172172
let (pred_epoch, _) = to_epoch_and_slot(&pred_global_slot);
173173
let (next_epoch, next_slot) = to_epoch_and_slot(&curr_global_slot);
174-
let has_ancestor_in_same_checkpoint_window = in_same_checkpoint_window(
175-
&pred_global_slot,
176-
&curr_global_slot,
177-
pred_block.constants(),
178-
);
174+
let has_ancestor_in_same_checkpoint_window =
175+
in_same_checkpoint_window(&pred_global_slot, &curr_global_slot);
179176

180177
let block_stake_winner = won_slot.delegator.0.clone();
181178
let vrf_truncated_output = won_slot.vrf_output.clone();
@@ -440,7 +437,7 @@ impl BlockProducerEnabled {
440437
time: meta.time(),
441438
won_slot: won_slot.clone(),
442439
chain: std::mem::take(chain),
443-
block: block.clone(),
440+
block: dbg!(block).clone(),
444441
};
445442
}
446443
}
@@ -453,7 +450,7 @@ impl BlockProducerEnabled {
453450
..
454451
} = &mut self.current
455452
{
456-
self.current = BlockProducerCurrentState::Produced {
453+
self.current = BlockProducerCurrentState::Injected {
457454
time: meta.time(),
458455
won_slot: won_slot.clone(),
459456
chain: std::mem::take(chain),
@@ -517,15 +514,11 @@ fn in_seed_update_range(
517514
fn in_same_checkpoint_window(
518515
slot1: &ConsensusGlobalSlotStableV1,
519516
slot2: &ConsensusGlobalSlotStableV1,
520-
constants: &MinaBaseProtocolConstantsCheckedValueStableV1,
521517
) -> bool {
522-
checkpoint_window(slot1, constants) == checkpoint_window(slot2, constants)
518+
checkpoint_window(slot1) == checkpoint_window(slot2)
523519
}
524520

525-
fn checkpoint_window(
526-
slot: &ConsensusGlobalSlotStableV1,
527-
constants: &MinaBaseProtocolConstantsCheckedValueStableV1,
528-
) -> u32 {
521+
fn checkpoint_window(slot: &ConsensusGlobalSlotStableV1) -> u32 {
529522
slot.slot_number.as_u32() / checkpoint_window_size_in_slots()
530523
}
531524

@@ -537,7 +530,7 @@ fn checkpoint_window_size_in_slots() -> u32 {
537530
let one_year_ms = days_to_ms(365);
538531
let slots_per_year = one_year_ms / CONSTRAINT_CONSTANTS.block_window_duration_ms;
539532
let size_in_slots = slots_per_year / 12;
540-
assert_eq!(size_in_slots % 12, 0);
533+
assert_eq!(slots_per_year % 12, 0);
541534
size_in_slots as u32
542535
}
543536

node/src/block_producer/block_producer_state.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use mina_p2p_messages::v2::{
22
ConsensusBodyReferenceStableV1, LedgerProofProdStableV2, MinaBaseStagedLedgerHashStableV1,
33
NonZeroCurvePoint, StagedLedgerDiffDiffStableV2,
44
};
5-
use openmina_core::block::ArcBlockWithHash;
5+
use openmina_core::{block::ArcBlockWithHash, consensus::consensus_take};
66
use serde::{Deserialize, Serialize};
77

88
use super::{
@@ -85,8 +85,12 @@ pub enum BlockProducerCurrentState {
8585
},
8686
}
8787

88-
#[derive(Serialize, Deserialize, Debug, Clone)]
89-
pub enum BlockProducerWonSlotDiscardReason {}
88+
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
89+
pub enum BlockProducerWonSlotDiscardReason {
90+
BestTipStakingLedgerDifferent,
91+
BestTipGlobalSlotHigher,
92+
BestTipSuperior,
93+
}
9094

9195
impl BlockProducerState {
9296
pub fn new(now: redux::Timestamp, config: Option<BlockProducerConfig>) -> Self {
@@ -197,11 +201,46 @@ impl BlockProducerCurrentState {
197201

198202
pub fn won_slot_should_wait(&self, now: redux::Timestamp) -> bool {
199203
match self {
200-
Self::WonSlot { won_slot, .. } => won_slot.slot_time < now,
204+
Self::WonSlot { won_slot, .. } => now < won_slot.slot_time,
205+
_ => false,
206+
}
207+
}
208+
209+
pub fn won_slot_should_produce(&self, now: redux::Timestamp) -> bool {
210+
match self {
211+
Self::WonSlot { won_slot, .. } | Self::WonSlotWait { won_slot, .. } => {
212+
now >= won_slot.slot_time
213+
}
201214
_ => false,
202215
}
203216
}
204217

218+
pub fn won_slot_should_discard(
219+
&self,
220+
best_tip: &ArcBlockWithHash,
221+
) -> Option<BlockProducerWonSlotDiscardReason> {
222+
let won_slot = self.won_slot()?;
223+
if won_slot.global_slot_since_genesis.as_u32() < best_tip.global_slot() {
224+
return Some(BlockProducerWonSlotDiscardReason::BestTipGlobalSlotHigher);
225+
}
226+
// TODO(binier): check if staking ledger changed
227+
228+
if won_slot < best_tip
229+
|| self.produced_block().map_or(false, |block| {
230+
!consensus_take(
231+
best_tip.consensus_state(),
232+
block.consensus_state(),
233+
best_tip.hash(),
234+
block.hash(),
235+
)
236+
})
237+
{
238+
return Some(BlockProducerWonSlotDiscardReason::BestTipSuperior);
239+
}
240+
241+
None
242+
}
243+
205244
pub fn is_producing(&self) -> bool {
206245
match self {
207246
Self::Idle { .. }

node/src/transition_frontier/sync/transition_frontier_sync_actions.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use mina_p2p_messages::v2::StateHash;
22
use openmina_core::block::ArcBlockWithHash;
3+
use openmina_core::consensus::consensus_take;
34
use serde::{Deserialize, Serialize};
45

56
use crate::p2p::channels::rpc::P2pRpcId;
@@ -91,10 +92,15 @@ impl redux::EnablingCondition<crate::State> for TransitionFrontierSyncBestTipUpd
9192
.sync
9293
.best_tip()
9394
.map_or(true, |tip| self.best_tip.hash != tip.hash)
95+
// TODO(binier): TMP. we shouldn't need to check consensus here.
9496
&& state
95-
.consensus
97+
.transition_frontier
98+
.sync
9699
.best_tip()
97-
.map_or(true, |tip| &self.best_tip.hash == tip.hash)
100+
.or(state.transition_frontier.best_tip())
101+
.map_or(false, |tip| {
102+
consensus_take(tip.consensus_state(), self.best_tip.consensus_state(), tip.hash(), self.best_tip.hash())
103+
})
98104
// Don't sync to best tip if we are in the middle of producing
99105
// a block unless that best tip candidate is better consensus-wise
100106
// than the one that we are producing.

0 commit comments

Comments
 (0)