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