Skip to main content

zebra_network/peer_set/
set.rs

1//! Abstractions that represent "the rest of the network".
2//!
3//! # Implementation
4//!
5//! The [`PeerSet`] implementation is adapted from the one in [tower::Balance][tower-balance].
6//!
7//! As described in Tower's documentation, it:
8//!
9//! > Distributes requests across inner services using the [Power of Two Choices][p2c].
10//! >
11//! > As described in the [Finagle Guide][finagle]:
12//! >
13//! > > The algorithm randomly picks two services from the set of ready endpoints and
14//! > > selects the least loaded of the two. By repeatedly using this strategy, we can
15//! > > expect a manageable upper bound on the maximum load of any server.
16//! > >
17//! > > The maximum load variance between any two servers is bound by `ln(ln(n))` where
18//! > > `n` is the number of servers in the cluster.
19//!
20//! The Power of Two Choices should work well for many network requests, but not all of them.
21//! Some requests should only be made to a subset of connected peers.
22//! For example, a request for a particular inventory item
23//! should be made to a peer that has recently advertised that inventory hash.
24//! Other requests require broadcasts, such as transaction diffusion.
25//!
26//! Implementing this specialized routing logic inside the `PeerSet` -- so that
27//! it continues to abstract away "the rest of the network" into one endpoint --
28//! is not a problem, as the `PeerSet` can simply maintain more information on
29//! its peers and route requests appropriately. However, there is a problem with
30//! maintaining accurate backpressure information, because the `Service` trait
31//! requires that service readiness is independent of the data in the request.
32//!
33//! For this reason, in the future, this code will probably be refactored to
34//! address this backpressure mismatch. One possibility is to refactor the code
35//! so that one entity holds and maintains the peer set and metadata on the
36//! peers, and each "backpressure category" of request is assigned to different
37//! `Service` impls with specialized `poll_ready()` implementations. Another
38//! less-elegant solution (which might be useful as an intermediate step for the
39//! inventory case) is to provide a way to borrow a particular backing service,
40//! say by address.
41//!
42//! [finagle]: https://twitter.github.io/finagle/guide/Clients.html#power-of-two-choices-p2c-least-loaded
43//! [p2c]: http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf
44//! [tower-balance]: https://github.com/tower-rs/tower/tree/master/tower/src/balance
45//!
46//! # Behavior During Network Upgrades
47//!
48//! [ZIP-201] specifies peer behavior during network upgrades:
49//!
50//! > With scheduled network upgrades, at the activation height, nodes on each consensus branch
51//! > should disconnect from nodes on other consensus branches and only accept new incoming
52//! > connections from nodes on the same consensus branch.
53//!
54//! Zebra handles this with the help of [`MinimumPeerVersion`], which determines the minimum peer
55//! protocol version to accept based on the current best chain tip height. The minimum version is
56//! therefore automatically increased when the block height reaches a network upgrade's activation
57//! height. The helper type is then used to:
58//!
59//! - cancel handshakes to outdated peers, in `handshake::negotiate_version`
60//! - cancel requests to and disconnect from peers that have become outdated, in
61//!   [`PeerSet::push_unready`]
62//! - disconnect from peers that have just responded and became outdated, in
63//!   [`PeerSet::poll_unready`]
64//! - disconnect from idle peers that have become outdated, in
65//!   [`PeerSet::disconnect_from_outdated_peers`]
66//!
67//! ## Network Coalescence
68//!
69//! [ZIP-201] also specifies how Zcashd behaves [leading up to a activation
70//! height][1]. Since Zcashd limits the number of connections to at most eight
71//! peers, it will gradually migrate its connections to up-to-date peers as it
72//! approaches the activation height.
73//!
74//! The motivation for this behavior is to avoid an abrupt partitioning the network, which can lead
75//! to isolated peers and increases the chance of an eclipse attack on some peers of the network.
76//!
77//! Zebra does not gradually migrate its peers as it approaches an activation height. This is
78//! because Zebra by default can connect to up to 75 peers, as can be seen in [`Config::default`].
79//! Since this is a lot larger than the 8 peers Zcashd connects to, an eclipse attack becomes a lot
80//! more costly to execute, and the probability of an abrupt network partition that isolates peers
81//! is lower.
82//!
83//! Even if a Zebra node is manually configured to connect to a smaller number
84//! of peers, the [`AddressBook`][2] is configured to hold a large number of
85//! peer addresses ([`MAX_ADDRS_IN_ADDRESS_BOOK`][3]). Since the address book
86//! prioritizes addresses it trusts (like those that it has successfully
87//! connected to before), the node should be able to recover and rejoin the
88//! network by itself, as long as the address book is populated with enough
89//! entries.
90//!
91//! [1]: https://zips.z.cash/zip-0201#network-coalescence
92//! [2]: crate::AddressBook
93//! [3]: crate::constants::MAX_ADDRS_IN_ADDRESS_BOOK
94//! [ZIP-201]: https://zips.z.cash/zip-0201
95
96use std::{
97    collections::{HashMap, HashSet},
98    convert,
99    fmt::Debug,
100    marker::PhantomData,
101    net::IpAddr,
102    pin::Pin,
103    sync::Arc,
104    task::{Context, Poll},
105    time::Instant,
106};
107
108use futures::{
109    channel::{mpsc, oneshot},
110    future::{FutureExt, TryFutureExt},
111    prelude::*,
112    stream::FuturesUnordered,
113    task::noop_waker,
114};
115use indexmap::IndexMap;
116use itertools::Itertools;
117use num_integer::div_ceil;
118use tokio::{
119    sync::{broadcast, watch},
120    task::JoinHandle,
121};
122use tower::{
123    discover::{Change, Discover},
124    load::Load,
125    Service,
126};
127
128use zebra_chain::{chain_tip::ChainTip, parameters::Network};
129
130use crate::{
131    address_book::AddressMetrics,
132    constants::MIN_PEER_SET_LOG_INTERVAL,
133    peer::{LoadTrackedClient, MinimumPeerVersion},
134    peer_set::{
135        unready_service::{Error as UnreadyError, UnreadyService},
136        InventoryChange, InventoryRegistry,
137    },
138    protocol::{
139        external::InventoryHash,
140        internal::{Request, Response},
141    },
142    BoxError, Config, PeerError, PeerSocketAddr, SharedPeerError,
143};
144
145#[cfg(test)]
146mod tests;
147
148/// A signal sent by the [`PeerSet`] when it has no ready peers, and gets a request from Zebra.
149///
150/// In response to this signal, the crawler tries to open more peer connections.
151#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
152pub struct MorePeers;
153
154/// A signal sent by the [`PeerSet`] to cancel a [`Client`][1]'s current request
155/// or response.
156///
157/// When it receives this signal, the [`Client`][1] stops processing and exits.
158///
159/// [1]: crate::peer::Client
160#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
161pub struct CancelClientWork;
162
163type ResponseFuture = Pin<Box<dyn Future<Output = Result<Response, BoxError>> + Send + 'static>>;
164
165/// A [`tower::Service`] that abstractly represents "the rest of the network".
166///
167/// # Security
168///
169/// The `Discover::Key` must be the transient remote address of each peer. This
170/// address may only be valid for the duration of a single connection. (For
171/// example, inbound connections have an ephemeral remote port, and proxy
172/// connections have an ephemeral local or proxy port.)
173///
174/// Otherwise, malicious peers could interfere with other peers' `PeerSet` state.
175pub struct PeerSet<D, C>
176where
177    D: Discover<Key = PeerSocketAddr, Service = LoadTrackedClient> + Unpin,
178    D::Error: Into<BoxError>,
179    C: ChainTip,
180{
181    // Peer Tracking: New Peers
182    //
183    /// Provides new and deleted peer [`Change`]s to the peer set,
184    /// via the [`Discover`] trait implementation.
185    discover: D,
186
187    /// A channel that asks the peer crawler task to connect to more peers.
188    demand_signal: mpsc::Sender<MorePeers>,
189
190    /// A watch channel receiver with a copy of banned IP addresses.
191    bans_receiver: watch::Receiver<Arc<IndexMap<IpAddr, std::time::Instant>>>,
192
193    // Peer Tracking: Ready Peers
194    //
195    /// Connected peers that are ready to receive requests from Zebra,
196    /// or send requests to Zebra.
197    ready_services: HashMap<D::Key, D::Service>,
198
199    // Request Routing
200    //
201    /// Stores gossiped inventory hashes from connected peers.
202    ///
203    /// Used to route inventory requests to peers that are likely to have it.
204    inventory_registry: InventoryRegistry,
205
206    /// Stores requests that should be routed to peers once they are ready.
207    queued_broadcast_all: Option<(
208        Request,
209        tokio::sync::mpsc::Sender<ResponseFuture>,
210        HashSet<D::Key>,
211    )>,
212
213    // Peer Tracking: Busy Peers
214    //
215    /// Connected peers that are handling a Zebra request,
216    /// or Zebra is handling one of their requests.
217    unready_services: FuturesUnordered<UnreadyService<D::Key, D::Service, Request>>,
218
219    /// Channels used to cancel the request that an unready service is doing.
220    cancel_handles: HashMap<D::Key, oneshot::Sender<CancelClientWork>>,
221
222    // Peer Validation
223    //
224    /// An endpoint to see the minimum peer protocol version in real time.
225    ///
226    /// The minimum version depends on the block height, and [`MinimumPeerVersion`] listens for
227    /// height changes and determines the correct minimum version.
228    minimum_peer_version: MinimumPeerVersion<C>,
229
230    /// The configured limit for inbound and outbound connections.
231    ///
232    /// The peer set panics if this size is exceeded.
233    /// If that happens, our connection limit code has a bug.
234    peerset_total_connection_limit: usize,
235
236    // Background Tasks
237    //
238    /// Channel for passing ownership of tokio JoinHandles from PeerSet's background tasks
239    ///
240    /// The join handles passed into the PeerSet are used populate the `guards` member
241    handle_rx: tokio::sync::oneshot::Receiver<Vec<JoinHandle<Result<(), BoxError>>>>,
242
243    /// Unordered set of handles to background tasks associated with the `PeerSet`
244    ///
245    /// These guards are checked for errors as part of `poll_ready` which lets
246    /// the `PeerSet` propagate errors from background tasks back to the user
247    guards: futures::stream::FuturesUnordered<JoinHandle<Result<(), BoxError>>>,
248
249    // Metrics and Logging
250    //
251    /// Address book metrics watch channel.
252    ///
253    /// Used for logging diagnostics.
254    address_metrics: watch::Receiver<AddressMetrics>,
255
256    /// The last time we logged a message about the peer set size
257    last_peer_log: Option<Instant>,
258
259    /// The configured maximum number of peers that can be in the
260    /// peer set per IP, defaults to [`crate::constants::DEFAULT_MAX_CONNS_PER_IP`]
261    max_conns_per_ip: usize,
262
263    /// The network of this peer set.
264    network: Network,
265}
266
267impl<D, C> Drop for PeerSet<D, C>
268where
269    D: Discover<Key = PeerSocketAddr, Service = LoadTrackedClient> + Unpin,
270    D::Error: Into<BoxError>,
271    C: ChainTip,
272{
273    fn drop(&mut self) {
274        // We don't have access to the current task (if any), so we just drop everything we can.
275        let waker = noop_waker();
276        let mut cx = Context::from_waker(&waker);
277
278        self.shut_down_tasks_and_channels(&mut cx);
279    }
280}
281
282impl<D, C> PeerSet<D, C>
283where
284    D: Discover<Key = PeerSocketAddr, Service = LoadTrackedClient> + Unpin,
285    D::Error: Into<BoxError>,
286    C: ChainTip,
287{
288    #[allow(clippy::too_many_arguments)]
289    /// Construct a peerset which uses `discover` to manage peer connections.
290    ///
291    /// Arguments:
292    /// - `config`: configures the peer set connection limit;
293    /// - `discover`: handles peer connects and disconnects;
294    /// - `demand_signal`: requests more peers when all peers are busy (unready);
295    /// - `handle_rx`: receives background task handles,
296    ///   monitors them to make sure they're still running,
297    ///   and shuts down all the tasks as soon as one task exits;
298    /// - `inv_stream`: receives inventory changes from peers,
299    ///   allowing the peer set to direct inventory requests;
300    /// - `bans_receiver`: receives a map of banned IP addresses that should be dropped;
301    /// - `address_book`: when peer set is busy, it logs address book diagnostics.
302    /// - `minimum_peer_version`: endpoint to see the minimum peer protocol version in real time.
303    /// - `max_conns_per_ip`: configured maximum number of peers that can be in the
304    ///   peer set per IP, defaults to the config value or to
305    ///   [`crate::constants::DEFAULT_MAX_CONNS_PER_IP`].
306    pub fn new(
307        config: &Config,
308        discover: D,
309        demand_signal: mpsc::Sender<MorePeers>,
310        handle_rx: tokio::sync::oneshot::Receiver<Vec<JoinHandle<Result<(), BoxError>>>>,
311        inv_stream: broadcast::Receiver<InventoryChange>,
312        bans_receiver: watch::Receiver<Arc<IndexMap<IpAddr, std::time::Instant>>>,
313        address_metrics: watch::Receiver<AddressMetrics>,
314        minimum_peer_version: MinimumPeerVersion<C>,
315        max_conns_per_ip: Option<usize>,
316    ) -> Self {
317        Self {
318            // New peers
319            discover,
320            demand_signal,
321            // Banned peers
322            bans_receiver,
323
324            // Ready peers
325            ready_services: HashMap::new(),
326            // Request Routing
327            inventory_registry: InventoryRegistry::new(inv_stream),
328            queued_broadcast_all: None,
329
330            // Busy peers
331            unready_services: FuturesUnordered::new(),
332            cancel_handles: HashMap::new(),
333
334            // Peer validation
335            minimum_peer_version,
336            peerset_total_connection_limit: config.peerset_total_connection_limit(),
337
338            // Background tasks
339            handle_rx,
340            guards: futures::stream::FuturesUnordered::new(),
341
342            // Metrics
343            last_peer_log: None,
344            address_metrics,
345
346            max_conns_per_ip: max_conns_per_ip.unwrap_or(config.max_connections_per_ip),
347
348            network: config.network.clone(),
349        }
350    }
351
352    /// Check background task handles to make sure they're still running.
353    ///
354    /// Never returns `Ok`.
355    ///
356    /// If any background task exits, shuts down all other background tasks,
357    /// and returns an error. Otherwise, returns `Pending`, and registers a wakeup for
358    /// receiving the background tasks, or the background tasks exiting.
359    fn poll_background_errors(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), BoxError>> {
360        futures::ready!(self.receive_tasks_if_needed(cx))?;
361
362        // Return Pending if all background tasks are still running.
363        match futures::ready!(Pin::new(&mut self.guards).poll_next(cx)) {
364            Some(res) => {
365                info!(
366                    background_tasks = %self.guards.len(),
367                    "a peer set background task exited, shutting down other peer set tasks"
368                );
369
370                self.shut_down_tasks_and_channels(cx);
371
372                // Flatten the join result and inner result, and return any errors.
373                res.map_err(Into::into)
374                    // TODO: replace with Result::flatten when it stabilises (#70142)
375                    .and_then(convert::identity)?;
376
377                // Turn Ok() task exits into errors.
378                Poll::Ready(Err("a peer set background task exited".into()))
379            }
380
381            None => {
382                self.shut_down_tasks_and_channels(cx);
383                Poll::Ready(Err("all peer set background tasks have exited".into()))
384            }
385        }
386    }
387
388    /// Receive background tasks, if they've been sent on the channel, but not consumed yet.
389    ///
390    /// Returns a result representing the current task state, or `Poll::Pending` if the background
391    /// tasks should be polled again to check their state.
392    fn receive_tasks_if_needed(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), BoxError>> {
393        if self.guards.is_empty() {
394            // Return Pending if the tasks have not been sent yet.
395            let handles = futures::ready!(Pin::new(&mut self.handle_rx).poll(cx));
396
397            match handles {
398                // The tasks have been sent, but not consumed yet.
399                Ok(handles) => {
400                    // Currently, the peer set treats an empty background task set as an error.
401                    //
402                    // TODO: refactor `handle_rx` and `guards` into an enum
403                    //       for the background task state: Waiting/Running/Shutdown.
404                    assert!(
405                        !handles.is_empty(),
406                        "the peer set requires at least one background task"
407                    );
408
409                    self.guards.extend(handles);
410
411                    Poll::Ready(Ok(()))
412                }
413
414                // The sender was dropped without sending the tasks.
415                Err(_) => Poll::Ready(Err(
416                    "sender did not send peer background tasks before it was dropped".into(),
417                )),
418            }
419        } else {
420            Poll::Ready(Ok(()))
421        }
422    }
423
424    /// Shut down:
425    /// - services by dropping the service lists
426    /// - background tasks via their join handles or cancel handles
427    /// - channels by closing the channel
428    fn shut_down_tasks_and_channels(&mut self, cx: &mut Context<'_>) {
429        // Drop services and cancel their background tasks.
430        self.ready_services = HashMap::new();
431
432        for (_peer_key, handle) in self.cancel_handles.drain() {
433            let _ = handle.send(CancelClientWork);
434        }
435        self.unready_services = FuturesUnordered::new();
436
437        // Close the MorePeers channel for all senders,
438        // so we don't add more peers to a shut down peer set.
439        self.demand_signal.close_channel();
440
441        // Shut down background tasks, ignoring pending polls.
442        self.handle_rx.close();
443        let _ = self.receive_tasks_if_needed(cx);
444        for guard in self.guards.iter() {
445            guard.abort();
446        }
447    }
448
449    /// Checks for newly ready, disconnects from outdated peers, and polls ready peer errors.
450    fn poll_peers(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), BoxError>> {
451        // Check for newly ready peers, including newly added peers (which are added as unready).
452        // So it needs to run after `poll_discover()`. Registers a wakeup if there are any unready
453        // peers.
454        //
455        // Each connected peer should become ready within a few minutes, or timeout, close the
456        // connection, and release its connection slot.
457        //
458        // TODO: drop peers that overload us with inbound messages and never become ready (#7822)
459        let _poll_pending_or_ready: Poll<Option<()>> = self.poll_unready(cx)?;
460
461        // Cleanup
462
463        // Only checks the versions of ready peers, so it needs to run after `poll_unready()`.
464        self.disconnect_from_outdated_peers();
465
466        // Check for failures in ready peers, removing newly errored or disconnected peers.
467        // So it needs to run after `poll_unready()`.
468        self.poll_ready_peer_errors(cx).map(Ok)
469    }
470
471    /// Check busy peer services for request completion or errors.
472    ///
473    /// Move newly ready services to the ready list if they are for peers with supported protocol
474    /// versions, otherwise they are dropped. Also drop failed services.
475    ///
476    /// Never returns an error.
477    ///
478    /// Returns `Ok(Some(())` if at least one peer became ready, `Poll::Pending` if there are
479    /// unready peers, but none became ready, and `Ok(None)` if the unready peers were empty.
480    ///
481    /// If there are any remaining unready peers, registers a wakeup for the next time one becomes
482    /// ready. If there are no unready peers, doesn't register any wakeups. (Since wakeups come
483    /// from peers, there needs to be at least one peer to register a wakeup.)
484    fn poll_unready(&mut self, cx: &mut Context<'_>) -> Poll<Result<Option<()>, BoxError>> {
485        let mut result = Poll::Pending;
486
487        // # Correctness
488        //
489        // `poll_next()` must always be called, because `self.unready_services` could have been
490        // empty before the call to `self.poll_ready()`.
491        //
492        // > When new futures are added, `poll_next` must be called in order to begin receiving
493        // > wake-ups for new futures.
494        //
495        // <https://docs.rs/futures/latest/futures/stream/futures_unordered/struct.FuturesUnordered.html>
496        //
497        // Returns Pending if we've finished processing the unready service changes,
498        // but there are still some unready services.
499        loop {
500            // No ready peers left, but there are some unready peers pending.
501            let Poll::Ready(ready_peer) = Pin::new(&mut self.unready_services).poll_next(cx) else {
502                break;
503            };
504
505            match ready_peer {
506                // No unready peers in the list.
507                None => {
508                    // If we've finished processing the unready service changes, and there are no
509                    // unready services left, it doesn't make sense to return Pending, because
510                    // their stream is terminated. But when we add more unready peers and call
511                    // `poll_next()`, its termination status will be reset, and it will receive
512                    // wakeups again.
513                    if result.is_pending() {
514                        result = Poll::Ready(Ok(None));
515                    }
516
517                    break;
518                }
519
520                // Unready -> Ready
521                Some(Ok((key, svc))) => {
522                    trace!(?key, "service became ready");
523
524                    if self.bans_receiver.borrow().contains_key(&key.ip()) {
525                        warn!(?key, "service is banned, dropping service");
526                        std::mem::drop(svc);
527                        let cancel = self.cancel_handles.remove(&key);
528                        debug_assert!(
529                            cancel.is_some(),
530                            "missing cancel handle for banned unready peer"
531                        );
532                        continue;
533                    }
534
535                    self.push_ready(true, key, svc);
536
537                    // Return Ok if at least one peer became ready.
538                    result = Poll::Ready(Ok(Some(())));
539                }
540
541                // Unready -> Canceled
542                Some(Err((key, UnreadyError::Canceled))) => {
543                    // A service be canceled because we've connected to the same service twice.
544                    // In that case, there is a cancel handle for the peer address,
545                    // but it belongs to the service for the newer connection.
546                    trace!(
547                        ?key,
548                        duplicate_connection = self.cancel_handles.contains_key(&key),
549                        "service was canceled, dropping service"
550                    );
551                }
552                Some(Err((key, UnreadyError::CancelHandleDropped(_)))) => {
553                    // Similarly, services with dropped cancel handes can have duplicates.
554                    trace!(
555                        ?key,
556                        duplicate_connection = self.cancel_handles.contains_key(&key),
557                        "cancel handle was dropped, dropping service"
558                    );
559                }
560
561                // Unready -> Errored
562                Some(Err((key, UnreadyError::Inner(error)))) => {
563                    debug!(%error, "service failed while unready, dropping service");
564
565                    let cancel = self.cancel_handles.remove(&key);
566                    assert!(cancel.is_some(), "missing cancel handle");
567                }
568            }
569        }
570
571        result
572    }
573
574    /// Checks previously ready peer services for errors.
575    ///
576    /// The only way these peer `Client`s can become unready is when we send them a request,
577    /// because the peer set has exclusive access to send requests to each peer. (If an inbound
578    /// request is in progress, it will be handled, then our request will be sent by the connection
579    /// task.)
580    ///
581    /// Returns `Poll::Ready` if there are some ready peers, and `Poll::Pending` if there are no
582    /// ready peers. Registers a wakeup if any peer has failed due to a disconnection, hang, or protocol error.
583    ///
584    /// # Panics
585    ///
586    /// If any peers somehow became unready without being sent a request. This indicates a bug in the peer set, where requests
587    /// are sent to peers without putting them in `unready_peers`.
588    fn poll_ready_peer_errors(&mut self, cx: &mut Context<'_>) -> Poll<()> {
589        let mut previous = HashMap::new();
590        std::mem::swap(&mut previous, &mut self.ready_services);
591
592        // TODO: consider only checking some peers each poll (for performance reasons),
593        //       but make sure we eventually check all of them.
594        for (key, mut svc) in previous.drain() {
595            let Poll::Ready(peer_readiness) = Pin::new(&mut svc).poll_ready(cx) else {
596                unreachable!(
597                    "unexpected unready peer: peers must be put into the unready_peers list \
598                     after sending them a request"
599                );
600            };
601
602            match peer_readiness {
603                // Still ready, add it back to the list.
604                Ok(()) => {
605                    if self.bans_receiver.borrow().contains_key(&key.ip()) {
606                        debug!(?key, "service ip is banned, dropping service");
607                        std::mem::drop(svc);
608                        continue;
609                    }
610
611                    self.push_ready(false, key, svc)
612                }
613
614                // Ready -> Errored
615                Err(error) => {
616                    debug!(%error, "service failed while ready, dropping service");
617
618                    // Ready services can just be dropped, they don't need any cleanup.
619                    std::mem::drop(svc);
620                }
621            }
622        }
623
624        if self.ready_services.is_empty() {
625            Poll::Pending
626        } else {
627            Poll::Ready(())
628        }
629    }
630
631    /// Returns the number of peer connections Zebra already has with
632    /// the provided IP address
633    ///
634    /// # Performance
635    ///
636    /// This method is `O(connected peers)`, so it should not be called from a loop
637    /// that is already iterating through the peer set.
638    fn num_peers_with_ip(&self, ip: IpAddr) -> usize {
639        self.ready_services
640            .keys()
641            .chain(self.cancel_handles.keys())
642            .filter(|addr| addr.ip() == ip)
643            .count()
644    }
645
646    /// Returns `true` if Zebra is already connected to the IP and port in `addr`.
647    fn has_peer_with_addr(&self, addr: PeerSocketAddr) -> bool {
648        self.ready_services.contains_key(&addr) || self.cancel_handles.contains_key(&addr)
649    }
650
651    /// Processes the entire list of newly inserted or removed services.
652    ///
653    /// Puts inserted services in the unready list.
654    /// Drops removed services, after cancelling any pending requests.
655    ///
656    /// If the peer connector channel is closed, returns an error.
657    ///
658    /// Otherwise, returns `Ok` if it discovered at least one peer, or `Poll::Pending` if it didn't
659    /// discover any peers. Always registers a wakeup for new peers, even when it returns `Ok`.
660    fn poll_discover(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), BoxError>> {
661        // Return pending if there are no peers in the list.
662        let mut result = Poll::Pending;
663
664        loop {
665            // If we've emptied the list, finish looping, otherwise process the new peer.
666            let Poll::Ready(discovered) = Pin::new(&mut self.discover).poll_discover(cx) else {
667                break;
668            };
669
670            // If the change channel has a permanent error, return that error.
671            let change = discovered
672                .ok_or("discovery stream closed")?
673                .map_err(Into::into)?;
674
675            // Otherwise we have successfully processed a peer.
676            result = Poll::Ready(Ok(()));
677
678            // Process each change.
679            match change {
680                Change::Remove(key) => {
681                    trace!(?key, "got Change::Remove from Discover");
682                    self.remove(&key);
683                }
684                Change::Insert(key, svc) => {
685                    // We add peers as unready, so that we:
686                    // - always do the same checks on every ready peer, and
687                    // - check for any errors that happened right after the handshake
688                    trace!(?key, "got Change::Insert from Discover");
689
690                    // # Security
691                    //
692                    // Drop the new peer if we are already connected to it.
693                    // Preferring old connections avoids connection thrashing.
694                    if self.has_peer_with_addr(key) {
695                        std::mem::drop(svc);
696                        continue;
697                    }
698
699                    // # Security
700                    //
701                    // drop the new peer if there are already `max_conns_per_ip` peers with
702                    // the same IP address in the peer set.
703                    if self.num_peers_with_ip(key.ip()) >= self.max_conns_per_ip {
704                        std::mem::drop(svc);
705                        continue;
706                    }
707
708                    self.push_unready(key, svc);
709                }
710            }
711        }
712
713        result
714    }
715
716    /// Checks if the minimum peer version has changed, and disconnects from outdated peers.
717    fn disconnect_from_outdated_peers(&mut self) {
718        if let Some(minimum_version) = self.minimum_peer_version.changed() {
719            // It is ok to drop ready services, they don't need anything cancelled.
720            self.ready_services
721                .retain(|_address, peer| peer.remote_version() >= minimum_version);
722        }
723    }
724
725    /// Takes a ready service by key.
726    fn take_ready_service(&mut self, key: &D::Key) -> Option<D::Service> {
727        if let Some(svc) = self.ready_services.remove(key) {
728            assert!(
729                !self.cancel_handles.contains_key(key),
730                "cancel handles are only used for unready service work"
731            );
732
733            Some(svc)
734        } else {
735            None
736        }
737    }
738
739    /// Remove the service corresponding to `key` from the peer set.
740    ///
741    /// Drops the service, cancelling any pending request or response to that peer.
742    /// If the peer does not exist, does nothing.
743    fn remove(&mut self, key: &D::Key) {
744        if let Some(ready_service) = self.take_ready_service(key) {
745            // A ready service has no work to cancel, so just drop it.
746            std::mem::drop(ready_service);
747        } else if let Some(handle) = self.cancel_handles.remove(key) {
748            // Cancel the work, implicitly dropping the cancel handle.
749            // The service future returns a `Canceled` error,
750            // making `poll_unready` drop the service.
751            let _ = handle.send(CancelClientWork);
752        }
753    }
754
755    /// Adds a ready service to the ready list if it's for a peer with a supported version.
756    /// If `was_unready` is true, also removes the peer's cancel handle.
757    ///
758    /// If the service is for a connection to an outdated peer, the service is dropped.
759    fn push_ready(&mut self, was_unready: bool, key: D::Key, svc: D::Service) {
760        let cancel = self.cancel_handles.remove(&key);
761        assert_eq!(
762            cancel.is_some(),
763            was_unready,
764            "missing or unexpected cancel handle"
765        );
766
767        if svc.remote_version() >= self.minimum_peer_version.current() {
768            self.ready_services.insert(key, svc);
769        } else {
770            std::mem::drop(svc);
771        }
772    }
773
774    /// Adds a busy service to the unready list if it's for a peer with a supported version,
775    /// and adds a cancel handle for the service's current request.
776    ///
777    /// If the service is for a connection to an outdated peer, the request is cancelled and the
778    /// service is dropped.
779    fn push_unready(&mut self, key: D::Key, svc: D::Service) {
780        let peer_version = svc.remote_version();
781        let (tx, rx) = oneshot::channel();
782
783        self.unready_services.push(UnreadyService {
784            key: Some(key),
785            service: Some(svc),
786            cancel: rx,
787            _req: PhantomData,
788        });
789
790        if peer_version >= self.minimum_peer_version.current() {
791            self.cancel_handles.insert(key, tx);
792        } else {
793            // Cancel any request made to the service because it is using an outdated protocol
794            // version.
795            let _ = tx.send(CancelClientWork);
796        }
797    }
798
799    /// Performs P2C on `self.ready_services` to randomly select a less-loaded ready service.
800    fn select_ready_p2c_peer(&self) -> Option<D::Key> {
801        self.select_p2c_peer_from_list(&self.ready_services.keys().copied().collect())
802    }
803
804    /// Performs P2C on `ready_service_list` to randomly select a less-loaded ready service.
805    #[allow(clippy::unwrap_in_result)]
806    fn select_p2c_peer_from_list(&self, ready_service_list: &HashSet<D::Key>) -> Option<D::Key> {
807        match ready_service_list.len() {
808            0 => None,
809            1 => Some(
810                *ready_service_list
811                    .iter()
812                    .next()
813                    .expect("just checked there is one service"),
814            ),
815            len => {
816                // Choose 2 random peers, then return the least loaded of those 2 peers.
817                let (a, b) = {
818                    let idxs = rand::seq::index::sample(&mut rand::thread_rng(), len, 2);
819                    let a = idxs.index(0);
820                    let b = idxs.index(1);
821
822                    let a = *ready_service_list
823                        .iter()
824                        .nth(a)
825                        .expect("sample returns valid indexes");
826                    let b = *ready_service_list
827                        .iter()
828                        .nth(b)
829                        .expect("sample returns valid indexes");
830
831                    (a, b)
832                };
833
834                let a_load = self.query_load(&a).expect("supplied services are ready");
835                let b_load = self.query_load(&b).expect("supplied services are ready");
836
837                let selected = if a_load <= b_load { a } else { b };
838
839                trace!(
840                    a.key = ?a,
841                    a.load = ?a_load,
842                    b.key = ?b,
843                    b.load = ?b_load,
844                    selected = ?selected,
845                    ?len,
846                    "selected service by p2c"
847                );
848
849                Some(selected)
850            }
851        }
852    }
853
854    /// Randomly chooses `max_peers` ready services, ignoring service load.
855    ///
856    /// The chosen peers are unique, but their order is not fully random.
857    fn select_random_ready_peers(&self, max_peers: usize) -> Vec<D::Key> {
858        use rand::seq::IteratorRandom;
859
860        self.ready_services
861            .keys()
862            .copied()
863            .choose_multiple(&mut rand::thread_rng(), max_peers)
864    }
865
866    /// Accesses a ready endpoint by `key` and returns its current load.
867    ///
868    /// Returns `None` if the service is not in the ready service list.
869    fn query_load(&self, key: &D::Key) -> Option<<D::Service as Load>::Metric> {
870        let svc = self.ready_services.get(key);
871        svc.map(|svc| svc.load())
872    }
873
874    /// Routes a request using P2C load-balancing.
875    fn route_p2c(&mut self, req: Request) -> <Self as tower::Service<Request>>::Future {
876        if let Some(p2c_key) = self.select_ready_p2c_peer() {
877            tracing::trace!(?p2c_key, "routing based on p2c");
878
879            let mut svc = self
880                .take_ready_service(&p2c_key)
881                .expect("selected peer must be ready");
882
883            let fut = svc.call(req);
884            self.push_unready(p2c_key, svc);
885
886            return fut.map_err(Into::into).boxed();
887        }
888
889        async move {
890            // Let other tasks run, so a retry request might get different ready peers.
891            tokio::task::yield_now().await;
892
893            // # Security
894            //
895            // Avoid routing requests to peers that are missing inventory.
896            // If we kept trying doomed requests, peers that are missing our requested inventory
897            // could take up a large amount of our bandwidth and retry limits.
898            Err(SharedPeerError::from(PeerError::NoReadyPeers))
899        }
900        .map_err(Into::into)
901        .boxed()
902    }
903
904    /// Tries to route a request to a ready peer that advertised that inventory,
905    /// falling back to a ready peer that isn't missing the inventory.
906    ///
907    /// If all ready peers are missing the inventory,
908    /// returns a synthetic [`NotFoundRegistry`](PeerError::NotFoundRegistry) error.
909    ///
910    /// Uses P2C to route requests to the least loaded peer in each list.
911    fn route_inv(
912        &mut self,
913        req: Request,
914        hash: InventoryHash,
915    ) -> <Self as tower::Service<Request>>::Future {
916        let advertising_peer_list = self
917            .inventory_registry
918            .advertising_peers(hash)
919            .filter(|&addr| self.ready_services.contains_key(addr))
920            .copied()
921            .collect();
922
923        // # Security
924        //
925        // Choose a random, less-loaded peer with the inventory.
926        //
927        // If we chose the first peer in HashMap order,
928        // peers would be able to influence our choice by switching addresses.
929        // But we need the choice to be random,
930        // so that a peer can't provide all our inventory responses.
931        let peer = self.select_p2c_peer_from_list(&advertising_peer_list);
932
933        if let Some(mut svc) = peer.and_then(|key| self.take_ready_service(&key)) {
934            let peer = peer.expect("just checked peer is Some");
935            tracing::trace!(?hash, ?peer, "routing to a peer which advertised inventory");
936            let fut = svc.call(req);
937            self.push_unready(peer, svc);
938            return fut.map_err(Into::into).boxed();
939        }
940
941        let missing_peer_list: HashSet<PeerSocketAddr> = self
942            .inventory_registry
943            .missing_peers(hash)
944            .copied()
945            .collect();
946        let maybe_peer_list = self
947            .ready_services
948            .keys()
949            .filter(|addr| !missing_peer_list.contains(addr))
950            .copied()
951            .collect();
952
953        // Security: choose a random, less-loaded peer that might have the inventory.
954        let peer = self.select_p2c_peer_from_list(&maybe_peer_list);
955
956        if let Some(mut svc) = peer.and_then(|key| self.take_ready_service(&key)) {
957            let peer = peer.expect("just checked peer is Some");
958            tracing::trace!(?hash, ?peer, "routing to a peer that might have inventory");
959            let fut = svc.call(req);
960            self.push_unready(peer, svc);
961            return fut.map_err(Into::into).boxed();
962        }
963
964        tracing::debug!(
965            ?hash,
966            "all ready peers are missing inventory, failing request"
967        );
968
969        async move {
970            // Let other tasks run, so a retry request might get different ready peers.
971            tokio::task::yield_now().await;
972
973            // # Security
974            //
975            // Avoid routing requests to peers that are missing inventory.
976            // If we kept trying doomed requests, peers that are missing our requested inventory
977            // could take up a large amount of our bandwidth and retry limits.
978            Err(SharedPeerError::from(PeerError::NotFoundRegistry(vec![
979                hash,
980            ])))
981        }
982        .map_err(Into::into)
983        .boxed()
984    }
985
986    /// Routes the same request to up to `max_peers` ready peers, ignoring return values.
987    ///
988    /// `max_peers` must be at least one, and at most the number of ready peers.
989    fn route_multiple(
990        &mut self,
991        req: Request,
992        max_peers: usize,
993    ) -> <Self as tower::Service<Request>>::Future {
994        assert!(
995            max_peers > 0,
996            "requests must be routed to at least one peer"
997        );
998        assert!(
999            max_peers <= self.ready_services.len(),
1000            "requests can only be routed to ready peers"
1001        );
1002
1003        let selected_peers = self.select_random_ready_peers(max_peers);
1004        self.send_multiple(req, selected_peers)
1005    }
1006
1007    /// Sends the same request to the provided ready peers, ignoring return values.
1008    ///
1009    /// # Security
1010    ///
1011    /// Callers should choose peers randomly, ignoring load.
1012    /// This avoids favouring malicious peers, because peers can influence their own load.
1013    ///
1014    /// The order of peers isn't completely random,
1015    /// but peer request order is not security-sensitive.
1016    fn send_multiple(
1017        &mut self,
1018        req: Request,
1019        peers: Vec<D::Key>,
1020    ) -> <Self as tower::Service<Request>>::Future {
1021        let futs = FuturesUnordered::new();
1022        for key in peers {
1023            let mut svc = self
1024                .take_ready_service(&key)
1025                .expect("selected peers are ready");
1026            futs.push(svc.call(req.clone()).map_err(|_| ()));
1027            self.push_unready(key, svc);
1028        }
1029
1030        async move {
1031            let results = futs.collect::<Vec<Result<_, _>>>().await;
1032            tracing::debug!(
1033                ok.len = results.iter().filter(|r| r.is_ok()).count(),
1034                err.len = results.iter().filter(|r| r.is_err()).count(),
1035                "sent peer request to multiple peers"
1036            );
1037            Ok(Response::Nil)
1038        }
1039        .boxed()
1040    }
1041
1042    /// Broadcasts the same request to lots of ready peers, ignoring return values.
1043    fn route_broadcast(&mut self, req: Request) -> <Self as tower::Service<Request>>::Future {
1044        // Broadcasts ignore the response
1045        self.route_multiple(req, self.number_of_peers_to_broadcast())
1046    }
1047
1048    /// Broadcasts the same request to all ready peers, ignoring return values.
1049    fn broadcast_all(&mut self, req: Request) -> <Self as tower::Service<Request>>::Future {
1050        let ready_peers = self.ready_services.keys().copied().collect();
1051        let send_multiple_fut = self.send_multiple(req.clone(), ready_peers);
1052        let Some(mut queued_broadcast_fut_receiver) = self.queue_broadcast_all_unready(&req) else {
1053            return send_multiple_fut;
1054        };
1055
1056        async move {
1057            let _ = send_multiple_fut.await?;
1058            while queued_broadcast_fut_receiver.recv().await.is_some() {}
1059            Ok(Response::Nil)
1060        }
1061        .boxed()
1062    }
1063
1064    /// If there are unready peers, queues a request to be broadcasted to them and
1065    /// returns a channel receiver for callers to await the broadcast_all() futures, or
1066    /// returns None if there are no unready peers.
1067    fn queue_broadcast_all_unready(
1068        &mut self,
1069        req: &Request,
1070    ) -> Option<tokio::sync::mpsc::Receiver<ResponseFuture>> {
1071        if !self.cancel_handles.is_empty() {
1072            /// How many broadcast all futures to send to the channel until the peer set should wait for the channel consumer
1073            /// to read a message before continuing to send the queued broadcast request to peers that were originally unready.
1074            const QUEUED_BROADCAST_FUTS_CHANNEL_SIZE: usize = 3;
1075
1076            let (sender, receiver) = tokio::sync::mpsc::channel(QUEUED_BROADCAST_FUTS_CHANNEL_SIZE);
1077            let unready_peers: HashSet<_> = self.cancel_handles.keys().cloned().collect();
1078            let queued = (req.clone(), sender, unready_peers);
1079
1080            // Drop the existing queued broadcast all request, if any.
1081            self.queued_broadcast_all = Some(queued);
1082
1083            Some(receiver)
1084        } else {
1085            None
1086        }
1087    }
1088
1089    /// Broadcasts the same requests to all ready peers which were unready when
1090    /// [`PeerSet::broadcast_all()`] was last called, ignoring return values.
1091    fn broadcast_all_queued(&mut self) {
1092        let Some((req, sender, mut remaining_peers)) = self.queued_broadcast_all.take() else {
1093            return;
1094        };
1095
1096        let bans = self.bans_receiver.borrow().clone();
1097        remaining_peers.retain(|addr| !bans.contains_key(&addr.ip()));
1098
1099        let Ok(reserved_send_slot) = sender.try_reserve() else {
1100            self.queued_broadcast_all = Some((req, sender, remaining_peers));
1101            return;
1102        };
1103
1104        let peers: Vec<_> = self
1105            .ready_services
1106            .keys()
1107            .filter(|ready_peer| remaining_peers.remove(ready_peer))
1108            .copied()
1109            .collect();
1110
1111        reserved_send_slot.send(self.send_multiple(req.clone(), peers).boxed());
1112
1113        if !remaining_peers.is_empty() {
1114            self.queued_broadcast_all = Some((req, sender, remaining_peers));
1115        }
1116    }
1117
1118    /// Given a number of ready peers calculate to how many of them Zebra will
1119    /// actually send the request to. Return this number.
1120    pub(crate) fn number_of_peers_to_broadcast(&self) -> usize {
1121        if self.network.is_regtest() {
1122            // In regtest, we broadcast to all peers, so that we can test the
1123            // peer set with a small number of peers.
1124            self.ready_services.len()
1125        } else {
1126            // We are currently sending broadcast messages to a third of the total peers.
1127            const PEER_FRACTION_TO_BROADCAST: usize = 3;
1128
1129            // Round up, so that if we have one ready peer, it gets the request.
1130            div_ceil(self.ready_services.len(), PEER_FRACTION_TO_BROADCAST)
1131        }
1132    }
1133
1134    /// Returns the list of addresses in the peer set.
1135    fn peer_set_addresses(&self) -> Vec<PeerSocketAddr> {
1136        self.ready_services
1137            .keys()
1138            .chain(self.cancel_handles.keys())
1139            .cloned()
1140            .collect()
1141    }
1142
1143    /// Logs the peer set size, and any potential connectivity issues.
1144    fn log_peer_set_size(&mut self) {
1145        let ready_services_len = self.ready_services.len();
1146        let unready_services_len = self.unready_services.len();
1147        trace!(ready_peers = ?ready_services_len, unready_peers = ?unready_services_len);
1148
1149        let now = Instant::now();
1150
1151        // These logs are designed to be human-readable in a terminal, at the
1152        // default Zebra log level. If you need to know the peer set size for
1153        // every request, use the trace-level logs, or the metrics exporter.
1154        if let Some(last_peer_log) = self.last_peer_log {
1155            // Avoid duplicate peer set logs
1156            if now.duration_since(last_peer_log) < MIN_PEER_SET_LOG_INTERVAL {
1157                return;
1158            }
1159        } else {
1160            // Suppress initial logs until the peer set has started up.
1161            // There can be multiple initial requests before the first peer is
1162            // ready.
1163            self.last_peer_log = Some(now);
1164            return;
1165        }
1166
1167        self.last_peer_log = Some(now);
1168
1169        // Log potential duplicate connections.
1170        let peers = self.peer_set_addresses();
1171
1172        // Check for duplicates by address and port: these are unexpected and represent a bug.
1173        let duplicates: Vec<PeerSocketAddr> = peers.iter().duplicates().cloned().collect();
1174
1175        let mut peer_counts = peers.iter().counts();
1176        peer_counts.retain(|peer, _count| duplicates.contains(peer));
1177
1178        if !peer_counts.is_empty() {
1179            let duplicate_connections: usize = peer_counts.values().sum();
1180
1181            warn!(
1182                ?duplicate_connections,
1183                duplicated_peers = ?peer_counts.len(),
1184                peers = ?peers.len(),
1185                "duplicate peer connections in peer set"
1186            );
1187        }
1188
1189        // Check for duplicates by address: these can happen if there are multiple nodes
1190        // behind a NAT or on a single server.
1191        let peers: Vec<IpAddr> = peers.iter().map(|addr| addr.ip()).collect();
1192        let duplicates: Vec<IpAddr> = peers.iter().duplicates().cloned().collect();
1193
1194        let mut peer_counts = peers.iter().counts();
1195        peer_counts.retain(|peer, _count| duplicates.contains(peer));
1196
1197        if !peer_counts.is_empty() {
1198            let duplicate_connections: usize = peer_counts.values().sum();
1199
1200            info!(
1201                ?duplicate_connections,
1202                duplicated_peers = ?peer_counts.len(),
1203                peers = ?peers.len(),
1204                "duplicate IP addresses in peer set"
1205            );
1206        }
1207
1208        // Only log connectivity warnings if all our peers are busy (or there are no peers).
1209        if ready_services_len > 0 {
1210            return;
1211        }
1212
1213        let address_metrics = *self.address_metrics.borrow();
1214        if unready_services_len == 0 {
1215            warn!(
1216                ?address_metrics,
1217                "network request with no peer connections. Hint: check your network connection"
1218            );
1219        } else {
1220            info!(?address_metrics, "network request with no ready peers: finding more peers, waiting for {} peers to answer requests",
1221                  unready_services_len);
1222        }
1223    }
1224
1225    /// Updates the peer set metrics.
1226    ///
1227    /// # Panics
1228    ///
1229    /// If the peer set size exceeds the connection limit.
1230    fn update_metrics(&self) {
1231        let num_ready = self.ready_services.len();
1232        let num_unready = self.unready_services.len();
1233        let num_peers = num_ready + num_unready;
1234        metrics::gauge!("pool.num_ready").set(num_ready as f64);
1235        metrics::gauge!("pool.num_unready").set(num_unready as f64);
1236        metrics::gauge!("zcash.net.peers").set(num_peers as f64);
1237
1238        // Security: make sure we haven't exceeded the connection limit
1239        if num_peers > self.peerset_total_connection_limit {
1240            let address_metrics = *self.address_metrics.borrow();
1241            panic!(
1242                "unexpectedly exceeded configured peer set connection limit: \n\
1243                 peers: {num_peers:?}, ready: {num_ready:?}, unready: {num_unready:?}, \n\
1244                 address_metrics: {address_metrics:?}",
1245            );
1246        }
1247    }
1248}
1249
1250impl<D, C> Service<Request> for PeerSet<D, C>
1251where
1252    D: Discover<Key = PeerSocketAddr, Service = LoadTrackedClient> + Unpin,
1253    D::Error: Into<BoxError>,
1254    C: ChainTip,
1255{
1256    type Response = Response;
1257    type Error = BoxError;
1258    type Future =
1259        Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
1260
1261    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
1262        // Update service and peer statuses.
1263        //
1264        // # Correctness
1265        //
1266        // All of the futures that receive a context from this method can wake the peer set buffer
1267        // task. If there are no ready peers, and no new peers, network requests will pause until:
1268        // - an unready peer becomes ready, or
1269        // - a new peer arrives.
1270
1271        // Check for new peers, and register a task wakeup when the next new peers arrive. New peers
1272        // can be infrequent if our connection slots are full, or we're connected to all
1273        // available/useful peers.
1274        let _poll_pending_or_ready: Poll<()> = self.poll_discover(cx)?;
1275
1276        // These tasks don't provide new peers or newly ready peers.
1277        let _poll_pending: Poll<()> = self.poll_background_errors(cx)?;
1278        let _poll_pending_or_ready: Poll<()> = self.inventory_registry.poll_inventory(cx)?;
1279
1280        let ready_peers = self.poll_peers(cx)?;
1281
1282        // These metrics should run last, to report the most up-to-date information.
1283        self.log_peer_set_size();
1284        self.update_metrics();
1285
1286        if ready_peers.is_pending() {
1287            // # Correctness
1288            //
1289            // If the channel is full, drop the demand signal rather than waiting. If we waited
1290            // here, the crawler could deadlock sending a request to fetch more peers, because it
1291            // also empties the channel.
1292            trace!("no ready services, sending demand signal");
1293            let _ = self.demand_signal.try_send(MorePeers);
1294
1295            // # Correctness
1296            //
1297            // The current task must be scheduled for wakeup every time we return `Poll::Pending`.
1298            //
1299            // As long as there are unready or new peers, this task will run, because:
1300            // - `poll_discover` schedules this task for wakeup when new peers arrive.
1301            // - if there are unready peers, `poll_unready` or `poll_ready_peers` schedule this
1302            //   task for wakeup when peer services become ready.
1303            //
1304            // To avoid peers blocking on a full peer status/error channel:
1305            // - `poll_background_errors` schedules this task for wakeup when the peer status
1306            //   update task exits.
1307            return Poll::Pending;
1308        }
1309
1310        self.broadcast_all_queued();
1311
1312        if self.ready_services.is_empty() {
1313            self.poll_peers(cx)
1314        } else {
1315            Poll::Ready(Ok(()))
1316        }
1317    }
1318
1319    fn call(&mut self, req: Request) -> Self::Future {
1320        let fut = match req {
1321            // Only do inventory-aware routing on individual items.
1322            Request::BlocksByHash(ref hashes) if hashes.len() == 1 => {
1323                let hash = InventoryHash::from(*hashes.iter().next().unwrap());
1324                self.route_inv(req, hash)
1325            }
1326            Request::TransactionsById(ref hashes) if hashes.len() == 1 => {
1327                let hash = InventoryHash::from(*hashes.iter().next().unwrap());
1328                self.route_inv(req, hash)
1329            }
1330
1331            // Broadcast advertisements to lots of peers
1332            Request::AdvertiseTransactionIds(_) => self.route_broadcast(req),
1333            Request::AdvertiseBlock(_) => self.route_broadcast(req),
1334            Request::AdvertiseBlockToAll(_) => self.broadcast_all(req),
1335
1336            // Choose a random less-loaded peer for all other requests
1337            _ => self.route_p2c(req),
1338        };
1339        self.update_metrics();
1340
1341        fut
1342    }
1343}