p2p/channels/best_tip/
p2p_channels_best_tip_actions.rs1use openmina_core::{block::ArcBlockWithHash, ActionEvent};
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 channels::{best_tip::P2pChannelsBestTipState, P2pChannelsAction},
6 P2pState, PeerId,
7};
8
9use super::BestTipPropagationState;
10
11#[derive(Debug, Clone, Serialize, Deserialize, ActionEvent)]
12#[action_event(fields(display(peer_id), best_tip = display(&best_tip.hash)))]
13pub enum P2pChannelsBestTipAction {
14 Init {
16 peer_id: PeerId,
17 },
18 Pending {
19 peer_id: PeerId,
20 },
21 Ready {
23 peer_id: PeerId,
24 },
25 RequestSend {
27 peer_id: PeerId,
28 },
29 Received {
31 peer_id: PeerId,
32 best_tip: ArcBlockWithHash,
33 },
34 RequestReceived {
36 peer_id: PeerId,
37 },
38 ResponseSend {
40 peer_id: PeerId,
41 best_tip: ArcBlockWithHash,
42 },
43}
44
45impl P2pChannelsBestTipAction {
46 pub fn peer_id(&self) -> &PeerId {
47 match self {
48 Self::Init { peer_id }
49 | Self::Pending { peer_id }
50 | Self::Ready { peer_id }
51 | Self::RequestSend { peer_id }
52 | Self::Received { peer_id, .. }
53 | Self::RequestReceived { peer_id }
54 | Self::ResponseSend { peer_id, .. } => peer_id,
55 }
56 }
57}
58
59impl redux::EnablingCondition<P2pState> for P2pChannelsBestTipAction {
60 fn is_enabled(&self, state: &P2pState, _time: redux::Timestamp) -> bool {
61 match self {
62 P2pChannelsBestTipAction::Init { peer_id } => state
63 .get_ready_peer(peer_id)
64 .is_some_and(|p| matches!(&p.channels.best_tip, P2pChannelsBestTipState::Enabled)),
65 P2pChannelsBestTipAction::Pending { peer_id } => {
66 state.get_ready_peer(peer_id).is_some_and(|p| {
67 matches!(&p.channels.best_tip, P2pChannelsBestTipState::Init { .. })
68 })
69 }
70 P2pChannelsBestTipAction::Ready { peer_id } => {
71 state.get_ready_peer(peer_id).is_some_and(|p| {
72 matches!(
73 &p.channels.best_tip,
74 P2pChannelsBestTipState::Pending { .. }
75 )
76 })
77 }
78 P2pChannelsBestTipAction::RequestSend { peer_id } => state
79 .get_ready_peer(peer_id)
80 .is_some_and(|p| match &p.channels.best_tip {
81 P2pChannelsBestTipState::Ready { local, .. } => matches!(
82 local,
83 BestTipPropagationState::WaitingForRequest { .. }
84 | BestTipPropagationState::Responded { .. },
85 ),
86 _ => false,
87 }),
88 P2pChannelsBestTipAction::Received { peer_id, .. } => {
89 state
92 .get_ready_peer(peer_id)
93 .is_some_and(|p| match &p.channels.best_tip {
94 P2pChannelsBestTipState::Ready { local, .. } => {
95 matches!(local, BestTipPropagationState::Requested { .. })
96 }
97 _ => false,
98 })
99 }
100 P2pChannelsBestTipAction::RequestReceived { peer_id } => state
101 .get_ready_peer(peer_id)
102 .is_some_and(|p| match &p.channels.best_tip {
103 P2pChannelsBestTipState::Ready { remote, .. } => matches!(
104 remote,
105 BestTipPropagationState::WaitingForRequest { .. }
106 | BestTipPropagationState::Responded { .. }
107 ),
108 _ => false,
109 }),
110 P2pChannelsBestTipAction::ResponseSend { peer_id, best_tip } => state
111 .get_ready_peer(peer_id)
112 .is_some_and(|p| match &p.channels.best_tip {
113 P2pChannelsBestTipState::Ready {
114 remote, last_sent, ..
115 } => {
116 if !matches!(remote, BestTipPropagationState::Requested { .. }) {
117 return false;
118 }
119 last_sent
120 .as_ref()
121 .is_none_or(|sent| sent.hash != best_tip.hash)
122 }
123 _ => false,
124 }),
125 }
126 }
127}
128
129impl From<P2pChannelsBestTipAction> for crate::P2pAction {
130 fn from(action: P2pChannelsBestTipAction) -> Self {
131 Self::Channels(P2pChannelsAction::BestTip(action))
132 }
133}