Skip to main content

zakura_network/
lib.rs

1//! Networking code for the Zakura node.
2//!
3//! ## Network Protocol Design
4//!
5//! The Zcash network protocol is inherited from Bitcoin, which uses a
6//! stateful network protocol in which messages can arrive in any
7//! order (even before a handshake is complete!). The same Bitcoin message
8//! may be a request or a response depending on context.
9//!
10//! ### Achieving Concurrency
11//!
12//! This crate translates the legacy Zcash network protocol
13//! into a stateless, request-response oriented protocol defined by
14//! the [`Request`] and [`Response`] enums. `zakura-network` completely
15//! encapsulates all peer handling code behind a single
16//! [`tower::Service`] representing "the network", which load-balances
17//! outbound [`Request`]s over available peers.
18//!
19//! Unlike the underlying legacy network protocol, Zebra's `PeerSet`
20//! [`tower::Service`] guarantees that each `Request` future will resolve to the
21//! correct `Response`, rather than an unrelated `Response` message.
22//!
23//! Each peer connection is handled by a distinct [`peer::Connection`] task.
24//! The Zcash network protocol is bidirectional, so Zebra interprets incoming
25//! Zcash messages as either:
26//! - [`Response`]s to previously sent outbound [`Request`]s, or
27//! - inbound [`Request`]s to an internal [`tower::Service`] representing "this node".
28//!
29//! All connection state is isolated to individual peers, so this
30//! design is structurally immune to the recent `ping` attack.
31//!
32//! ### Connection Pool
33//!
34//! Because [`tower::Service`]s provide backpressure information, we
35//! can dynamically manage the size of the connection pool according
36//! to inbound and outbound demand.  The inbound service can shed load
37//! when it is not ready for requests, causing those peer connections
38//! to close, and the outbound service can connect to additional peers
39//! when it is overloaded.
40//!
41//! ## `zakura-network` Structure
42//!
43//! [`init`] is the main entry point for `zakura-network`.
44//! It uses the following services, tasks, and endpoints:
45//!
46//! ### Low-Level Network Connections
47//!
48//! Inbound Zcash Listener Task:
49//!  * accepts inbound connections on the listener port
50//!  * initiates Zcash [`peer::Handshake`]s, which creates [`peer::Connection`]
51//!    tasks for each inbound connection
52//!
53//! Outbound Zcash Connector Service:
54//!  * initiates outbound connections to peer addresses
55//!  * initiates Zcash [`peer::Handshake`]s, which creates [`peer::Connection`]
56//!    tasks for each outbound connection
57//!
58//! Zebra uses direct TCP connections to share blocks and mempool transactions
59//! with other peers.
60//!
61//! ### Individual Peer Connections
62//!
63//! Each new peer connection spawns the following tasks:
64//!
65//! [`peer::Client`] Service:
66//!  * provides an interface for outbound requests to an individual peer
67//!    * accepts [`Request`]s assigned to this peer by the `PeerSet`
68//!    * sends each request to the peer as Zcash [`Message`][1]
69//!    * waits for the inbound response [`Message`][1] from the peer, and returns it as a [`Response`]
70//!
71//! [`peer::Connection`] Service:
72//!  * manages connection state: awaiting a request, or handling an inbound or outbound response
73//!  * provides an interface for inbound requests from an individual peer
74//!    * accepts inbound Zcash [`Message`][1]s from this peer
75//!    * handles each message as a [`Request`] to the inbound service
76//!    * sends the [`Response`] to the peer as Zcash [`Message`][1]s
77//!  * drops peer connections if the inbound request queue is overloaded
78//!
79//! Since the Zcash network protocol is bidirectional,
80//! inbound and outbound connections are handled using the same logic.
81//!
82//! ### Connection Pool
83//!
84//! `PeerSet` Network Service:
85//!  * provides an interface for other services and tasks running within this node
86//!    to make requests to remote peers ("the rest of the network")
87//!    * accepts [`Request`]s from the local node
88//!    * sends each request to a [`peer::Client`] using randomised load-balancing
89//!    * returns the [`Response`] from the [`peer::Client`]
90//!
91//! Inbound Network Service:
92//!  * provides an interface for remote peers to request data held by this node
93//!    * accepts inbound Zcash [`Request`]s from [`peer::Connection`]s
94//!    * handles each message as a [`Request`] to the local node
95//!    * sends the [`Response`] to the [`peer::Connection`]
96//!
97//! Note: the inbound service is implemented by the [`init`] caller.
98//!
99//! Peer Inventory Service:
100//!  * tracks gossiped `inv` advertisements for each peer
101//!  * updated before each `PeerSet` request is processed
102//!  * tracks missing inventory for each peer
103//!  * used by the `PeerSet` to route block and transaction requests
104//!    to peers that have the requested data
105//!
106//! ### Peer Discovery
107//!
108//! [`AddressBook`] Service:
109//!  * maintains a list of peer addresses and associated connection attempt metadata
110//!  * address book metadata is used to prioritise peer connection attempts
111//!  * updated by an independent thread based on peer connection status changes
112//!  * caches peer addresses to disk regularly using an independent task
113//!
114//! Initial Seed Peer Task:
115//! On startup:
116//!  * loads seed peers from the config, resolving them via DNS if required
117//!  * loads cached peer addresses from disk
118//!  * initiates new outbound peer connections to seed and cached peers
119//!  * adds seed and cached peer addresses to the [`AddressBook`]
120//!
121//! Peer Crawler Task:
122//!  * discovers new peer addresses by sending `Addr` requests to connected peers
123//!  * initiates new outbound peer connections in response to application demand
124//!
125//! [1]: protocol::external::Message
126
127#![doc(html_favicon_url = "https://zakura.com/assets/rustdoc/zakura-favicon-128.png")]
128#![doc(html_logo_url = "https://zakura.com/assets/rustdoc/zakura-icon.png")]
129#![doc(html_root_url = "https://docs.rs/zakura_network")]
130// Long Tower service and future types are routine in this crate, and factoring
131// them into type aliases would not make the code clearer.
132#![allow(clippy::type_complexity)]
133
134#[macro_use]
135extern crate pin_project;
136#[macro_use]
137extern crate serde;
138#[macro_use]
139extern crate tracing;
140#[macro_use]
141extern crate bitflags;
142
143/// Type alias to make working with tower traits easier.
144///
145/// Note: the 'static lifetime bound means that the *type* cannot have any
146/// non-'static lifetimes, (e.g., when a type contains a borrow and is
147/// parameterized by 'a), *not* that the object itself has 'static lifetime.
148pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
149
150pub mod address_book_peers;
151pub mod config;
152pub mod constants;
153
154mod address_book;
155mod address_book_updater;
156#[cfg(any(test, feature = "proptest-impl"))]
157mod isolated;
158mod meta_addr;
159mod peer;
160mod peer_cache_updater;
161mod peer_registry;
162mod peer_set;
163mod policies;
164mod protocol;
165pub mod zakura;
166
167#[allow(unused)]
168pub(crate) use peer_set::PeerSet;
169
170#[cfg(any(test, feature = "proptest-impl"))]
171pub use crate::{isolated::connect_isolated_with_inbound, protocol::external::canonical_peer_addr};
172
173pub use crate::{
174    address_book::{AddressBook, BannedIps},
175    address_book_peers::AddressBookPeers,
176    config::{CacheDir, Config, P2pStack},
177    meta_addr::{PeerAddrState, PeerSocketAddr},
178    peer::{
179        Client, ConnectedAddr, ConnectionInfo, HandshakeError, NotFoundClass, PeerError,
180        SharedPeerError,
181    },
182    peer_registry::ConnectedPeer,
183    peer_set::{init, init_with_zakura, init_with_zakura_header_sync},
184    policies::RetryLimit,
185    protocol::{
186        external::{Version, VersionMessage, MAX_TX_INV_IN_SENT_MESSAGE},
187        internal::{InventoryResponse, PeerSource, Request, Response},
188    },
189};
190
191/// Types used in the definition of [`Request`], [`Response`], and [`VersionMessage`].
192pub mod types {
193    pub use crate::{
194        meta_addr::MetaAddr,
195        protocol::{
196            external::{AddrInVersion, Nonce},
197            types::PeerServices,
198        },
199    };
200
201    #[cfg(any(test, feature = "proptest-impl"))]
202    pub use crate::protocol::external::InventoryHash;
203}