node/transition_frontier/
transition_frontier_reducer.rs1use super::{
2 sync::{SyncError, TransitionFrontierSyncState},
3 TransitionFrontierAction, TransitionFrontierActionWithMetaRef, TransitionFrontierState,
4};
5use openmina_core::block::AppliedBlock;
6
7impl TransitionFrontierState {
8 pub fn reducer(
9 mut state_context: crate::Substate<Self>,
10 action: TransitionFrontierActionWithMetaRef<'_>,
11 ) {
12 let Ok(state) = state_context.get_substate_mut() else {
13 return;
15 };
16 let (action, meta) = action.split();
17
18 state.chain_diff.take();
20
21 match action {
22 TransitionFrontierAction::Genesis(a) => {
23 super::genesis::TransitionFrontierGenesisState::reducer(
24 openmina_core::Substate::from_compatible_substate(state_context),
25 meta.with_action(a),
26 )
27 }
28 TransitionFrontierAction::GenesisEffect(_) => {}
29 TransitionFrontierAction::GenesisInject => {
30 let Some(genesis) = state.genesis.block_with_real_or_dummy_proof() else {
31 return;
32 };
33 let genesis = AppliedBlock {
34 block: genesis,
35 just_emitted_a_proof: true,
36 };
37 state.best_chain = vec![genesis];
38 state.sync = TransitionFrontierSyncState::Synced { time: meta.time() };
39 }
40 TransitionFrontierAction::GenesisProvenInject => {
41 let Some(genesis) = state.genesis.proven_block() else {
42 return;
43 };
44 if let Some(block) = state.best_chain.get_mut(0) {
45 block.block = genesis.clone();
46 } else {
47 let genesis = AppliedBlock {
48 block: genesis.clone(),
49 just_emitted_a_proof: true,
50 };
51 state.best_chain = vec![genesis];
52 }
53 if !state.sync.is_pending() {
54 state.sync = TransitionFrontierSyncState::Synced { time: meta.time() };
55 }
56 }
57 TransitionFrontierAction::Candidate(a) => {
58 super::candidate::TransitionFrontierCandidatesState::reducer(
59 openmina_core::Substate::from_compatible_substate(state_context),
60 meta.with_action(a),
61 );
62 }
63 TransitionFrontierAction::Sync(a) => {
64 let best_chain = state.best_chain.clone();
65 super::sync::TransitionFrontierSyncState::reducer(
66 openmina_core::Substate::from_compatible_substate(state_context),
67 meta.with_action(a),
68 &best_chain,
69 );
70 }
71 TransitionFrontierAction::Synced {
72 needed_protocol_states: needed_protocol_state_hashes,
73 } => {
74 let TransitionFrontierSyncState::CommitSuccess {
75 chain,
76 needed_protocol_states,
77 ..
78 } = &mut state.sync
79 else {
80 return;
81 };
82 let mut needed_protocol_state_hashes = needed_protocol_state_hashes.clone();
83 let new_chain = std::mem::take(chain);
84 let needed_protocol_states = std::mem::take(needed_protocol_states);
85
86 state.needed_protocol_states.extend(needed_protocol_states);
87 state
88 .needed_protocol_states
89 .retain(|k, _| needed_protocol_state_hashes.remove(k));
90
91 for hash in needed_protocol_state_hashes {
92 let block = state
93 .best_chain
94 .iter()
95 .find(|b| b.hash() == &hash)
96 .or_else(|| new_chain.iter().find(|b| b.hash() == &hash));
97 let block = block.expect("we lack needed block!");
99 let protocol_state = block.header().protocol_state.clone();
100 state.needed_protocol_states.insert(hash, protocol_state);
101 }
102
103 state.blacklist.retain(|_, height| {
104 let tip = new_chain.last().unwrap();
108 height
109 .checked_add(tip.constants().k.as_u32())
110 .expect("overflow")
111 > tip.height()
112 });
113 state.chain_diff = state.maybe_make_chain_diff(&new_chain);
114 state.best_chain = new_chain;
115 state.sync = TransitionFrontierSyncState::Synced { time: meta.time() };
116 }
117 TransitionFrontierAction::SyncFailed { error, .. } => {
118 match error {
119 SyncError::BlockApplyFailed(block, _) => {
120 state.blacklist.insert(block.hash().clone(), block.height());
121 }
122 }
123 state.sync = TransitionFrontierSyncState::Synced { time: meta.time() };
124 }
125 }
126 }
127}