p2p/network/kad/
p2p_network_kad_actions.rs

1use multiaddr::Multiaddr;
2use openmina_core::ActionEvent;
3use redux::EnablingCondition;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7    kad::stream::P2pNetworkKademliaStreamAction, request::P2pNetworkKadRequestAction,
8    ConnectionAddr, P2pAction, P2pNetworkAction, P2pNetworkKadEntry, P2pState, PeerId, StreamId,
9};
10
11use super::{bootstrap::P2pNetworkKadBootstrapAction, CID};
12
13/// Kademlia actions.
14#[derive(Debug, Clone, Serialize, Deserialize, derive_more::From, ActionEvent)]
15pub enum P2pNetworkKadAction {
16    System(P2pNetworkKademliaAction),
17    Bootstrap(P2pNetworkKadBootstrapAction),
18    Request(P2pNetworkKadRequestAction),
19    Stream(P2pNetworkKademliaStreamAction),
20}
21
22impl EnablingCondition<P2pState> for P2pNetworkKadAction {
23    fn is_enabled(&self, state: &P2pState, time: redux::Timestamp) -> bool {
24        match self {
25            P2pNetworkKadAction::System(action) => action.is_enabled(state, time),
26            P2pNetworkKadAction::Bootstrap(action) => action.is_enabled(state, time),
27            P2pNetworkKadAction::Request(action) => action.is_enabled(state, time),
28            P2pNetworkKadAction::Stream(action) => action.is_enabled(state, time),
29        }
30    }
31}
32
33impl From<P2pNetworkKadAction> for P2pAction {
34    fn from(value: P2pNetworkKadAction) -> Self {
35        P2pNetworkAction::Kad(value).into()
36    }
37}
38
39/// Kademlia system actions
40#[derive(Debug, Clone, Serialize, Deserialize, ActionEvent)]
41#[action_event(fields(
42    display(addr),
43    display(peer_id),
44    stream_id,
45    debug(key),
46    debug(closest_peers),
47    debug(addrs)
48))]
49pub enum P2pNetworkKademliaAction {
50    /// Answer `FIND_NODE` request.
51    ///
52    /// Answers peer's `FIND_NODE` request by querying routing table for closest nodes.
53    AnswerFindNodeRequest {
54        addr: ConnectionAddr,
55        peer_id: PeerId,
56        stream_id: StreamId,
57        key: CID,
58    },
59    /// Udate result of scheduled outgoing `FIND_NODE`.
60    ///
61    /// Udates result of scheduled outgoing `FIND_NODE` request to a peer.
62    UpdateFindNodeRequest {
63        addr: ConnectionAddr,
64        peer_id: PeerId,
65        stream_id: StreamId,
66        closest_peers: Vec<P2pNetworkKadEntry>,
67    },
68    /// Perform local node's Kademlia bootstrap.
69    #[action_event(level = info)]
70    StartBootstrap { key: PeerId },
71    /// Bootstrap is finished.
72    BootstrapFinished,
73
74    /// Update routing table with peer addresses
75    #[action_event(level = info)]
76    UpdateRoutingTable {
77        peer_id: PeerId,
78        addrs: Vec<Multiaddr>,
79    },
80}
81
82impl EnablingCondition<P2pState> for P2pNetworkKademliaAction {
83    fn is_enabled(&self, state: &P2pState, time: redux::Timestamp) -> bool {
84        let Some(discovery_state) = &state.network.scheduler.discovery_state else {
85            return false;
86        };
87        match self {
88            P2pNetworkKademliaAction::AnswerFindNodeRequest {
89                peer_id, stream_id, ..
90            } => discovery_state
91                .find_kad_stream_state(peer_id, stream_id)
92                .is_some(),
93            P2pNetworkKademliaAction::UpdateFindNodeRequest {
94                addr: _,
95                peer_id,
96                stream_id,
97                ..
98            } => {
99                discovery_state
100                    .find_kad_stream_state(peer_id, stream_id)
101                    .is_some()
102                    && discovery_state.request(peer_id).is_some()
103            }
104            P2pNetworkKademliaAction::StartBootstrap { .. } => discovery_state
105                .status
106                .can_bootstrap(time, &state.config.timeouts),
107            P2pNetworkKademliaAction::BootstrapFinished { .. } => {
108                // TODO: also can run bootstrap on timely basis.
109                matches!(
110                    discovery_state.status,
111                    super::P2pNetworkKadStatus::Bootstrapping(_)
112                )
113            }
114            P2pNetworkKademliaAction::UpdateRoutingTable { .. } => true,
115        }
116    }
117}
118
119impl From<P2pNetworkKademliaAction> for P2pAction {
120    fn from(value: P2pNetworkKademliaAction) -> Self {
121        P2pAction::Network(P2pNetworkKadAction::System(value).into())
122    }
123}