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}