sc_network/service/traits.rs
1// This file is part of Substrate.
2//
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18//
19// If you read this, you are very thorough, congratulations.
20
21//! Traits defined by `sc-network`.
22
23use crate::{
24 config::{IncomingRequest, MultiaddrWithPeerId, NotificationHandshake, Params, SetConfig},
25 error::{self, Error},
26 event::Event,
27 network_state::NetworkState,
28 request_responses::{IfDisconnected, RequestFailure},
29 service::{metrics::NotificationMetrics, signature::Signature, PeerStoreProvider},
30 types::ProtocolName,
31 ReputationChange,
32};
33
34use futures::{channel::oneshot, Stream};
35use prometheus_endpoint::Registry;
36
37use sc_network_common::{role::ObservedRole, ExHashT};
38pub use sc_network_types::{
39 kad::{Key as KademliaKey, Record},
40 multiaddr::Multiaddr,
41 PeerId,
42};
43use sp_runtime::traits::Block as BlockT;
44
45use std::{
46 collections::HashSet,
47 fmt::Debug,
48 future::Future,
49 pin::Pin,
50 sync::Arc,
51 time::{Duration, Instant},
52};
53
54pub use libp2p::identity::SigningError;
55
56/// Supertrait defining the services provided by [`NetworkBackend`] service handle.
57pub trait NetworkService:
58 NetworkSigner
59 + NetworkDHTProvider
60 + NetworkStatusProvider
61 + NetworkPeers
62 + NetworkEventStream
63 + NetworkStateInfo
64 + NetworkRequest
65 + Send
66 + Sync
67 + 'static
68{
69}
70
71impl<T> NetworkService for T where
72 T: NetworkSigner
73 + NetworkDHTProvider
74 + NetworkStatusProvider
75 + NetworkPeers
76 + NetworkEventStream
77 + NetworkStateInfo
78 + NetworkRequest
79 + Send
80 + Sync
81 + 'static
82{
83}
84
85/// Trait defining the required functionality from a notification protocol configuration.
86pub trait NotificationConfig: Debug {
87 /// Get access to the `SetConfig` of the notification protocol.
88 fn set_config(&self) -> &SetConfig;
89
90 /// Get protocol name.
91 fn protocol_name(&self) -> &ProtocolName;
92}
93
94/// Trait defining the required functionality from a request-response protocol configuration.
95pub trait RequestResponseConfig: Debug {
96 /// Get protocol name.
97 fn protocol_name(&self) -> &ProtocolName;
98}
99
100/// Trait defining required functionality from `PeerStore`.
101#[async_trait::async_trait]
102pub trait PeerStore {
103 /// Get handle to `PeerStore`.
104 fn handle(&self) -> Arc<dyn PeerStoreProvider>;
105
106 /// Start running `PeerStore` event loop.
107 async fn run(self);
108}
109
110/// Networking backend.
111#[async_trait::async_trait]
112pub trait NetworkBackend<B: BlockT + 'static, H: ExHashT>: Send + 'static {
113 /// Whether this backend supports Bitswap ([`crate::config::Params::ipfs_config`]).
114 const SUPPORTS_IPFS: bool = false;
115
116 /// Type representing notification protocol-related configuration.
117 type NotificationProtocolConfig: NotificationConfig;
118
119 /// Type representing request-response protocol-related configuration.
120 type RequestResponseProtocolConfig: RequestResponseConfig;
121
122 /// Type implementing `NetworkService` for the networking backend.
123 ///
124 /// `NetworkService` allows other subsystems of the blockchain to interact with `sc-network`
125 /// using `NetworkService`.
126 type NetworkService<Block, Hash>: NetworkService + Clone;
127
128 /// Type implementing [`PeerStore`].
129 type PeerStore: PeerStore;
130
131 /// Create new `NetworkBackend`.
132 fn new(params: Params<B, H, Self>) -> Result<Self, Error>
133 where
134 Self: Sized;
135
136 /// Get handle to `NetworkService` of the `NetworkBackend`.
137 fn network_service(&self) -> Arc<dyn NetworkService>;
138
139 /// Create [`PeerStore`].
140 fn peer_store(bootnodes: Vec<PeerId>, metrics_registry: Option<Registry>) -> Self::PeerStore;
141
142 /// Register metrics that are used by the notification protocols.
143 fn register_notification_metrics(registry: Option<&Registry>) -> NotificationMetrics;
144
145 /// Create notification protocol configuration and an associated `NotificationService`
146 /// for the protocol.
147 fn notification_config(
148 protocol_name: ProtocolName,
149 fallback_names: Vec<ProtocolName>,
150 max_notification_size: u64,
151 handshake: Option<NotificationHandshake>,
152 set_config: SetConfig,
153 metrics: NotificationMetrics,
154 peerstore_handle: Arc<dyn PeerStoreProvider>,
155 ) -> (Self::NotificationProtocolConfig, Box<dyn NotificationService>);
156
157 /// Create request-response protocol configuration.
158 fn request_response_config(
159 protocol_name: ProtocolName,
160 fallback_names: Vec<ProtocolName>,
161 max_request_size: u64,
162 max_response_size: u64,
163 request_timeout: Duration,
164 inbound_queue: Option<async_channel::Sender<IncomingRequest>>,
165 ) -> Self::RequestResponseProtocolConfig;
166
167 /// Start [`NetworkBackend`] event loop.
168 async fn run(mut self);
169}
170
171/// Signer with network identity
172pub trait NetworkSigner {
173 /// Signs the message with the `KeyPair` that defines the local [`PeerId`].
174 fn sign_with_local_identity(&self, msg: Vec<u8>) -> Result<Signature, SigningError>;
175
176 /// Verify signature using peer's public key.
177 ///
178 /// `public_key` must be Protobuf-encoded ed25519 public key.
179 ///
180 /// Returns `Err(())` if public cannot be parsed into a valid ed25519 public key.
181 fn verify(
182 &self,
183 peer_id: sc_network_types::PeerId,
184 public_key: &Vec<u8>,
185 signature: &Vec<u8>,
186 message: &Vec<u8>,
187 ) -> Result<bool, String>;
188}
189
190impl<T> NetworkSigner for Arc<T>
191where
192 T: ?Sized,
193 T: NetworkSigner,
194{
195 fn sign_with_local_identity(&self, msg: Vec<u8>) -> Result<Signature, SigningError> {
196 T::sign_with_local_identity(self, msg)
197 }
198
199 fn verify(
200 &self,
201 peer_id: sc_network_types::PeerId,
202 public_key: &Vec<u8>,
203 signature: &Vec<u8>,
204 message: &Vec<u8>,
205 ) -> Result<bool, String> {
206 T::verify(self, peer_id, public_key, signature, message)
207 }
208}
209
210/// Provides access to the networking DHT.
211pub trait NetworkDHTProvider {
212 /// Start finding closest peers to the target.
213 fn find_closest_peers(&self, target: PeerId);
214
215 /// Start getting a value from the DHT.
216 fn get_value(&self, key: &KademliaKey);
217
218 /// Start putting a value in the DHT.
219 fn put_value(&self, key: KademliaKey, value: Vec<u8>);
220
221 /// Start putting the record to `peers`.
222 ///
223 /// If `update_local_storage` is true the local storage is udpated as well.
224 fn put_record_to(&self, record: Record, peers: HashSet<PeerId>, update_local_storage: bool);
225
226 /// Store a record in the DHT memory store.
227 fn store_record(
228 &self,
229 key: KademliaKey,
230 value: Vec<u8>,
231 publisher: Option<PeerId>,
232 expires: Option<Instant>,
233 );
234
235 /// Register this node as a provider for `key` on the DHT.
236 fn start_providing(&self, key: KademliaKey);
237
238 /// Deregister this node as a provider for `key` on the DHT.
239 fn stop_providing(&self, key: KademliaKey);
240
241 /// Start getting the list of providers for `key` on the DHT.
242 fn get_providers(&self, key: KademliaKey);
243}
244
245impl<T> NetworkDHTProvider for Arc<T>
246where
247 T: ?Sized,
248 T: NetworkDHTProvider,
249{
250 fn find_closest_peers(&self, target: PeerId) {
251 T::find_closest_peers(self, target)
252 }
253
254 fn get_value(&self, key: &KademliaKey) {
255 T::get_value(self, key)
256 }
257
258 fn put_value(&self, key: KademliaKey, value: Vec<u8>) {
259 T::put_value(self, key, value)
260 }
261
262 fn put_record_to(&self, record: Record, peers: HashSet<PeerId>, update_local_storage: bool) {
263 T::put_record_to(self, record, peers, update_local_storage)
264 }
265
266 fn store_record(
267 &self,
268 key: KademliaKey,
269 value: Vec<u8>,
270 publisher: Option<PeerId>,
271 expires: Option<Instant>,
272 ) {
273 T::store_record(self, key, value, publisher, expires)
274 }
275
276 fn start_providing(&self, key: KademliaKey) {
277 T::start_providing(self, key)
278 }
279
280 fn stop_providing(&self, key: KademliaKey) {
281 T::stop_providing(self, key)
282 }
283
284 fn get_providers(&self, key: KademliaKey) {
285 T::get_providers(self, key)
286 }
287}
288
289/// Provides an ability to set a fork sync request for a particular block.
290pub trait NetworkSyncForkRequest<BlockHash, BlockNumber> {
291 /// Notifies the sync service to try and sync the given block from the given
292 /// peers.
293 ///
294 /// If the given vector of peers is empty then the underlying implementation
295 /// should make a best effort to fetch the block from any peers it is
296 /// connected to (NOTE: this assumption will change in the future #3629).
297 fn set_sync_fork_request(&self, peers: Vec<PeerId>, hash: BlockHash, number: BlockNumber);
298}
299
300impl<T, BlockHash, BlockNumber> NetworkSyncForkRequest<BlockHash, BlockNumber> for Arc<T>
301where
302 T: ?Sized,
303 T: NetworkSyncForkRequest<BlockHash, BlockNumber>,
304{
305 fn set_sync_fork_request(&self, peers: Vec<PeerId>, hash: BlockHash, number: BlockNumber) {
306 T::set_sync_fork_request(self, peers, hash, number)
307 }
308}
309
310/// Overview status of the network.
311#[derive(Clone)]
312pub struct NetworkStatus {
313 /// Total number of connected peers.
314 pub num_connected_peers: usize,
315 /// The total number of bytes received.
316 pub total_bytes_inbound: u64,
317 /// The total number of bytes sent.
318 pub total_bytes_outbound: u64,
319}
320
321/// Provides high-level status information about network.
322#[async_trait::async_trait]
323pub trait NetworkStatusProvider {
324 /// High-level network status information.
325 ///
326 /// Returns an error if the `NetworkWorker` is no longer running.
327 async fn status(&self) -> Result<NetworkStatus, ()>;
328
329 /// Get the network state.
330 ///
331 /// Returns an error if the `NetworkWorker` is no longer running.
332 async fn network_state(&self) -> Result<NetworkState, ()>;
333}
334
335// Manual implementation to avoid extra boxing here
336impl<T> NetworkStatusProvider for Arc<T>
337where
338 T: ?Sized,
339 T: NetworkStatusProvider,
340{
341 fn status<'life0, 'async_trait>(
342 &'life0 self,
343 ) -> Pin<Box<dyn Future<Output = Result<NetworkStatus, ()>> + Send + 'async_trait>>
344 where
345 'life0: 'async_trait,
346 Self: 'async_trait,
347 {
348 T::status(self)
349 }
350
351 fn network_state<'life0, 'async_trait>(
352 &'life0 self,
353 ) -> Pin<Box<dyn Future<Output = Result<NetworkState, ()>> + Send + 'async_trait>>
354 where
355 'life0: 'async_trait,
356 Self: 'async_trait,
357 {
358 T::network_state(self)
359 }
360}
361
362/// Provides low-level API for manipulating network peers.
363#[async_trait::async_trait]
364pub trait NetworkPeers {
365 /// Set authorized peers.
366 ///
367 /// Need a better solution to manage authorized peers, but now just use reserved peers for
368 /// prototyping.
369 fn set_authorized_peers(&self, peers: HashSet<PeerId>);
370
371 /// Set authorized_only flag.
372 ///
373 /// Need a better solution to decide authorized_only, but now just use reserved_only flag for
374 /// prototyping.
375 fn set_authorized_only(&self, reserved_only: bool);
376
377 /// Adds an address known to a node.
378 fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr);
379
380 /// Report a given peer as either beneficial (+) or costly (-) according to the
381 /// given scalar.
382 fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange);
383
384 /// Get peer reputation.
385 fn peer_reputation(&self, peer_id: &PeerId) -> i32;
386
387 /// Disconnect from a node as soon as possible.
388 ///
389 /// This triggers the same effects as if the connection had closed itself spontaneously.
390 fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName);
391
392 /// Connect to unreserved peers and allow unreserved peers to connect for syncing purposes.
393 fn accept_unreserved_peers(&self);
394
395 /// Disconnect from unreserved peers and deny new unreserved peers to connect for syncing
396 /// purposes.
397 fn deny_unreserved_peers(&self);
398
399 /// Adds a `PeerId` and its `Multiaddr` as reserved for a sync protocol (default peer set).
400 ///
401 /// Returns an `Err` if the given string is not a valid multiaddress
402 /// or contains an invalid peer ID (which includes the local peer ID).
403 fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String>;
404
405 /// Removes a `PeerId` from the list of reserved peers for a sync protocol (default peer set).
406 fn remove_reserved_peer(&self, peer_id: PeerId);
407
408 /// Sets the reserved set of a protocol to the given set of peers.
409 ///
410 /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also
411 /// consist of only `/p2p/<peerid>`.
412 ///
413 /// The node will start establishing/accepting connections and substreams to/from peers in this
414 /// set, if it doesn't have any substream open with them yet.
415 ///
416 /// Note however, if a call to this function results in less peers on the reserved set, they
417 /// will not necessarily get disconnected (depending on available free slots in the peer set).
418 /// If you want to also disconnect those removed peers, you will have to call
419 /// `remove_from_peers_set` on those in addition to updating the reserved set. You can omit
420 /// this step if the peer set is in reserved only mode.
421 ///
422 /// Returns an `Err` if one of the given addresses is invalid or contains an
423 /// invalid peer ID (which includes the local peer ID), or if `protocol` does not
424 /// refer to a known protocol.
425 fn set_reserved_peers(
426 &self,
427 protocol: ProtocolName,
428 peers: HashSet<Multiaddr>,
429 ) -> Result<(), String>;
430
431 /// Add peers to a peer set.
432 ///
433 /// Each `Multiaddr` must end with a `/p2p/` component containing the `PeerId`. It can also
434 /// consist of only `/p2p/<peerid>`.
435 ///
436 /// Returns an `Err` if one of the given addresses is invalid or contains an
437 /// invalid peer ID (which includes the local peer ID), or if `protocol` does not
438 /// refer to a know protocol.
439 fn add_peers_to_reserved_set(
440 &self,
441 protocol: ProtocolName,
442 peers: HashSet<Multiaddr>,
443 ) -> Result<(), String>;
444
445 /// Remove peers from a peer set.
446 ///
447 /// Returns `Err` if `protocol` does not refer to a known protocol.
448 fn remove_peers_from_reserved_set(
449 &self,
450 protocol: ProtocolName,
451 peers: Vec<PeerId>,
452 ) -> Result<(), String>;
453
454 /// Returns the number of peers in the sync peer set we're connected to.
455 fn sync_num_connected(&self) -> usize;
456
457 /// Attempt to get peer role.
458 ///
459 /// Right now the peer role is decoded from the received handshake for all protocols
460 /// (`/block-announces/1` has other information as well). If the handshake cannot be
461 /// decoded into a role, the role queried from `PeerStore` and if the role is not stored
462 /// there either, `None` is returned and the peer should be discarded.
463 fn peer_role(&self, peer_id: PeerId, handshake: Vec<u8>) -> Option<ObservedRole>;
464
465 /// Get the list of reserved peers.
466 ///
467 /// Returns an error if the `NetworkWorker` is no longer running.
468 async fn reserved_peers(&self) -> Result<Vec<PeerId>, ()>;
469}
470
471// Manual implementation to avoid extra boxing here
472#[async_trait::async_trait]
473impl<T> NetworkPeers for Arc<T>
474where
475 T: ?Sized,
476 T: NetworkPeers,
477{
478 fn set_authorized_peers(&self, peers: HashSet<PeerId>) {
479 T::set_authorized_peers(self, peers)
480 }
481
482 fn set_authorized_only(&self, reserved_only: bool) {
483 T::set_authorized_only(self, reserved_only)
484 }
485
486 fn add_known_address(&self, peer_id: PeerId, addr: Multiaddr) {
487 T::add_known_address(self, peer_id, addr)
488 }
489
490 fn report_peer(&self, peer_id: PeerId, cost_benefit: ReputationChange) {
491 T::report_peer(self, peer_id, cost_benefit)
492 }
493
494 fn peer_reputation(&self, peer_id: &PeerId) -> i32 {
495 T::peer_reputation(self, peer_id)
496 }
497
498 fn disconnect_peer(&self, peer_id: PeerId, protocol: ProtocolName) {
499 T::disconnect_peer(self, peer_id, protocol)
500 }
501
502 fn accept_unreserved_peers(&self) {
503 T::accept_unreserved_peers(self)
504 }
505
506 fn deny_unreserved_peers(&self) {
507 T::deny_unreserved_peers(self)
508 }
509
510 fn add_reserved_peer(&self, peer: MultiaddrWithPeerId) -> Result<(), String> {
511 T::add_reserved_peer(self, peer)
512 }
513
514 fn remove_reserved_peer(&self, peer_id: PeerId) {
515 T::remove_reserved_peer(self, peer_id)
516 }
517
518 fn set_reserved_peers(
519 &self,
520 protocol: ProtocolName,
521 peers: HashSet<Multiaddr>,
522 ) -> Result<(), String> {
523 T::set_reserved_peers(self, protocol, peers)
524 }
525
526 fn add_peers_to_reserved_set(
527 &self,
528 protocol: ProtocolName,
529 peers: HashSet<Multiaddr>,
530 ) -> Result<(), String> {
531 T::add_peers_to_reserved_set(self, protocol, peers)
532 }
533
534 fn remove_peers_from_reserved_set(
535 &self,
536 protocol: ProtocolName,
537 peers: Vec<PeerId>,
538 ) -> Result<(), String> {
539 T::remove_peers_from_reserved_set(self, protocol, peers)
540 }
541
542 fn sync_num_connected(&self) -> usize {
543 T::sync_num_connected(self)
544 }
545
546 fn peer_role(&self, peer_id: PeerId, handshake: Vec<u8>) -> Option<ObservedRole> {
547 T::peer_role(self, peer_id, handshake)
548 }
549
550 fn reserved_peers<'life0, 'async_trait>(
551 &'life0 self,
552 ) -> Pin<Box<dyn Future<Output = Result<Vec<PeerId>, ()>> + Send + 'async_trait>>
553 where
554 'life0: 'async_trait,
555 Self: 'async_trait,
556 {
557 T::reserved_peers(self)
558 }
559}
560
561/// Provides access to network-level event stream.
562pub trait NetworkEventStream {
563 /// Returns a stream containing the events that happen on the network.
564 ///
565 /// If this method is called multiple times, the events are duplicated.
566 ///
567 /// The stream never ends (unless the `NetworkWorker` gets shut down).
568 ///
569 /// The name passed is used to identify the channel in the Prometheus metrics. Note that the
570 /// parameter is a `&'static str`, and not a `String`, in order to avoid accidentally having
571 /// an unbounded set of Prometheus metrics, which would be quite bad in terms of memory
572 fn event_stream(&self, name: &'static str) -> Pin<Box<dyn Stream<Item = Event> + Send>>;
573}
574
575impl<T> NetworkEventStream for Arc<T>
576where
577 T: ?Sized,
578 T: NetworkEventStream,
579{
580 fn event_stream(&self, name: &'static str) -> Pin<Box<dyn Stream<Item = Event> + Send>> {
581 T::event_stream(self, name)
582 }
583}
584
585/// Trait for providing information about the local network state
586pub trait NetworkStateInfo {
587 /// Returns the local external addresses.
588 fn external_addresses(&self) -> Vec<Multiaddr>;
589
590 /// Returns the listening addresses (without trailing `/p2p/` with our `PeerId`).
591 fn listen_addresses(&self) -> Vec<Multiaddr>;
592
593 /// Returns the local Peer ID.
594 fn local_peer_id(&self) -> PeerId;
595}
596
597impl<T> NetworkStateInfo for Arc<T>
598where
599 T: ?Sized,
600 T: NetworkStateInfo,
601{
602 fn external_addresses(&self) -> Vec<Multiaddr> {
603 T::external_addresses(self)
604 }
605
606 fn listen_addresses(&self) -> Vec<Multiaddr> {
607 T::listen_addresses(self)
608 }
609
610 fn local_peer_id(&self) -> PeerId {
611 T::local_peer_id(self)
612 }
613}
614
615/// Reserved slot in the notifications buffer, ready to accept data.
616pub trait NotificationSenderReady {
617 /// Consumes this slots reservation and actually queues the notification.
618 ///
619 /// NOTE: Traits can't consume itself, but calling this method second time will return an error.
620 fn send(&mut self, notification: Vec<u8>) -> Result<(), NotificationSenderError>;
621}
622
623/// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol.
624#[async_trait::async_trait]
625pub trait NotificationSender: Send + Sync + 'static {
626 /// Returns a future that resolves when the `NotificationSender` is ready to send a
627 /// notification.
628 async fn ready(&self)
629 -> Result<Box<dyn NotificationSenderReady + '_>, NotificationSenderError>;
630}
631
632/// Error returned by the notification sink.
633#[derive(Debug, thiserror::Error)]
634pub enum NotificationSenderError {
635 /// The notification receiver has been closed, usually because the underlying connection
636 /// closed.
637 ///
638 /// Some of the notifications most recently sent may not have been received. However,
639 /// the peer may still be connected and a new notification sink for the same
640 /// protocol obtained from [`NotificationService::message_sink()`].
641 #[error("The notification receiver has been closed")]
642 Closed,
643 /// Protocol name hasn't been registered.
644 #[error("Protocol name hasn't been registered")]
645 BadProtocol,
646}
647
648/// Provides ability to send network requests.
649#[async_trait::async_trait]
650pub trait NetworkRequest {
651 /// Sends a single targeted request to a specific peer. On success, returns the response of
652 /// the peer.
653 ///
654 /// Request-response protocols are a way to complement notifications protocols, but
655 /// notifications should remain the default ways of communicating information. For example, a
656 /// peer can announce something through a notification, after which the recipient can obtain
657 /// more information by performing a request.
658 /// As such, call this function with `IfDisconnected::ImmediateError` for `connect`. This way
659 /// you will get an error immediately for disconnected peers, instead of waiting for a
660 /// potentially very long connection attempt, which would suggest that something is wrong
661 /// anyway, as you are supposed to be connected because of the notification protocol.
662 ///
663 /// No limit or throttling of concurrent outbound requests per peer and protocol are enforced.
664 /// Such restrictions, if desired, need to be enforced at the call site(s).
665 ///
666 /// The protocol must have been registered through
667 /// `NetworkConfiguration::request_response_protocols`.
668 async fn request(
669 &self,
670 target: PeerId,
671 protocol: ProtocolName,
672 request: Vec<u8>,
673 fallback_request: Option<(Vec<u8>, ProtocolName)>,
674 connect: IfDisconnected,
675 ) -> Result<(Vec<u8>, ProtocolName), RequestFailure>;
676
677 /// Variation of `request` which starts a request whose response is delivered on a provided
678 /// channel.
679 ///
680 /// Instead of blocking and waiting for a reply, this function returns immediately, sending
681 /// responses via the passed in sender. This alternative API exists to make it easier to
682 /// integrate with message passing APIs.
683 ///
684 /// Keep in mind that the connected receiver might receive a `Canceled` event in case of a
685 /// closing connection. This is expected behaviour. With `request` you would get a
686 /// `RequestFailure::Network(OutboundFailure::ConnectionClosed)` in that case.
687 fn start_request(
688 &self,
689 target: PeerId,
690 protocol: ProtocolName,
691 request: Vec<u8>,
692 fallback_request: Option<(Vec<u8>, ProtocolName)>,
693 tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
694 connect: IfDisconnected,
695 );
696}
697
698// Manual implementation to avoid extra boxing here
699impl<T> NetworkRequest for Arc<T>
700where
701 T: ?Sized,
702 T: NetworkRequest,
703{
704 fn request<'life0, 'async_trait>(
705 &'life0 self,
706 target: PeerId,
707 protocol: ProtocolName,
708 request: Vec<u8>,
709 fallback_request: Option<(Vec<u8>, ProtocolName)>,
710 connect: IfDisconnected,
711 ) -> Pin<
712 Box<
713 dyn Future<Output = Result<(Vec<u8>, ProtocolName), RequestFailure>>
714 + Send
715 + 'async_trait,
716 >,
717 >
718 where
719 'life0: 'async_trait,
720 Self: 'async_trait,
721 {
722 T::request(self, target, protocol, request, fallback_request, connect)
723 }
724
725 fn start_request(
726 &self,
727 target: PeerId,
728 protocol: ProtocolName,
729 request: Vec<u8>,
730 fallback_request: Option<(Vec<u8>, ProtocolName)>,
731 tx: oneshot::Sender<Result<(Vec<u8>, ProtocolName), RequestFailure>>,
732 connect: IfDisconnected,
733 ) {
734 T::start_request(self, target, protocol, request, fallback_request, tx, connect)
735 }
736}
737
738/// Provides ability to announce blocks to the network.
739pub trait NetworkBlock<BlockHash, BlockNumber> {
740 /// Make sure an important block is propagated to peers.
741 ///
742 /// In chain-based consensus, we often need to make sure non-best forks are
743 /// at least temporarily synced. This function forces such an announcement.
744 fn announce_block(&self, hash: BlockHash, data: Option<Vec<u8>>);
745
746 /// Inform the network service about new best imported block.
747 fn new_best_block_imported(&self, hash: BlockHash, number: BlockNumber);
748}
749
750impl<T, BlockHash, BlockNumber> NetworkBlock<BlockHash, BlockNumber> for Arc<T>
751where
752 T: ?Sized,
753 T: NetworkBlock<BlockHash, BlockNumber>,
754{
755 fn announce_block(&self, hash: BlockHash, data: Option<Vec<u8>>) {
756 T::announce_block(self, hash, data)
757 }
758
759 fn new_best_block_imported(&self, hash: BlockHash, number: BlockNumber) {
760 T::new_best_block_imported(self, hash, number)
761 }
762}
763
764/// Substream acceptance result.
765#[derive(Debug, PartialEq, Eq)]
766pub enum ValidationResult {
767 /// Accept inbound substream.
768 Accept,
769
770 /// Reject inbound substream.
771 Reject,
772}
773
774/// Substream direction.
775#[derive(Debug, Copy, Clone, PartialEq, Eq)]
776pub enum Direction {
777 /// Substream opened by the remote node.
778 Inbound,
779
780 /// Substream opened by the local node.
781 Outbound,
782}
783
784impl From<litep2p::protocol::notification::Direction> for Direction {
785 fn from(direction: litep2p::protocol::notification::Direction) -> Self {
786 match direction {
787 litep2p::protocol::notification::Direction::Inbound => Direction::Inbound,
788 litep2p::protocol::notification::Direction::Outbound => Direction::Outbound,
789 }
790 }
791}
792
793impl Direction {
794 /// Is the direction inbound.
795 pub fn is_inbound(&self) -> bool {
796 std::matches!(self, Direction::Inbound)
797 }
798}
799
800/// Events received by the protocol from `Notifications`.
801#[derive(Debug)]
802pub enum NotificationEvent {
803 /// Validate inbound substream.
804 ValidateInboundSubstream {
805 /// Peer ID.
806 peer: PeerId,
807
808 /// Received handshake.
809 handshake: Vec<u8>,
810
811 /// `oneshot::Sender` for sending validation result back to `Notifications`
812 result_tx: tokio::sync::oneshot::Sender<ValidationResult>,
813 },
814
815 /// Remote identified by `PeerId` opened a substream and sent `Handshake`.
816 /// Validate `Handshake` and report status (accept/reject) to `Notifications`.
817 NotificationStreamOpened {
818 /// Peer ID.
819 peer: PeerId,
820
821 /// Is the substream inbound or outbound.
822 direction: Direction,
823
824 /// Received handshake.
825 handshake: Vec<u8>,
826
827 /// Negotiated fallback.
828 negotiated_fallback: Option<ProtocolName>,
829 },
830
831 /// Substream was closed.
832 NotificationStreamClosed {
833 /// Peer Id.
834 peer: PeerId,
835 },
836
837 /// Notification was received from the substream.
838 NotificationReceived {
839 /// Peer ID.
840 peer: PeerId,
841
842 /// Received notification.
843 notification: Vec<u8>,
844 },
845}
846
847/// Notification service
848///
849/// Defines behaviors that both the protocol implementations and `Notifications` can expect from
850/// each other.
851///
852/// `Notifications` can send two different kinds of information to protocol:
853/// * substream-related information
854/// * notification-related information
855///
856/// When an unvalidated, inbound substream is received by `Notifications`, it sends the inbound
857/// stream information (peer ID, handshake) to protocol for validation. Protocol must then verify
858/// that the handshake is valid (and in the future that it has a slot it can allocate for the peer)
859/// and then report back the `ValidationResult` which is either `Accept` or `Reject`.
860///
861/// After the validation result has been received by `Notifications`, it prepares the
862/// substream for communication by initializing the necessary sinks and emits
863/// `NotificationStreamOpened` which informs the protocol that the remote peer is ready to receive
864/// notifications.
865///
866/// Two different flavors of sending options are provided:
867/// * synchronous sending ([`NotificationService::send_sync_notification()`])
868/// * asynchronous sending ([`NotificationService::send_async_notification()`])
869///
870/// The former is used by the protocols not ready to exercise backpressure and the latter by the
871/// protocols that can do it.
872///
873/// Both local and remote peer can close the substream at any time. Local peer can do so by calling
874/// [`NotificationService::close_substream()`] which instructs `Notifications` to close the
875/// substream. Remote closing the substream is indicated to the local peer by receiving
876/// [`NotificationEvent::NotificationStreamClosed`] event.
877///
878/// In case the protocol must update its handshake while it's operating (such as updating the best
879/// block information), it can do so by calling [`NotificationService::set_handshake()`]
880/// which instructs `Notifications` to update the handshake it stored during protocol
881/// initialization.
882///
883/// All peer events are multiplexed on the same incoming event stream from `Notifications` and thus
884/// each event carries a `PeerId` so the protocol knows whose information to update when receiving
885/// an event.
886#[async_trait::async_trait]
887pub trait NotificationService: Debug + Send {
888 /// Instruct `Notifications` to open a new substream for `peer`.
889 ///
890 /// `dial_if_disconnected` informs `Notifications` whether to dial
891 // the peer if there is currently no active connection to it.
892 //
893 // NOTE: not offered by the current implementation
894 async fn open_substream(&mut self, peer: PeerId) -> Result<(), ()>;
895
896 /// Instruct `Notifications` to close substream for `peer`.
897 // NOTE: not offered by the current implementation
898 async fn close_substream(&mut self, peer: PeerId) -> Result<(), ()>;
899
900 /// Send synchronous `notification` to `peer`.
901 fn send_sync_notification(&mut self, peer: &PeerId, notification: Vec<u8>);
902
903 /// Send asynchronous `notification` to `peer`, allowing sender to exercise backpressure.
904 ///
905 /// Returns an error if the peer doesn't exist.
906 async fn send_async_notification(
907 &mut self,
908 peer: &PeerId,
909 notification: Vec<u8>,
910 ) -> Result<(), error::Error>;
911
912 /// Set handshake for the notification protocol replacing the old handshake.
913 async fn set_handshake(&mut self, handshake: Vec<u8>) -> Result<(), ()>;
914
915 /// Non-blocking variant of `set_handshake()` that attempts to update the handshake
916 /// and returns an error if the channel is blocked.
917 ///
918 /// Technically the function can return an error if the channel to `Notifications` is closed
919 /// but that doesn't happen under normal operation.
920 fn try_set_handshake(&mut self, handshake: Vec<u8>) -> Result<(), ()>;
921
922 /// Get next event from the `Notifications` event stream.
923 async fn next_event(&mut self) -> Option<NotificationEvent>;
924
925 /// Make a copy of the object so it can be shared between protocol components
926 /// who wish to have access to the same underlying notification protocol.
927 fn clone(&mut self) -> Result<Box<dyn NotificationService>, ()>;
928
929 /// Get protocol name of the `NotificationService`.
930 fn protocol(&self) -> &ProtocolName;
931
932 /// Get message sink of the peer.
933 fn message_sink(&self, peer: &PeerId) -> Option<Box<dyn MessageSink>>;
934}
935
936/// Message sink for peers.
937///
938/// If protocol cannot use [`NotificationService`] to send notifications to peers and requires,
939/// e.g., notifications to be sent in another task, the protocol may acquire a [`MessageSink`]
940/// object for each peer by calling [`NotificationService::message_sink()`]. Calling this
941/// function returns an object which allows the protocol to send notifications to the remote peer.
942///
943/// Use of this API is discouraged as it's not as performant as sending notifications through
944/// [`NotificationService`] due to synchronization required to keep the underlying notification
945/// sink up to date with possible sink replacement events.
946#[async_trait::async_trait]
947pub trait MessageSink: Send + Sync {
948 /// Send synchronous `notification` to the peer associated with this [`MessageSink`].
949 fn send_sync_notification(&self, notification: Vec<u8>);
950
951 /// Send an asynchronous `notification` to to the peer associated with this [`MessageSink`],
952 /// allowing sender to exercise backpressure.
953 ///
954 /// Returns an error if the peer does not exist.
955 async fn send_async_notification(&self, notification: Vec<u8>) -> Result<(), error::Error>;
956}
957
958/// Trait defining the behavior of a bandwidth sink.
959pub trait BandwidthSink: Send + Sync {
960 /// Get the number of bytes received.
961 fn total_inbound(&self) -> u64;
962
963 /// Get the number of bytes sent.
964 fn total_outbound(&self) -> u64;
965}