Move transactions protocol to its own crate (#12264)

* Move transaction protocol to its own crate

* Update Cargo.lock

* Fix binaries

* Update client/network/transactions/src/lib.rs

Co-authored-by: Dmitry Markin <dmitry@markin.tech>

* Update client/service/src/builder.rs

Co-authored-by: Bastian Köcher <info@kchr.de>

* Apply review comments

* Revert one change and apply cargo-fmt

* Remove Transaction from Message

* Add array-bytes

* trigger CI

* Add comment about codec index

Co-authored-by: Dmitry Markin <dmitry@markin.tech>
Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
Aaro Altonen
2022-09-26 15:10:09 +03:00
committed by GitHub
parent ea377d0b17
commit 4c19c13d05
32 changed files with 466 additions and 471 deletions
@@ -18,6 +18,8 @@
//! Configuration of the networking layer.
use crate::protocol;
use libp2p::{multiaddr, Multiaddr, PeerId};
use std::{fmt, str, str::FromStr};
@@ -171,3 +173,129 @@ impl From<multiaddr::Error> for ParseErr {
Self::MultiaddrParse(err)
}
}
/// Configuration for a set of nodes.
#[derive(Clone, Debug)]
pub struct SetConfig {
/// Maximum allowed number of incoming substreams related to this set.
pub in_peers: u32,
/// Number of outgoing substreams related to this set that we're trying to maintain.
pub out_peers: u32,
/// List of reserved node addresses.
pub reserved_nodes: Vec<MultiaddrWithPeerId>,
/// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically
/// refused.
pub non_reserved_mode: NonReservedPeerMode,
}
impl Default for SetConfig {
fn default() -> Self {
Self {
in_peers: 25,
out_peers: 75,
reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Accept,
}
}
}
/// Extension to [`SetConfig`] for sets that aren't the default set.
///
/// > **Note**: As new fields might be added in the future, please consider using the `new` method
/// > and modifiers instead of creating this struct manually.
#[derive(Clone, Debug)]
pub struct NonDefaultSetConfig {
/// Name of the notifications protocols of this set. A substream on this set will be
/// considered established once this protocol is open.
///
/// > **Note**: This field isn't present for the default set, as this is handled internally
/// > by the networking code.
pub notifications_protocol: protocol::ProtocolName,
/// If the remote reports that it doesn't support the protocol indicated in the
/// `notifications_protocol` field, then each of these fallback names will be tried one by
/// one.
///
/// If a fallback is used, it will be reported in
/// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback`
pub fallback_names: Vec<protocol::ProtocolName>,
/// Maximum allowed size of single notifications.
pub max_notification_size: u64,
/// Base configuration.
pub set_config: SetConfig,
}
impl NonDefaultSetConfig {
/// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes.
pub fn new(notifications_protocol: protocol::ProtocolName, max_notification_size: u64) -> Self {
Self {
notifications_protocol,
max_notification_size,
fallback_names: Vec::new(),
set_config: SetConfig {
in_peers: 0,
out_peers: 0,
reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Deny,
},
}
}
/// Modifies the configuration to allow non-reserved nodes.
pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) {
self.set_config.in_peers = in_peers;
self.set_config.out_peers = out_peers;
self.set_config.non_reserved_mode = NonReservedPeerMode::Accept;
}
/// Add a node to the list of reserved nodes.
pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) {
self.set_config.reserved_nodes.push(peer);
}
/// Add a list of protocol names used for backward compatibility.
///
/// See the explanations in [`NonDefaultSetConfig::fallback_names`].
pub fn add_fallback_names(&mut self, fallback_names: Vec<protocol::ProtocolName>) {
self.fallback_names.extend(fallback_names);
}
}
/// Configuration for the transport layer.
#[derive(Clone, Debug)]
pub enum TransportConfig {
/// Normal transport mode.
Normal {
/// If true, the network will use mDNS to discover other libp2p nodes on the local network
/// and connect to them if they support the same chain.
enable_mdns: bool,
/// If true, allow connecting to private IPv4 addresses (as defined in
/// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have
/// been passed in `::sc_network::config::NetworkConfiguration::boot_nodes`.
allow_private_ipv4: bool,
},
/// Only allow connections within the same process.
/// Only addresses of the form `/memory/...` will be supported.
MemoryOnly,
}
/// The policy for connections to non-reserved peers.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NonReservedPeerMode {
/// Accept them. This is the default.
Accept,
/// Deny them.
Deny,
}
impl NonReservedPeerMode {
/// Attempt to parse the peer mode from a string.
pub fn parse(s: &str) -> Option<Self> {
match s {
"accept" => Some(Self::Accept),
"deny" => Some(Self::Deny),
_ => None,
}
}
}
@@ -0,0 +1,77 @@
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Substrate network possible errors.
use crate::{config::TransportConfig, protocol::ProtocolName};
use libp2p::{Multiaddr, PeerId};
use std::fmt;
/// Result type alias for the network.
pub type Result<T> = std::result::Result<T, Error>;
/// Error type for the network.
#[derive(thiserror::Error)]
pub enum Error {
/// Io error
#[error(transparent)]
Io(#[from] std::io::Error),
/// Client error
#[error(transparent)]
Client(#[from] Box<sp_blockchain::Error>),
/// The same bootnode (based on address) is registered with two different peer ids.
#[error(
"The same bootnode (`{address}`) is registered with two different peer ids: `{first_id}` and `{second_id}`"
)]
DuplicateBootnode {
/// The address of the bootnode.
address: Multiaddr,
/// The first peer id that was found for the bootnode.
first_id: PeerId,
/// The second peer id that was found for the bootnode.
second_id: PeerId,
},
/// Prometheus metrics error.
#[error(transparent)]
Prometheus(#[from] prometheus_endpoint::PrometheusError),
/// The network addresses are invalid because they don't match the transport.
#[error(
"The following addresses are invalid because they don't match the transport: {addresses:?}"
)]
AddressesForAnotherTransport {
/// Transport used.
transport: TransportConfig,
/// The invalid addresses.
addresses: Vec<Multiaddr>,
},
/// The same request-response protocol has been registered multiple times.
#[error("Request-response protocol registered multiple times: {protocol}")]
DuplicateRequestResponseProtocol {
/// Name of the protocol registered multiple times.
protocol: ProtocolName,
},
}
// Make `Debug` use the `Display` implementation.
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
@@ -19,8 +19,16 @@
//! Common data structures of the networking layer.
pub mod config;
pub mod error;
pub mod message;
pub mod protocol;
pub mod request_responses;
pub mod service;
pub mod sync;
pub mod utils;
/// Minimum Requirements for a Hash within Networking
pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {}
impl<T> ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static
{}
@@ -604,35 +604,6 @@ where
}
}
/// Provides ability to propagate transactions over the network.
pub trait NetworkTransaction<H> {
/// You may call this when new transactions are imported by the transaction pool.
///
/// All transactions will be fetched from the `TransactionPool` that was passed at
/// initialization as part of the configuration and propagated to peers.
fn trigger_repropagate(&self);
/// You must call when new transaction is imported by the transaction pool.
///
/// This transaction will be fetched from the `TransactionPool` that was passed at
/// initialization as part of the configuration and propagated to peers.
fn propagate_transaction(&self, hash: H);
}
impl<T, H> NetworkTransaction<H> for Arc<T>
where
T: ?Sized,
T: NetworkTransaction<H>,
{
fn trigger_repropagate(&self) {
T::trigger_repropagate(self)
}
fn propagate_transaction(&self, hash: H) {
T::propagate_transaction(self, hash)
}
}
/// Provides ability to announce blocks to the network.
pub trait NetworkBlock<BlockHash, BlockNumber> {
/// Make sure an important block is propagated to peers.
@@ -0,0 +1,85 @@
// This file is part of Substrate.
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use futures::{stream::unfold, FutureExt, Stream, StreamExt};
use futures_timer::Delay;
use linked_hash_set::LinkedHashSet;
use std::{hash::Hash, num::NonZeroUsize, time::Duration};
/// Creates a stream that returns a new value every `duration`.
pub fn interval(duration: Duration) -> impl Stream<Item = ()> + Unpin {
unfold((), move |_| Delay::new(duration).map(|_| Some(((), ())))).map(drop)
}
/// Wrapper around `LinkedHashSet` with bounded growth.
///
/// In the limit, for each element inserted the oldest existing element will be removed.
#[derive(Debug, Clone)]
pub struct LruHashSet<T: Hash + Eq> {
set: LinkedHashSet<T>,
limit: NonZeroUsize,
}
impl<T: Hash + Eq> LruHashSet<T> {
/// Create a new `LruHashSet` with the given (exclusive) limit.
pub fn new(limit: NonZeroUsize) -> Self {
Self { set: LinkedHashSet::new(), limit }
}
/// Insert element into the set.
///
/// Returns `true` if this is a new element to the set, `false` otherwise.
/// Maintains the limit of the set by removing the oldest entry if necessary.
/// Inserting the same element will update its LRU position.
pub fn insert(&mut self, e: T) -> bool {
if self.set.insert(e) {
if self.set.len() == usize::from(self.limit) {
self.set.pop_front(); // remove oldest entry
}
return true
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn maintains_limit() {
let three = NonZeroUsize::new(3).unwrap();
let mut set = LruHashSet::<u8>::new(three);
// First element.
assert!(set.insert(1));
assert_eq!(vec![&1], set.set.iter().collect::<Vec<_>>());
// Second element.
assert!(set.insert(2));
assert_eq!(vec![&1, &2], set.set.iter().collect::<Vec<_>>());
// Inserting the same element updates its LRU position.
assert!(!set.insert(1));
assert_eq!(vec![&2, &1], set.set.iter().collect::<Vec<_>>());
// We reached the limit. The next element forces the oldest one out.
assert!(set.insert(3));
assert_eq!(vec![&1, &3], set.set.iter().collect::<Vec<_>>());
}
}