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}