cuprate_p2p_core/
services.rs

1use std::time::Instant;
2
3use cuprate_pruning::{PruningError, PruningSeed};
4use cuprate_wire::{CoreSyncData, PeerListEntryBase};
5
6use crate::{
7    client::InternalPeerID,
8    handles::ConnectionHandle,
9    types::{BanState, ConnectionInfo, Peerlist, SetBan},
10    NetZoneAddress, NetworkAddressIncorrectZone, NetworkZone,
11};
12
13/// A request to the core sync service for our node's [`CoreSyncData`].
14pub struct CoreSyncDataRequest;
15
16/// A response from the core sync service containing our [`CoreSyncData`].
17pub struct CoreSyncDataResponse(pub CoreSyncData);
18
19/// A [`NetworkZone`] specific [`PeerListEntryBase`].
20///
21/// Using this type instead of [`PeerListEntryBase`] in the address book makes
22/// usage easier for the rest of the P2P code as we can guarantee only the correct addresses will be stored and returned.
23#[derive(Debug, Copy, Clone, Eq, PartialEq)]
24#[cfg_attr(
25    feature = "borsh",
26    derive(borsh::BorshSerialize, borsh::BorshDeserialize)
27)]
28pub struct ZoneSpecificPeerListEntryBase<A: NetZoneAddress> {
29    pub adr: A,
30    pub id: u64,
31    pub last_seen: i64,
32    pub pruning_seed: PruningSeed,
33    pub rpc_port: u16,
34    pub rpc_credits_per_hash: u32,
35}
36
37impl<A: NetZoneAddress> From<ZoneSpecificPeerListEntryBase<A>> for PeerListEntryBase {
38    fn from(value: ZoneSpecificPeerListEntryBase<A>) -> Self {
39        Self {
40            adr: value.adr.into(),
41            id: value.id,
42            last_seen: value.last_seen,
43            pruning_seed: value.pruning_seed.compress(),
44            rpc_port: value.rpc_port,
45            rpc_credits_per_hash: value.rpc_credits_per_hash,
46        }
47    }
48}
49
50/// An error converting a [`PeerListEntryBase`] into a [`ZoneSpecificPeerListEntryBase`].
51#[derive(Debug, thiserror::Error)]
52pub enum PeerListConversionError {
53    #[error("Address is in incorrect zone")]
54    Address(#[from] NetworkAddressIncorrectZone),
55    #[error("Pruning seed error: {0}")]
56    PruningSeed(#[from] PruningError),
57}
58
59impl<A: NetZoneAddress> TryFrom<PeerListEntryBase> for ZoneSpecificPeerListEntryBase<A> {
60    type Error = PeerListConversionError;
61
62    fn try_from(value: PeerListEntryBase) -> Result<Self, Self::Error> {
63        Ok(Self {
64            adr: value.adr.try_into()?,
65            id: value.id,
66            last_seen: value.last_seen,
67            pruning_seed: PruningSeed::decompress_p2p_rules(value.pruning_seed)?,
68            rpc_port: value.rpc_port,
69            rpc_credits_per_hash: value.rpc_credits_per_hash,
70        })
71    }
72}
73
74/// A request to the address book service.
75pub enum AddressBookRequest<Z: NetworkZone> {
76    /// Tells the address book that we have connected or received a connection from a peer.
77    NewConnection {
78        /// The [`InternalPeerID`] of this connection.
79        internal_peer_id: InternalPeerID<Z::Addr>,
80        /// The public address of the peer, if this peer has a reachable public address.
81        public_address: Option<Z::Addr>,
82        /// The [`ConnectionHandle`] to this peer.
83        handle: ConnectionHandle,
84        /// An ID the peer assigned itself.
85        id: u64,
86        /// The peers [`PruningSeed`].
87        pruning_seed: PruningSeed,
88        /// The peers rpc port.
89        rpc_port: u16,
90        /// The peers rpc credits per hash
91        rpc_credits_per_hash: u32,
92    },
93
94    /// Tells the address book about a peer list received from a peer.
95    IncomingPeerList(
96        InternalPeerID<Z::Addr>,
97        Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>,
98    ),
99
100    /// Takes a random white peer from the peer list. If height is specified
101    /// then the peer list should retrieve a peer that should have a full
102    /// block at that height according to it's pruning seed
103    TakeRandomWhitePeer { height: Option<usize> },
104
105    /// Takes a random gray peer from the peer list. If height is specified
106    /// then the peer list should retrieve a peer that should have a full
107    /// block at that height according to it's pruning seed
108    TakeRandomGrayPeer { height: Option<usize> },
109
110    /// Takes a random peer from the peer list. If height is specified
111    /// then the peer list should retrieve a peer that should have a full
112    /// block at that height according to it's pruning seed.
113    ///
114    /// The address book will look in the white peer list first, then the gray
115    /// one if no peer is found.
116    TakeRandomPeer { height: Option<usize> },
117
118    /// Gets the specified number of white peers, or less if we don't have enough.
119    GetWhitePeers(usize),
120
121    /// Gets our own optionally specified address
122    OwnAddress,
123
124    /// Get info on all peers, white & grey.
125    Peerlist,
126
127    /// Get the amount of white & grey peers.
128    PeerlistSize,
129
130    /// Get information on all connections.
131    ConnectionInfo,
132
133    /// Get the amount of incoming & outgoing connections.
134    ConnectionCount,
135
136    /// (Un)ban a peer.
137    SetBan(SetBan<Z::Addr>),
138
139    /// Checks if the given peer is banned.
140    GetBan(Z::Addr),
141
142    /// Get the state of all bans.
143    GetBans,
144}
145
146/// A response from the address book service.
147pub enum AddressBookResponse<Z: NetworkZone> {
148    /// Generic OK response.
149    ///
150    /// Response to:
151    /// - [`AddressBookRequest::NewConnection`]
152    /// - [`AddressBookRequest::IncomingPeerList`]
153    Ok,
154
155    /// Response to:
156    /// - [`AddressBookRequest::TakeRandomWhitePeer`]
157    /// - [`AddressBookRequest::TakeRandomGrayPeer`]
158    /// - [`AddressBookRequest::TakeRandomPeer`]
159    Peer(ZoneSpecificPeerListEntryBase<Z::Addr>),
160
161    /// Response to [`AddressBookRequest::GetWhitePeers`].
162    Peers(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
163
164    /// Response to [`AddressBookRequest::Peerlist`].
165    Peerlist(Peerlist<Z::Addr>),
166
167    /// Response to [`AddressBookRequest::PeerlistSize`].
168    PeerlistSize { white: usize, grey: usize },
169
170    /// Response to [`AddressBookRequest::ConnectionInfo`].
171    ConnectionInfo(Vec<ConnectionInfo<Z::Addr>>),
172
173    /// Response to [`AddressBookRequest::ConnectionCount`].
174    ConnectionCount { incoming: usize, outgoing: usize },
175
176    /// Response to [`AddressBookRequest::GetBan`].
177    ///
178    /// This returns [`None`] if the peer is not banned,
179    /// else it returns how long the peer is banned for.
180    GetBan { unban_instant: Option<Instant> },
181
182    /// Response to [`AddressBookRequest::GetBans`].
183    GetBans(Vec<BanState<Z::Addr>>),
184
185    /// Response to [`AddressBookRequest::OwnAddress`]
186    ///
187    /// This returns [`None`] if the address book do
188    /// not contain a self designated address.
189    OwnAddress(Option<Z::Addr>),
190}