p2p/channels/best_tip/
p2p_channels_best_tip_reducer.rs1use 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 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}