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