node/transition_frontier/
transition_frontier_actions.rs1use std::{collections::BTreeSet, sync::Arc};
2
3use mina_p2p_messages::v2::StateHash;
4use openmina_core::{block::ArcBlockWithHash, ActionEvent};
5use serde::{Deserialize, Serialize};
6
7use super::{
8 candidate::TransitionFrontierCandidateAction,
9 genesis::TransitionFrontierGenesisAction,
10 genesis_effectful::TransitionFrontierGenesisEffectfulAction,
11 sync::{SyncError, TransitionFrontierSyncAction, TransitionFrontierSyncState},
12};
13
14pub type TransitionFrontierActionWithMeta = redux::ActionWithMeta<TransitionFrontierAction>;
15pub type TransitionFrontierActionWithMetaRef<'a> =
16 redux::ActionWithMeta<&'a TransitionFrontierAction>;
17
18#[derive(derive_more::From, Serialize, Deserialize, Debug, Clone, ActionEvent)]
19pub enum TransitionFrontierAction {
20 Genesis(TransitionFrontierGenesisAction),
21 GenesisEffect(TransitionFrontierGenesisEffectfulAction),
22 #[action_event(level = info)]
29 GenesisInject,
30 #[action_event(level = info)]
31 GenesisProvenInject,
32
33 Candidate(TransitionFrontierCandidateAction),
34 Sync(TransitionFrontierSyncAction),
35 Synced {
37 needed_protocol_states: BTreeSet<StateHash>,
39 },
40 SyncFailed {
41 best_tip: ArcBlockWithHash,
42 error: SyncError,
43 },
44}
45
46impl redux::EnablingCondition<crate::State> for TransitionFrontierAction {
47 fn is_enabled(&self, state: &crate::State, time: redux::Timestamp) -> bool {
48 match self {
49 TransitionFrontierAction::Genesis(a) => a.is_enabled(state, time),
50 TransitionFrontierAction::GenesisEffect(a) => a.is_enabled(state, time),
51 TransitionFrontierAction::GenesisInject => {
52 state.transition_frontier.root().is_none()
53 && state
54 .transition_frontier
55 .genesis
56 .block_with_real_or_dummy_proof()
57 .is_some()
58 }
59 TransitionFrontierAction::GenesisProvenInject => {
60 let Some(genesis) = state.transition_frontier.genesis.proven_block() else {
61 return false;
62 };
63 state
64 .transition_frontier
65 .root()
66 .is_none_or(|b| b.is_genesis() && !Arc::ptr_eq(&genesis.block, &b.block))
67 }
68 TransitionFrontierAction::Candidate(a) => a.is_enabled(state, time),
69 TransitionFrontierAction::Sync(a) => a.is_enabled(state, time),
70 TransitionFrontierAction::Synced { .. } => matches!(
71 state.transition_frontier.sync,
72 TransitionFrontierSyncState::CommitSuccess { .. }
73 ),
74 TransitionFrontierAction::SyncFailed { best_tip, error } => {
75 let sync = &state.transition_frontier.sync;
76 sync.best_tip().is_some_and(|b| b.hash() == best_tip.hash())
77 && match error {
78 SyncError::BlockApplyFailed(block, _) => sync
79 .block_state(block.hash())
80 .is_some_and(|s| s.is_apply_error()),
81 }
82 }
83 }
84 }
85}