From db8cabbb2cec7363e531eab927775692ed3b3e1a Mon Sep 17 00:00:00 2001 From: Shamil Gadelshin Date: Mon, 9 Oct 2023 17:00:54 +0700 Subject: [PATCH 1/2] networking: Introduce automatic Kademlia mode. --- .../bin/subspace-farmer/commands/farm/dsn.rs | 9 ++-- .../subspace-networking/examples/benchmark.rs | 2 - .../examples/random-walker.rs | 2 - .../src/bin/subspace-bootstrap-node/main.rs | 4 +- crates/subspace-networking/src/constructor.rs | 21 ++++++-- crates/subspace-networking/src/lib.rs | 4 +- crates/subspace-networking/src/node_runner.rs | 54 +++++++++++++++---- crates/subspace-service/src/dsn.rs | 8 +-- 8 files changed, 78 insertions(+), 26 deletions(-) diff --git a/crates/subspace-farmer/src/bin/subspace-farmer/commands/farm/dsn.rs b/crates/subspace-farmer/src/bin/subspace-farmer/commands/farm/dsn.rs index 7086d4329c..7a93886041 100644 --- a/crates/subspace-farmer/src/bin/subspace-farmer/commands/farm/dsn.rs +++ b/crates/subspace-farmer/src/bin/subspace-farmer/commands/farm/dsn.rs @@ -8,14 +8,14 @@ use subspace_farmer::piece_cache::PieceCache; use subspace_farmer::utils::readers_and_pieces::ReadersAndPieces; use subspace_farmer::{NodeClient, NodeRpcClient}; use subspace_networking::libp2p::identity::Keypair; -use subspace_networking::libp2p::kad::RecordKey; +use subspace_networking::libp2p::kad::{Mode, RecordKey}; use subspace_networking::libp2p::metrics::Metrics; use subspace_networking::libp2p::multiaddr::Protocol; use subspace_networking::utils::multihash::ToMultihash; use subspace_networking::utils::strip_peer_id; use subspace_networking::{ - construct, Config, NetworkingParametersManager, Node, NodeRunner, PeerInfo, PeerInfoProvider, - PieceByIndexRequest, PieceByIndexRequestHandler, PieceByIndexResponse, + construct, Config, KademliaMode, NetworkingParametersManager, Node, NodeRunner, PeerInfo, + PeerInfoProvider, PieceByIndexRequest, PieceByIndexRequestHandler, PieceByIndexResponse, SegmentHeaderBySegmentIndexesRequestHandler, SegmentHeaderRequest, SegmentHeaderResponse, }; use subspace_rpc_primitives::MAX_SEGMENT_HEADERS_PER_REQUEST; @@ -189,6 +189,9 @@ pub(super) fn configure_dsn( !PeerInfo::is_farmer(peer_info) })), bootstrap_addresses: bootstrap_nodes, + kademlia_mode: KademliaMode::Dynamic { + initial_mode: Mode::Client, + }, external_addresses, metrics, ..default_config diff --git a/crates/subspace-networking/examples/benchmark.rs b/crates/subspace-networking/examples/benchmark.rs index 387bf6e8b6..d0aaaa37bd 100644 --- a/crates/subspace-networking/examples/benchmark.rs +++ b/crates/subspace-networking/examples/benchmark.rs @@ -4,7 +4,6 @@ use futures::future::pending; use futures::stream::FuturesUnordered; use futures::StreamExt; use libp2p::identity::Keypair; -use libp2p::kad::Mode; use libp2p::multiaddr::Protocol; use libp2p::Multiaddr; use parking_lot::Mutex; @@ -273,7 +272,6 @@ pub async fn configure_dsn( let config = Config { listen_on: vec!["/ip4/0.0.0.0/tcp/0".parse().unwrap()], allow_non_global_addresses_in_dht: enable_private_ips, - kademlia_mode: Some(Mode::Client), request_response_protocols: vec![PieceByIndexRequestHandler::create(|_, _| async { None })], bootstrap_addresses, enable_autonat: false, diff --git a/crates/subspace-networking/examples/random-walker.rs b/crates/subspace-networking/examples/random-walker.rs index 54788c7b69..6526427b4c 100644 --- a/crates/subspace-networking/examples/random-walker.rs +++ b/crates/subspace-networking/examples/random-walker.rs @@ -3,7 +3,6 @@ use futures::channel::oneshot; use futures::future::pending; use futures::StreamExt; use libp2p::identity::Keypair; -use libp2p::kad::Mode; use libp2p::multiaddr::Protocol; use libp2p::{Multiaddr, PeerId}; use parking_lot::Mutex; @@ -366,7 +365,6 @@ async fn configure_dsn( let config = Config { listen_on: vec!["/ip4/0.0.0.0/tcp/0".parse().unwrap()], allow_non_global_addresses_in_dht: enable_private_ips, - kademlia_mode: Some(Mode::Client), request_response_protocols: vec![PieceByIndexRequestHandler::create(|_, _| async { None })], bootstrap_addresses, enable_autonat: false, diff --git a/crates/subspace-networking/src/bin/subspace-bootstrap-node/main.rs b/crates/subspace-networking/src/bin/subspace-bootstrap-node/main.rs index 12078c48b4..6972839fe5 100644 --- a/crates/subspace-networking/src/bin/subspace-bootstrap-node/main.rs +++ b/crates/subspace-networking/src/bin/subspace-bootstrap-node/main.rs @@ -7,6 +7,7 @@ use futures::{select, FutureExt}; use libp2p::identity::ed25519::Keypair; use libp2p::metrics::Metrics; use libp2p::{identity, Multiaddr, PeerId}; +use libp2p_kad::Mode; use prometheus_client::registry::Registry; use serde::{Deserialize, Serialize}; use std::error::Error; @@ -15,7 +16,7 @@ use std::net::SocketAddr; use std::sync::Arc; use subspace_metrics::{start_prometheus_metrics_server, RegistryAdapter}; use subspace_networking::libp2p::multiaddr::Protocol; -use subspace_networking::{peer_id, Config}; +use subspace_networking::{peer_id, Config, KademliaMode}; use tracing::{debug, info, Level}; use tracing_subscriber::fmt::Subscriber; use tracing_subscriber::util::SubscriberInitExt; @@ -163,6 +164,7 @@ async fn main() -> Result<(), Box> { general_connected_peers_handler: None, special_connected_peers_handler: None, bootstrap_addresses: bootstrap_nodes, + kademlia_mode: KademliaMode::Static(Mode::Server), external_addresses, metrics, diff --git a/crates/subspace-networking/src/constructor.rs b/crates/subspace-networking/src/constructor.rs index 5a91079584..e14b4f93c1 100644 --- a/crates/subspace-networking/src/constructor.rs +++ b/crates/subspace-networking/src/constructor.rs @@ -87,6 +87,20 @@ const TEMPORARY_BANS_DEFAULT_BACKOFF_RANDOMIZATION_FACTOR: f64 = 0.1; const TEMPORARY_BANS_DEFAULT_BACKOFF_MULTIPLIER: f64 = 1.5; const TEMPORARY_BANS_DEFAULT_MAX_INTERVAL: Duration = Duration::from_secs(30 * 60); +/// Max confidence for autonat protocol. Could affect Kademlia mode change. +pub(crate) const AUTONAT_MAX_CONFIDENCE: usize = 3; + +/// Defines Kademlia mode +pub enum KademliaMode { + /// The Kademlia mode is static for the duration of the application. + Static(Mode), + /// Kademlia mode will be changed using Autonat protocol when max confidence reached. + Dynamic { + /// Defines initial Kademlia mode. + initial_mode: Mode, + }, +} + /// Trait to be implemented on providers of local records pub trait LocalRecordProvider { /// Gets a provider record for key that is stored locally @@ -221,8 +235,8 @@ pub struct Config { pub special_target_connections: u32, /// Addresses to bootstrap Kademlia network pub bootstrap_addresses: Vec, - /// Kademlia mode. None means "automatic mode". - pub kademlia_mode: Option, + /// Kademlia mode. + pub kademlia_mode: KademliaMode, /// Known external addresses to the local peer. The addresses will be added on the swarm start /// and enable peer to notify others about its reachable address. pub external_addresses: Vec, @@ -340,7 +354,7 @@ where general_target_connections: SWARM_TARGET_CONNECTION_NUMBER, special_target_connections: SWARM_TARGET_CONNECTION_NUMBER, bootstrap_addresses: Vec::new(), - kademlia_mode: Some(Mode::Server), + kademlia_mode: KademliaMode::Static(Mode::Client), external_addresses: Vec::new(), enable_autonat: true, } @@ -468,6 +482,7 @@ where autonat: enable_autonat.then(|| AutonatConfig { use_connected: true, only_global_ips: !config.allow_non_global_addresses_in_dht, + confidence_max: AUTONAT_MAX_CONFIDENCE, ..Default::default() }), }); diff --git a/crates/subspace-networking/src/lib.rs b/crates/subspace-networking/src/lib.rs index 7ba4ba905d..7dfb5cf543 100644 --- a/crates/subspace-networking/src/lib.rs +++ b/crates/subspace-networking/src/lib.rs @@ -37,7 +37,9 @@ pub use crate::node_runner::NodeRunner; pub use crate::protocols::peer_info::{ Config as PeerInfoConfig, Notification, NotificationHandler, PeerInfo, PeerInfoProvider, }; -pub use constructor::{construct, peer_id, Config, CreationError, LocalRecordProvider}; +pub use constructor::{ + construct, peer_id, Config, CreationError, KademliaMode, LocalRecordProvider, +}; pub use libp2p; pub use protocols::request_response::handlers::generic_request_handler::{ GenericRequest, GenericRequestHandler, diff --git a/crates/subspace-networking/src/node_runner.rs b/crates/subspace-networking/src/node_runner.rs index d54634f814..b5cd35a56f 100644 --- a/crates/subspace-networking/src/node_runner.rs +++ b/crates/subspace-networking/src/node_runner.rs @@ -7,7 +7,7 @@ use crate::behavior::{ }; use crate::constructor; use crate::constructor::temporary_bans::TemporaryBans; -use crate::constructor::{ConnectedPeersHandler, LocalOnlyRecordStore}; +use crate::constructor::{ConnectedPeersHandler, KademliaMode, LocalOnlyRecordStore}; use crate::protocols::connected_peers::Event as ConnectedPeersEvent; use crate::protocols::peer_info::{Event as PeerInfoEvent, PeerInfoSuccess}; use crate::protocols::request_response::request_response_factory::{ @@ -22,18 +22,19 @@ use event_listener_primitives::HandlerId; use futures::channel::mpsc; use futures::future::Fuse; use futures::{FutureExt, StreamExt}; -use libp2p::autonat::Event as AutonatEvent; +use libp2p::autonat::{Event as AutonatEvent, NatStatus}; use libp2p::core::{address_translation, ConnectedPoint}; use libp2p::gossipsub::{Event as GossipsubEvent, TopicHash}; use libp2p::identify::Event as IdentifyEvent; use libp2p::kad::{ BootstrapOk, GetClosestPeersError, GetClosestPeersOk, GetProvidersError, GetProvidersOk, - GetRecordError, GetRecordOk, InboundRequest, Kademlia, KademliaEvent, Mode, PeerRecord, - ProgressStep, PutRecordOk, QueryId, QueryResult, Quorum, Record, + GetRecordError, GetRecordOk, InboundRequest, Kademlia, KademliaEvent, PeerRecord, ProgressStep, + PutRecordOk, QueryId, QueryResult, Quorum, Record, }; use libp2p::metrics::{Metrics, Recorder}; use libp2p::swarm::{DialError, SwarmEvent}; use libp2p::{futures, Multiaddr, PeerId, Swarm, TransportError}; +use libp2p_kad::Mode; use nohash_hasher::IntMap; use parking_lot::Mutex; use rand::rngs::StdRng; @@ -137,8 +138,8 @@ where bootstrap_addresses: Vec, /// Ensures a single bootstrap on run() invocation. bootstrap_command_state: Arc>, - /// Kademlia mode. None means "automatic mode". - kademlia_mode: Option, + /// Kademlia mode. + kademlia_mode: KademliaMode, /// Known external addresses to the local peer. The addresses are added on the swarm start /// and enable peer to notify others about its reachable address. external_addresses: Vec, @@ -167,7 +168,7 @@ where pub(crate) general_connection_decision_handler: Option, pub(crate) special_connection_decision_handler: Option, pub(crate) bootstrap_addresses: Vec, - pub(crate) kademlia_mode: Option, + pub(crate) kademlia_mode: KademliaMode, pub(crate) external_addresses: Vec, } @@ -318,11 +319,17 @@ where debug!("Bootstrap started."); + let initial_mode = match self.kademlia_mode { + KademliaMode::Static(mode) => mode, + KademliaMode::Dynamic { initial_mode } => initial_mode, + }; + self.swarm .behaviour_mut() .kademlia - .set_mode(self.kademlia_mode); - debug!("Kademlia mode set: {:?}.", self.kademlia_mode); + .set_mode(Some(initial_mode)); + + debug!("Kademlia mode set: {:?}.", initial_mode); let mut bootstrap_step = 0; loop { @@ -1186,7 +1193,34 @@ where } if let AutonatEvent::StatusChanged { old, new } = event { - info!(?old, ?new, "Public address status changed.") + info!(?old, ?new, "Public address status changed."); + + if let KademliaMode::Dynamic { .. } = self.kademlia_mode { + let mode = match &new { + NatStatus::Public(address) => { + if is_global_address_or_dns(address) + || self.allow_non_global_addresses_in_dht + { + Mode::Server + } else { + debug!( + ?old, + ?new, + ?address, + non_global_addresses=%self.allow_non_global_addresses_in_dht, + "Kademlia mode wasn't set." + ); + Mode::Client + } + } + NatStatus::Private => Mode::Client, + NatStatus::Unknown => Mode::Client, + }; + + self.swarm.behaviour_mut().kademlia.set_mode(Some(mode)); + + debug!("Kademlia mode set: {:?}.", mode); + }; } } diff --git a/crates/subspace-service/src/dsn.rs b/crates/subspace-service/src/dsn.rs index 16400ce1d2..25e8d92c21 100644 --- a/crates/subspace-service/src/dsn.rs +++ b/crates/subspace-service/src/dsn.rs @@ -6,13 +6,13 @@ use std::fs; use std::path::PathBuf; use std::sync::Arc; use subspace_core_primitives::{SegmentHeader, SegmentIndex}; -use subspace_networking::libp2p::kad::Mode as KademliaMode; +use subspace_networking::libp2p::kad::Mode; use subspace_networking::libp2p::metrics::Metrics; use subspace_networking::libp2p::{identity, Multiaddr}; use subspace_networking::utils::strip_peer_id; use subspace_networking::{ - CreationError, NetworkParametersPersistenceError, NetworkingParametersManager, Node, - NodeRunner, PeerInfoProvider, PieceByIndexRequestHandler, + CreationError, KademliaMode, NetworkParametersPersistenceError, NetworkingParametersManager, + Node, NodeRunner, PeerInfoProvider, PieceByIndexRequestHandler, SegmentHeaderBySegmentIndexesRequestHandler, SegmentHeaderRequest, SegmentHeaderResponse, }; use thiserror::Error; @@ -183,7 +183,7 @@ where general_connected_peers_handler: Some(Arc::new(|_| true)), bootstrap_addresses: dsn_config.bootstrap_nodes, external_addresses: dsn_config.external_addresses, - kademlia_mode: Some(KademliaMode::Client), + kademlia_mode: KademliaMode::Static(Mode::Client), metrics, ..default_networking_config From 82ee98a21ad61655d3de9f18976121fb60e8c4b2 Mon Sep 17 00:00:00 2001 From: Shamil Gadelshin Date: Tue, 10 Oct 2023 15:28:47 +0700 Subject: [PATCH 2/2] networking: Refactor the code. - add comments --- crates/subspace-networking/src/constructor.rs | 4 +++- crates/subspace-networking/src/node_runner.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/subspace-networking/src/constructor.rs b/crates/subspace-networking/src/constructor.rs index e14b4f93c1..41ae0fe7f1 100644 --- a/crates/subspace-networking/src/constructor.rs +++ b/crates/subspace-networking/src/constructor.rs @@ -235,7 +235,9 @@ pub struct Config { pub special_target_connections: u32, /// Addresses to bootstrap Kademlia network pub bootstrap_addresses: Vec, - /// Kademlia mode. + /// Kademlia mode. The default value is set to Static(Client). The peer won't add its address + /// to other peers` Kademlia routing table. Changing this behaviour implies that a peer can + /// provide pieces to others. pub kademlia_mode: KademliaMode, /// Known external addresses to the local peer. The addresses will be added on the swarm start /// and enable peer to notify others about its reachable address. diff --git a/crates/subspace-networking/src/node_runner.rs b/crates/subspace-networking/src/node_runner.rs index b5cd35a56f..59e56a1e77 100644 --- a/crates/subspace-networking/src/node_runner.rs +++ b/crates/subspace-networking/src/node_runner.rs @@ -1195,7 +1195,7 @@ where if let AutonatEvent::StatusChanged { old, new } = event { info!(?old, ?new, "Public address status changed."); - if let KademliaMode::Dynamic { .. } = self.kademlia_mode { + if matches!(self.kademlia_mode, KademliaMode::Dynamic { .. }) { let mode = match &new { NatStatus::Public(address) => { if is_global_address_or_dns(address)