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, 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(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
96
97    /// Takes a random white peer from the peer list. If height is specified
98    /// then the peer list should retrieve a peer that should have a full
99    /// block at that height according to it's pruning seed
100    TakeRandomWhitePeer { height: Option<usize> },
101
102    /// Takes a random gray peer from the peer list. If height is specified
103    /// then the peer list should retrieve a peer that should have a full
104    /// block at that height according to it's pruning seed
105    TakeRandomGrayPeer { height: Option<usize> },
106
107    /// Takes a random peer from the peer list. If height is specified
108    /// then the peer list should retrieve a peer that should have a full
109    /// block at that height according to it's pruning seed.
110    ///
111    /// The address book will look in the white peer list first, then the gray
112    /// one if no peer is found.
113    TakeRandomPeer { height: Option<usize> },
114
115    /// Gets the specified number of white peers, or less if we don't have enough.
116    GetWhitePeers(usize),
117
118    /// Get the amount of white & grey peers.
119    PeerlistSize,
120
121    /// Get information on all connections.
122    ConnectionInfo,
123
124    /// Get the amount of incoming & outgoing connections.
125    ConnectionCount,
126
127    /// (Un)ban a peer.
128    SetBan(SetBan<Z::Addr>),
129
130    /// Checks if the given peer is banned.
131    GetBan(Z::Addr),
132
133    /// Get the state of all bans.
134    GetBans,
135}
136
137/// A response from the address book service.
138pub enum AddressBookResponse<Z: NetworkZone> {
139    /// Generic OK response.
140    ///
141    /// Response to:
142    /// - [`AddressBookRequest::NewConnection`]
143    /// - [`AddressBookRequest::IncomingPeerList`]
144    Ok,
145
146    /// Response to:
147    /// - [`AddressBookRequest::TakeRandomWhitePeer`]
148    /// - [`AddressBookRequest::TakeRandomGrayPeer`]
149    /// - [`AddressBookRequest::TakeRandomPeer`]
150    Peer(ZoneSpecificPeerListEntryBase<Z::Addr>),
151
152    /// Response to [`AddressBookRequest::GetWhitePeers`].
153    Peers(Vec<ZoneSpecificPeerListEntryBase<Z::Addr>>),
154
155    /// Response to [`AddressBookRequest::PeerlistSize`].
156    PeerlistSize { white: usize, grey: usize },
157
158    /// Response to [`AddressBookRequest::ConnectionInfo`].
159    ConnectionInfo(Vec<ConnectionInfo<Z::Addr>>),
160
161    /// Response to [`AddressBookRequest::ConnectionCount`].
162    ConnectionCount { incoming: usize, outgoing: usize },
163
164    /// Response to [`AddressBookRequest::GetBan`].
165    ///
166    /// This returns [`None`] if the peer is not banned,
167    /// else it returns how long the peer is banned for.
168    GetBan { unban_instant: Option<Instant> },
169
170    /// Response to [`AddressBookRequest::GetBans`].
171    GetBans(Vec<BanState<Z::Addr>>),
172}