pub struct PeerPool { /* private fields */ }Implementations§
Source§impl PeerPool
impl PeerPool
Sourcepub async fn new(
network: NetworkType,
tls: Connector,
max_peers: usize,
requirement: PeerRequirement,
connect_timeout: Duration,
) -> Result<Self, ChiaQueryError>
pub async fn new( network: NetworkType, tls: Connector, max_peers: usize, requirement: PeerRequirement, connect_timeout: Duration, ) -> Result<Self, ChiaQueryError>
Spin up the pool by connecting to max_peers random full-node peers
concurrently. Under PeerRequirement::Required at least one peer must
succeed, otherwise we return ChiaQueryError::PeerDiscoveryFailed; under
PeerRequirement::Optional an empty pool is returned and refills later.
Sourcepub fn peak_height(&self) -> u32
pub fn peak_height(&self) -> u32
Latest peak height observed across all connected peers. Returns 0 if no peak has been received yet.
Sourcepub async fn select_peer(&self) -> Option<(Peer, SocketAddr)>
pub async fn select_peer(&self) -> Option<(Peer, SocketAddr)>
Round-robin select a peer from the pool.
Returns None when the pool is empty.
Sourcepub async fn select_corroborating_peers(
&self,
asked: SocketAddr,
) -> Vec<(Peer, SocketAddr)>
pub async fn select_corroborating_peers( &self, asked: SocketAddr, ) -> Vec<(Peer, SocketAddr)>
Every peer that could CORROBORATE an answer already given by the peer at asked.
A corroborating peer must be two things at once, and neither alone is enough:
- A different address than
asked. Asking the same connection twice returns the same opinion twice, which reads as agreement while being one voice. PeerOrigin::Discovered. A peer reached from a preferred address — an operator’s node, or one on this machine — is an excellent peer to READ from and is not evidence about the chain independent of this host, exactly asindependent_peer_countrecords.
They are returned ALL AT ONCE, and there is deliberately no singular form of this. Asking
corroborators one at a time lets the first responder settle a claim about the chain, which
is exactly the power a hostile peer has (dig_ecosystem#2462) — and a single corroborator
cannot reach CORROBORATION_FLOOR at all, so a caller that took one would be building an
answer it is not allowed to report as corroborated.
Returns an empty vector when the pool holds nobody who qualifies, which is the honest answer that there is nobody to corroborate with.
Sourcepub async fn eject_peer(&self, addr: SocketAddr)
pub async fn eject_peer(&self, addr: SocketAddr)
Remove a peer from the pool and asynchronously connect a replacement.
Sourcepub async fn peer_count(&self) -> usize
pub async fn peer_count(&self) -> usize
How many peers the pool HOLDS right now.
This is a live count of the connections currently in the pool, not
max_peers’s target: a pool that is still filling reports what it has, and
reports the target only once it has reached it. A caller showing this number to a user is
stating a fact about the machine, so a configured intention must never stand in for it.
A peer is removed by eject_peer, which runs when a request to it
FAILS. So the count is of peers held and believed usable; a connection that has died
silently is still counted until something tries to use it. That is the same liveness
standard has_peers has always answered by, made countable.
Sourcepub async fn independent_peer_count(&self) -> usize
pub async fn independent_peer_count(&self) -> usize
How many peers the pool holds that are INDEPENDENT opinions.
peer_count answers “how many connections do I have”; this answers
“how many of them could corroborate each other”. They differ by the peers reached from a
preferred address — an operator’s trusted node or one on this machine — which are excellent
peers to READ from and are not evidence about the chain independent of this host. A caller
deciding whether enough separate sources agree MUST use this number, because counting a
co-resident node as an independent voice is the thing that made a single local process able
to look like a full peer set (dig_ecosystem#2648).
Sourcepub async fn corroboration_readiness(
&self,
asked: SocketAddr,
) -> CorroborationReadiness
pub async fn corroboration_readiness( &self, asked: SocketAddr, ) -> CorroborationReadiness
Whether the pool can honestly attempt a CORROBORATED read of an answer given by asked.
The count is of the peers that WILL be asked to corroborate — precisely the set
select_corroborating_peers returns for the same
address, because both use is_corroborator to decide the set.
It takes the answering address rather than subtracting one blindly. An earlier version
charged the asker’s slot against the independent set whatever the asker was, so a read from
the operator’s own node — which is not in that set at all — silently spent an independent
voice it had never occupied. On the host this crate is sized for, two genuinely independent
peers agreeing with a co-resident node were downgraded to Uncorroborated* and pushed on
to the centralized coinset tier, which is the opposite of what NC-12 asks for.
This refuses; it never degrades. Corroborating against however many peers happen to be
present turns a four-voice quorum into a two-voice one that still reports itself
corroborated, and no consumer downstream can tell those apart. A caller handed
CorroborationReadiness::Insufficient must decline the read, not proceed with fewer
voices.
Sourcepub async fn cycle_expired_peers(&self) -> Option<SocketAddr>
pub async fn cycle_expired_peers(&self) -> Option<SocketAddr>
Rotate out the OLDEST discovered peer that has outlived PEER_LIFETIME, if any.
Returns the address ejected, so a caller can log or refill deliberately. This is NC-12’s
cycling half and it is driven by AGE alone: a peer that has answered every request is
exactly the peer this removes, because a set that never fails is a set an attacker only has
to capture once. The pool’s other eviction, eject_peer, fires on
request FAILURE and cannot substitute for this — a captured peer does not fail.
Only PeerOrigin::Discovered entries are rotated. A priority entry
is the operator’s own node or one on this machine; cycling it would re-dial the same
address, spending a handshake to change nothing.
One per call, so cycling can never empty the pool in a single sweep.
Sourcepub async fn maintain(&self)
pub async fn maintain(&self)
One maintenance pass: rotate out an over-age peer, then refill toward capacity.
Cycling before refilling is deliberate. Refilling first would find the pool at capacity and do nothing, so the rotation would leave a permanently smaller pool.
Sourcepub async fn try_refill(&self)
pub async fn try_refill(&self)
If the pool is under capacity, try to connect one new peer.
Also spawns a background task to handle its inbound NewPeakWallet
messages.
Sourcepub async fn subscribe_frames(&self, capacity: usize) -> FrameSubscription
pub async fn subscribe_frames(&self, capacity: usize) -> FrameSubscription
Subscribe to this pool’s frames, with room for capacity unread ones.
Falling further behind than capacity ENDS the subscription — see
FrameSubscription for why a gap is not an option.
Auto Trait Implementations§
impl !Freeze for PeerPool
impl !RefUnwindSafe for PeerPool
impl !UnwindSafe for PeerPool
impl Send for PeerPool
impl Sync for PeerPool
impl Unpin for PeerPool
impl UnsafeUnpin for PeerPool
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.