p2p/channels/best_tip/
p2p_channels_best_tip_reducer.rs

1use openmina_core::{bug_condition, Substate};
2use redux::ActionWithMeta;
3
4use crate::{
5    channels::{ChannelId, ChannelMsg, MsgId, P2pChannelsEffectfulAction},
6    P2pPeerAction, P2pState, PeerId,
7};
8
9use super::{
10    BestTipPropagationChannelMsg, BestTipPropagationState, P2pChannelsBestTipAction,
11    P2pChannelsBestTipState,
12};
13
14impl P2pChannelsBestTipState {
15    /// Substate is accessed
16    pub fn reducer<Action, State>(
17        mut state_context: Substate<Action, State, P2pState>,
18        action: ActionWithMeta<P2pChannelsBestTipAction>,
19    ) -> Result<(), String>
20    where
21        State: crate::P2pStateTrait,
22        Action: crate::P2pActionTrait<State>,
23    {
24        let (action, meta) = action.split();
25        let p2p_state = state_context.get_substate_mut()?;
26        let peer_id = *action.peer_id();
27        let is_libp2p = p2p_state.is_libp2p_peer(&peer_id);
28        let best_tip_state = &mut p2p_state
29            .get_ready_peer_mut(&peer_id)
30            .ok_or_else(|| format!("Peer state not found for: {action:?}"))?
31            .channels
32            .best_tip;
33
34        match action {
35            P2pChannelsBestTipAction::Init { .. } => {
36                *best_tip_state = Self::Init { time: meta.time() };
37
38                let dispatcher = state_context.into_dispatcher();
39
40                dispatcher.push(P2pChannelsEffectfulAction::InitChannel {
41                    peer_id,
42                    id: ChannelId::BestTipPropagation,
43                    on_success: redux::callback!(
44                        on_best_tip_channel_init(peer_id: PeerId) -> crate::P2pAction {
45                            P2pChannelsBestTipAction::Pending { peer_id }
46                        }
47                    ),
48                });
49                Ok(())
50            }
51            P2pChannelsBestTipAction::Pending { .. } => {
52                *best_tip_state = Self::Pending { time: meta.time() };
53                Ok(())
54            }
55            P2pChannelsBestTipAction::Ready { .. } => {
56                *best_tip_state = Self::Ready {
57                    time: meta.time(),
58                    local: BestTipPropagationState::WaitingForRequest { time: meta.time() },
59                    remote: BestTipPropagationState::WaitingForRequest { time: meta.time() },
60                    last_sent: None,
61                    last_received: None,
62                };
63
64                let dispatcher = state_context.into_dispatcher();
65                dispatcher.push(P2pChannelsBestTipAction::RequestSend { peer_id });
66
67                #[cfg(feature = "p2p-libp2p")]
68                if is_libp2p {
69                    dispatcher.push(P2pChannelsBestTipAction::RequestReceived { peer_id });
70                }
71                Ok(())
72            }
73            P2pChannelsBestTipAction::RequestSend { .. } => {
74                let Self::Ready { local, .. } = best_tip_state else {
75                    bug_condition!(
76                        "Invalid state for `P2pChannelsBestTipAction::RequestSend`, state: {:?}",
77                        best_tip_state
78                    );
79                    return Ok(());
80                };
81                *local = BestTipPropagationState::Requested { time: meta.time() };
82
83                let dispatcher = state_context.into_dispatcher();
84                dispatcher.push(P2pChannelsEffectfulAction::MessageSend {
85                    peer_id,
86                    msg_id: MsgId::first(),
87                    msg: ChannelMsg::BestTipPropagation(BestTipPropagationChannelMsg::GetNext),
88                });
89                Ok(())
90            }
91            P2pChannelsBestTipAction::Received { best_tip, .. } => {
92                let Self::Ready {
93                    local,
94                    last_received,
95                    ..
96                } = best_tip_state
97                else {
98                    bug_condition!(
99                        "Invalid state for `P2pChannelsBestTipAction::Received`, state: {:?}",
100                        best_tip_state
101                    );
102                    return Ok(());
103                };
104
105                *local = BestTipPropagationState::Responded { time: meta.time() };
106                *last_received = Some(best_tip.clone());
107
108                let dispatcher = state_context.into_dispatcher();
109                dispatcher.push(P2pPeerAction::BestTipUpdate { peer_id, best_tip });
110                dispatcher.push(P2pChannelsBestTipAction::RequestSend { peer_id });
111                Ok(())
112            }
113            P2pChannelsBestTipAction::RequestReceived { peer_id, .. } => {
114                let Self::Ready { remote, .. } = best_tip_state else {
115                    bug_condition!(
116                        "Invalid state for `P2pChannelsBestTipAction::RequestReceived`, state: {:?}",
117                        best_tip_state
118                    );
119                    return Ok(());
120                };
121
122                *remote = BestTipPropagationState::Requested { time: meta.time() };
123
124                let (dispatcher, state) = state_context.into_dispatcher_and_state();
125                let p2p_state: &P2pState = state.substate()?;
126
127                if let Some(callback) = &p2p_state
128                    .callbacks
129                    .on_p2p_channels_best_tip_request_received
130                {
131                    dispatcher.push_callback(callback.clone(), peer_id);
132                }
133                Ok(())
134            }
135            P2pChannelsBestTipAction::ResponseSend { best_tip, .. } => {
136                let Self::Ready {
137                    remote, last_sent, ..
138                } = best_tip_state
139                else {
140                    bug_condition!(
141                        "Invalid state for `P2pChannelsBestTipAction::ResponseSend`, state: {:?}",
142                        best_tip_state
143                    );
144                    return Ok(());
145                };
146
147                if !is_libp2p {
148                    *remote = BestTipPropagationState::Responded { time: meta.time() };
149                }
150                *last_sent = Some(best_tip.clone());
151
152                let dispatcher = state_context.into_dispatcher();
153
154                if !is_libp2p {
155                    dispatcher.push(P2pChannelsEffectfulAction::MessageSend {
156                        peer_id,
157                        msg_id: MsgId::first(),
158                        msg: ChannelMsg::BestTipPropagation(BestTipPropagationChannelMsg::BestTip(
159                            best_tip.block,
160                        )),
161                    });
162                    return Ok(());
163                }
164
165                Ok(())
166            }
167        }
168    }
169}