From ab607891b57bec306ddadc3b8d87ce3267418aca Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Sat, 22 Jun 2024 23:02:33 +0100 Subject: [PATCH 01/11] Swarm listens on both TCP and QUIC addresses --- aquadoggo/Cargo.toml | 3 +- aquadoggo/src/api/config_file.rs | 16 ++++----- aquadoggo/src/network/config.rs | 6 ++-- aquadoggo/src/network/service.rs | 60 +++++++++++++++++++++++--------- aquadoggo/src/network/swarm.rs | 12 ++++++- aquadoggo/src/network/utils.rs | 18 ++++++++++ 6 files changed, 86 insertions(+), 29 deletions(-) diff --git a/aquadoggo/Cargo.toml b/aquadoggo/Cargo.toml index f542b4905..726e3b009 100644 --- a/aquadoggo/Cargo.toml +++ b/aquadoggo/Cargo.toml @@ -42,12 +42,13 @@ libp2p = { version = "0.53.2", features = [ "macros", "mdns", "noise", + "quic", "relay", "rendezvous", "serde", + "tcp", "tokio", "yamux", - "quic", ] } lipmaa-link = "0.2.2" log = "0.4.19" diff --git a/aquadoggo/src/api/config_file.rs b/aquadoggo/src/api/config_file.rs index 897c3a0b2..c1fc5a12a 100644 --- a/aquadoggo/src/api/config_file.rs +++ b/aquadoggo/src/api/config_file.rs @@ -21,7 +21,7 @@ const DEFAULT_MAX_DATABASE_CONNECTIONS: u32 = 32; const DEFAULT_HTTP_PORT: u16 = 2020; -const DEFAULT_QUIC_PORT: u16 = 2022; +const DEFAULT_NODE_PORT: u16 = 2022; const DEFAULT_WORKER_POOL_SIZE: u32 = 16; @@ -41,8 +41,8 @@ fn default_http_port() -> u16 { DEFAULT_HTTP_PORT } -fn default_quic_port() -> u16 { - DEFAULT_QUIC_PORT +fn default_node_port() -> u16 { + DEFAULT_NODE_PORT } fn default_database_url() -> String { @@ -116,9 +116,9 @@ pub struct ConfigFile { #[serde(default = "default_http_port")] pub http_port: u16, - /// QUIC port for node-node communication and data replication. Defaults to 2022. - #[serde(default = "default_quic_port")] - pub quic_port: u16, + /// TCP / QUIC port for node-node communication and data replication. Defaults to 2022. + #[serde(default = "default_node_port")] + pub node_port: u16, /// Path to folder where blobs (large binary files) are persisted. Defaults to a temporary /// directory. @@ -219,7 +219,7 @@ impl Default for ConfigFile { database_url: default_database_url(), database_max_connections: default_max_database_connections(), http_port: default_http_port(), - quic_port: default_quic_port(), + node_port: default_node_port(), blobs_base_path: None, mdns: default_mdns(), private_key: None, @@ -301,7 +301,7 @@ impl TryFrom for Configuration { blobs_base_path, worker_pool_size: value.worker_pool_size, network: NetworkConfiguration { - quic_port: value.quic_port, + port: value.node_port, mdns: value.mdns, direct_node_addresses, allow_peer_ids, diff --git a/aquadoggo/src/network/config.rs b/aquadoggo/src/network/config.rs index 4854ff734..e12b93ee9 100644 --- a/aquadoggo/src/network/config.rs +++ b/aquadoggo/src/network/config.rs @@ -15,8 +15,8 @@ pub const NODE_NAMESPACE: &str = "aquadoggo"; /// Network config for the node. #[derive(Debug, Clone)] pub struct NetworkConfiguration { - /// QUIC port for node-node communication and data replication. - pub quic_port: u16, + /// QUIC or TCP port for node-node communication and data replication. + pub port: u16, /// Discover peers on the local network via mDNS (over IPv4 only, using port 5353). pub mdns: bool, @@ -120,7 +120,7 @@ pub struct NetworkConfiguration { impl Default for NetworkConfiguration { fn default() -> Self { Self { - quic_port: 2022, + port: 2022, mdns: true, direct_node_addresses: Vec::new(), allow_peer_ids: AllowList::::Wildcard, diff --git a/aquadoggo/src/network/service.rs b/aquadoggo/src/network/service.rs index 8671c1c18..5008ca8c7 100644 --- a/aquadoggo/src/network/service.rs +++ b/aquadoggo/src/network/service.rs @@ -61,22 +61,39 @@ pub async fn network_service( }; // Start listening on QUIC address. Pick a random one if the given is taken already. - let listen_addr_quic = Multiaddr::empty() + let mut listen_addr_quic = Multiaddr::empty() .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) - .with(Protocol::Udp(network_config.quic_port)) + .with(Protocol::Udp(network_config.port)) .with(Protocol::QuicV1); - if swarm.listen_on(listen_addr_quic).is_err() { - let random_port_addr = Multiaddr::empty() + if swarm.listen_on(listen_addr_quic.clone()).is_err() { + listen_addr_quic = Multiaddr::empty() .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) .with(Protocol::Udp(0)) .with(Protocol::QuicV1); info_or_print(&format!( "QUIC port {} was already taken, try random port instead ..", - network_config.quic_port + network_config.port )); - swarm.listen_on(random_port_addr)?; + swarm.listen_on(listen_addr_quic.clone())?; + } + + // Start listening on TCP address. Pick a random one if the given is taken already. + let mut listen_address_tcp = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Tcp(network_config.port)); + if swarm.listen_on(listen_address_tcp.clone()).is_err() { + listen_address_tcp = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Tcp(0)); + + info_or_print(&format!( + "TCP port {} was already taken, try random port instead ..", + network_config.port + )); + + swarm.listen_on(listen_address_tcp.clone())?; } info!("Network service ready!"); @@ -122,8 +139,11 @@ struct EventLoop { /// Shutdown handler. shutdown_handler: ShutdownHandler, - /// Did we learn our own port yet. - learned_port: bool, + /// Did we learn our own QUIC port yet. + learned_quic_port: bool, + + /// Did we learn our own TCP port yet. + learned_tcp_port: bool, /// Did we learn our observed address yet. learned_observed_addr: bool, @@ -147,7 +167,8 @@ impl EventLoop { known_peers: HashMap::new(), relays: HashMap::new(), shutdown_handler, - learned_port: false, + learned_quic_port: false, + learned_tcp_port: false, learned_observed_addr: false, } } @@ -179,15 +200,22 @@ impl EventLoop { let event = event.expect("Swarm stream to be infinite"); match event { SwarmEvent::NewListenAddr { address, .. } => { - if self.learned_port { - continue; + if !self.learned_quic_port { + // Show only one QUIC address during the runtime of the node, otherwise + // it might get too spammy + if let Some(address) = utils::to_quic_address(&address) { + info_or_print(&format!("Node is listening on 0.0.0.0:{} (QUIC)", address.port())); + self.learned_quic_port = true; + } } - // Show only one QUIC address during the runtime of the node, otherwise - // it might get too spammy - if let Some(address) = utils::to_quic_address(&address) { - info_or_print(&format!("Node is listening on 0.0.0.0:{}", address.port())); - self.learned_port = true; + if !self.learned_tcp_port { + // Show only one TCP address during the runtime of the node, otherwise + // it might get too spammy + if let Some(address) = utils::to_tcp_address(&address) { + info_or_print(&format!("Node is listening on 0.0.0.0:{} (TCP)", address.port())); + self.learned_tcp_port = true; + } } } SwarmEvent::Behaviour(Event::Identify(event)) => self.handle_identify_events(&event).await, diff --git a/aquadoggo/src/network/swarm.rs b/aquadoggo/src/network/swarm.rs index 6f525db6e..d80ae1509 100644 --- a/aquadoggo/src/network/swarm.rs +++ b/aquadoggo/src/network/swarm.rs @@ -2,7 +2,7 @@ use anyhow::Result; use libp2p::identity::Keypair; -use libp2p::{noise, yamux, Swarm, SwarmBuilder}; +use libp2p::{noise, tcp, yamux, Swarm, SwarmBuilder}; use crate::network::behaviour::P2pandaBehaviour; use crate::network::NetworkConfiguration; @@ -13,6 +13,11 @@ pub async fn build_relay_swarm( ) -> Result> { let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() + .with_tcp( + tcp::Config::default().port_reuse(true).nodelay(true), + noise::Config::new, + yamux::Config::default, + )? .with_quic() .with_behaviour(|key_pair| P2pandaBehaviour::new(network_config, key_pair, None).unwrap())? .build(); @@ -25,6 +30,11 @@ pub async fn build_client_swarm( ) -> Result> { let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() + .with_tcp( + tcp::Config::default().port_reuse(true).nodelay(true), + noise::Config::new, + yamux::Config::default, + )? .with_quic() .with_relay_client(noise::Config::new, yamux::Config::default)? .with_behaviour(|key_pair, relay_client| { diff --git a/aquadoggo/src/network/utils.rs b/aquadoggo/src/network/utils.rs index e19f0edff..7bb667980 100644 --- a/aquadoggo/src/network/utils.rs +++ b/aquadoggo/src/network/utils.rs @@ -30,6 +30,24 @@ pub fn to_quic_address(address: &Multiaddr) -> Option { } } +pub fn to_tcp_address(address: &Multiaddr) -> Option { + let hay = address.to_string(); + let regex = Regex::new(r"/ip4/(\d+.\d+.\d+.\d+)/tcp/(\d+)").unwrap(); + let caps = regex.captures(&hay); + + match caps { + None => None, + Some(caps) => { + let ip_address = caps.get(1).unwrap().as_str(); + let port = caps.get(2).unwrap().as_str(); + let socket = format!("{ip_address}:{port}") + .parse::() + .expect("Tried to convert invalid address"); + Some(socket) + } + } +} + pub fn is_known_peer_address( known_addresses: &mut [PeerAddress], peer_addresses: &[Multiaddr], From e1a79576cca69f348ef81204ae8db2e3752d06cf Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Mon, 24 Jun 2024 14:47:10 +0100 Subject: [PATCH 02/11] Support both QUIC and TCP protocols --- aquadoggo/src/api/config_file.rs | 8 +- aquadoggo/src/lib.rs | 2 +- aquadoggo/src/network/config.rs | 60 ++++++++++++ aquadoggo/src/network/mod.rs | 2 +- aquadoggo/src/network/relay.rs | 10 +- aquadoggo/src/network/service.rs | 160 +++++++++++++++++++------------ aquadoggo/src/network/swarm.rs | 2 +- aquadoggo/src/network/utils.rs | 22 ++++- aquadoggo_cli/src/config.rs | 9 +- 9 files changed, 197 insertions(+), 78 deletions(-) diff --git a/aquadoggo/src/api/config_file.rs b/aquadoggo/src/api/config_file.rs index c1fc5a12a..2021494ec 100644 --- a/aquadoggo/src/api/config_file.rs +++ b/aquadoggo/src/api/config_file.rs @@ -11,7 +11,7 @@ use p2panda_rs::schema::SchemaId; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tempfile::TempDir; -use crate::{AllowList, Configuration, NetworkConfiguration}; +use crate::{AllowList, Configuration, NetworkConfiguration, Transport}; const WILDCARD: &str = "*"; @@ -116,6 +116,10 @@ pub struct ConfigFile { #[serde(default = "default_http_port")] pub http_port: u16, + /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + #[serde(default)] + pub transport: Transport, + /// TCP / QUIC port for node-node communication and data replication. Defaults to 2022. #[serde(default = "default_node_port")] pub node_port: u16, @@ -214,6 +218,7 @@ pub struct ConfigFile { impl Default for ConfigFile { fn default() -> Self { Self { + transport: Transport::default(), log_level: default_log_level(), allow_schema_ids: UncheckedAllowList::default(), database_url: default_database_url(), @@ -301,6 +306,7 @@ impl TryFrom for Configuration { blobs_base_path, worker_pool_size: value.worker_pool_size, network: NetworkConfiguration { + transport: value.transport, port: value.node_port, mdns: value.mdns, direct_node_addresses, diff --git a/aquadoggo/src/lib.rs b/aquadoggo/src/lib.rs index c60a03f92..8452e926b 100644 --- a/aquadoggo/src/lib.rs +++ b/aquadoggo/src/lib.rs @@ -36,7 +36,7 @@ use log::{info, log_enabled, Level}; pub use crate::api::{ConfigFile, LockFile}; pub use crate::config::{AllowList, Configuration}; -pub use crate::network::NetworkConfiguration; +pub use crate::network::{NetworkConfiguration, Transport}; pub use node::Node; /// Init env_logger before the test suite runs to handle logging outputs. diff --git a/aquadoggo/src/network/config.rs b/aquadoggo/src/network/config.rs index e12b93ee9..a90d8e626 100644 --- a/aquadoggo/src/network/config.rs +++ b/aquadoggo/src/network/config.rs @@ -1,11 +1,13 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use std::net::{IpAddr, SocketAddr, ToSocketAddrs}; +use std::str::FromStr; use anyhow::Error; use libp2p::connection_limits::ConnectionLimits; use libp2p::multiaddr::Protocol; use libp2p::{Multiaddr, PeerId}; +use serde::{Deserialize, Deserializer, Serialize}; use crate::AllowList; @@ -15,6 +17,9 @@ pub const NODE_NAMESPACE: &str = "aquadoggo"; /// Network config for the node. #[derive(Debug, Clone)] pub struct NetworkConfiguration { + /// protocol (TCP/QUIC) used for node-node communication and data replication. + pub transport: Transport, + /// QUIC or TCP port for node-node communication and data replication. pub port: u16, @@ -120,6 +125,7 @@ pub struct NetworkConfiguration { impl Default for NetworkConfiguration { fn default() -> Self { Self { + transport: Transport::QUIC, port: 2022, mdns: true, direct_node_addresses: Vec::new(), @@ -204,6 +210,20 @@ impl PeerAddress { Err(e) => Err(e), } } + + pub fn tcp_multiaddr(&mut self) -> Result { + match self.socket() { + Ok(socket_address) => { + let mut multiaddr = match socket_address.ip() { + IpAddr::V4(ip) => Multiaddr::from(Protocol::Ip4(ip)), + IpAddr::V6(ip) => Multiaddr::from(Protocol::Ip6(ip)), + }; + multiaddr.push(Protocol::Tcp(socket_address.port())); + Ok(multiaddr) + } + Err(e) => Err(e), + } + } } impl From for PeerAddress { @@ -217,3 +237,43 @@ impl std::fmt::Display for PeerAddress { write!(f, "{}", self.addr_str) } } + +/// Enum representing transport protocol types. +#[derive(Debug, Clone, Copy, Default, Serialize)] +pub enum Transport { + #[default] + /// UDP/QUIC transport protocol + QUIC, + + /// TCP transport protocol + TCP, +} + +impl<'de> Deserialize<'de> for Transport { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let str_value = String::deserialize(deserializer)?; + let transport = str_value + .parse() + .map_err(|_| serde::de::Error::custom("Could not parse string as transport type"))?; + + Ok(transport) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct TransportParsingError; + +impl FromStr for Transport { + type Err = TransportParsingError; + + fn from_str(s: &str) -> Result { + match s.to_uppercase().as_str() { + "TCP" => Ok(Transport::TCP), + "QUIC" => Ok(Transport::QUIC), + _ => Err(TransportParsingError), + } + } +} diff --git a/aquadoggo/src/network/mod.rs b/aquadoggo/src/network/mod.rs index 400c0a023..c16c150b5 100644 --- a/aquadoggo/src/network/mod.rs +++ b/aquadoggo/src/network/mod.rs @@ -10,7 +10,7 @@ mod shutdown; mod swarm; pub mod utils; -pub use config::NetworkConfiguration; +pub use config::{NetworkConfiguration, Transport}; pub use peers::{Peer, PeerMessage}; pub use service::network_service; pub use shutdown::ShutdownHandler; diff --git a/aquadoggo/src/network/relay.rs b/aquadoggo/src/network/relay.rs index 89f2dd74f..5372cfcbd 100644 --- a/aquadoggo/src/network/relay.rs +++ b/aquadoggo/src/network/relay.rs @@ -61,14 +61,12 @@ impl Relay { return Ok(false); } - self.registering = true; - // Start listening on the circuit relay address. let circuit_address = self.circuit_addr(); swarm.listen_on(circuit_address.clone())?; // Register in the `NODE_NAMESPACE` using the rendezvous network behaviour. - swarm + let result = swarm .behaviour_mut() .rendezvous_client .as_mut() @@ -77,7 +75,11 @@ impl Relay { rendezvous::Namespace::from_static(NODE_NAMESPACE), self.peer_id, None, // Default ttl is 7200s - )?; + ); + + // If register attempt failed switch registering flag back to false. + self.registering = result.is_ok(); + result?; Ok(true) } diff --git a/aquadoggo/src/network/service.rs b/aquadoggo/src/network/service.rs index 5008ca8c7..176fe2c25 100644 --- a/aquadoggo/src/network/service.rs +++ b/aquadoggo/src/network/service.rs @@ -21,6 +21,7 @@ use crate::bus::{ServiceMessage, ServiceSender}; use crate::context::Context; use crate::manager::{ServiceReadySender, Shutdown}; use crate::network::behaviour::{Event, P2pandaBehaviour}; +use crate::network::config::Transport; use crate::network::relay::Relay; use crate::network::utils::{dial_known_peer, is_known_peer_address}; use crate::network::{identity, peers, swarm, utils, ShutdownHandler}; @@ -60,40 +61,45 @@ pub async fn network_service( swarm::build_client_swarm(&network_config, key_pair).await? }; - // Start listening on QUIC address. Pick a random one if the given is taken already. - let mut listen_addr_quic = Multiaddr::empty() - .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) - .with(Protocol::Udp(network_config.port)) - .with(Protocol::QuicV1); - if swarm.listen_on(listen_addr_quic.clone()).is_err() { - listen_addr_quic = Multiaddr::empty() - .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) - .with(Protocol::Udp(0)) - .with(Protocol::QuicV1); - - info_or_print(&format!( - "QUIC port {} was already taken, try random port instead ..", - network_config.port - )); - - swarm.listen_on(listen_addr_quic.clone())?; - } - - // Start listening on TCP address. Pick a random one if the given is taken already. - let mut listen_address_tcp = Multiaddr::empty() - .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) - .with(Protocol::Tcp(network_config.port)); - if swarm.listen_on(listen_address_tcp.clone()).is_err() { - listen_address_tcp = Multiaddr::empty() - .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) - .with(Protocol::Tcp(0)); - - info_or_print(&format!( - "TCP port {} was already taken, try random port instead ..", - network_config.port - )); - - swarm.listen_on(listen_address_tcp.clone())?; + match network_config.transport { + Transport::QUIC => { + // Start listening on QUIC address. Pick a random one if the given is taken already. + let mut listen_addr_quic = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Udp(network_config.port)) + .with(Protocol::QuicV1); + if swarm.listen_on(listen_addr_quic.clone()).is_err() { + info_or_print(&format!( + "QUIC port {} was already taken, try random port instead ..", + network_config.port + )); + + listen_addr_quic = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Udp(0)) + .with(Protocol::QuicV1); + + swarm.listen_on(listen_addr_quic.clone())?; + } + } + Transport::TCP => { + // Start listening on TCP address. Pick a random one if the given is taken already. + let mut listen_address_tcp = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Tcp(network_config.port)); + if swarm.listen_on(listen_address_tcp.clone()).is_err() { + info_or_print(&format!( + "TCP port {} was already taken, try random port instead ..", + network_config.port + )); + + listen_address_tcp = Multiaddr::empty() + .with(Protocol::from(Ipv4Addr::UNSPECIFIED)) + .with(Protocol::Tcp(0)); + + swarm.listen_on(listen_address_tcp.clone())?; + } + } } info!("Network service ready!"); @@ -255,13 +261,23 @@ impl EventLoop { // Attempt to dial all relay addresses. for relay_address in self.network_config.relay_addresses.iter_mut() { debug!("Dial relay at address {}", relay_address); - dial_known_peer(&mut self.swarm, &mut self.known_peers, relay_address); + dial_known_peer( + &mut self.swarm, + &mut self.known_peers, + relay_address, + self.network_config.transport, + ); } // Attempt to dial all direct peer addresses. for direct_node_address in self.network_config.direct_node_addresses.iter_mut() { debug!("Dial direct peer at address {}", direct_node_address); - dial_known_peer(&mut self.swarm, &mut self.known_peers, direct_node_address); + dial_known_peer( + &mut self.swarm, + &mut self.known_peers, + direct_node_address, + self.network_config.transport, + ); } } @@ -372,12 +388,7 @@ impl EventLoop { async fn handle_identify_events(&mut self, event: &identify::Event) { match event { identify::Event::Received { - info: - identify::Info { - observed_addr, - listen_addrs, - .. - }, + info: identify::Info { observed_addr, .. }, peer_id, } => { // We now learned at least one of our observed addr. @@ -401,32 +412,22 @@ impl EventLoop { // to avoid multiple connections being established to the same peer. // Check if the identified peer is one of our configured relay addresses. - if let Some(addr) = - is_known_peer_address(&mut self.network_config.relay_addresses, listen_addrs) - { - if self.relays.contains_key(peer_id) { + if let Some(relay) = self.relays.get_mut(peer_id) { + if !self.learned_observed_addr || !relay.told_addr { return; } - // Add the relay to our known peers. - debug!("Relay identified {peer_id} {addr}"); - self.known_peers.insert(addr.clone(), *peer_id); - - // Also add it to our map of identified relays. - self.relays.insert(*peer_id, Relay::new(*peer_id, addr)); - } - - // Check if the identified peer is one of our direct node addresses. - if let Some(addr) = is_known_peer_address( - &mut self.network_config.direct_node_addresses, - listen_addrs, - ) { - // Add the direct node to our known peers. - debug!("Direct node identified {peer_id} {addr}"); - self.known_peers.insert(addr, *peer_id); + // Attempt to register with the relay. + match relay.register(&mut self.swarm) { + Ok(registered) => { + if registered { + debug!("Registration request sent to relay {}", relay.peer_id) + } + } + Err(e) => debug!("Error registering on relay: {}", e), + }; } } - identify::Event::Sent { peer_id } => { if let Some(relay) = self.relays.get_mut(peer_id) { if !relay.told_addr { @@ -434,7 +435,12 @@ impl EventLoop { relay.told_addr = true; } + if !self.learned_observed_addr || !relay.told_addr { + return; + } + // Attempt to register with the relay. + debug!("Register on relay {}", relay.peer_id); match relay.register(&mut self.swarm) { Ok(registered) => { if registered { @@ -507,6 +513,7 @@ impl EventLoop { SwarmEvent::ConnectionEstablished { endpoint, num_established, + peer_id, .. } => { debug!( @@ -514,6 +521,33 @@ impl EventLoop { endpoint.get_remote_address(), num_established ); + + // Check if the connected peer is one of our relay addresses. + if let Some(addr) = is_known_peer_address( + &mut self.network_config.relay_addresses, + &[endpoint.get_remote_address().to_owned()], + self.network_config.transport, + ) { + if self.relays.contains_key(&peer_id) { + return; + } + + // Add the relay to our known peers. + debug!("Relay identified {peer_id} {addr}"); + self.known_peers.insert(addr.clone(), peer_id); + self.relays.insert(peer_id, Relay::new(peer_id, addr)); + } + + // Check if the connected peer is one of our direct node addresses. + if let Some(addr) = is_known_peer_address( + &mut self.network_config.direct_node_addresses, + &[endpoint.get_remote_address().to_owned()], + self.network_config.transport, + ) { + // Add the direct node to our known peers. + debug!("Direct node identified {peer_id} {addr}"); + self.known_peers.insert(addr, peer_id); + } } SwarmEvent::ConnectionClosed { peer_id, diff --git a/aquadoggo/src/network/swarm.rs b/aquadoggo/src/network/swarm.rs index d80ae1509..a947502d1 100644 --- a/aquadoggo/src/network/swarm.rs +++ b/aquadoggo/src/network/swarm.rs @@ -31,7 +31,7 @@ pub async fn build_client_swarm( let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() .with_tcp( - tcp::Config::default().port_reuse(true).nodelay(true), + tcp::Config::default().nodelay(true), noise::Config::new, yamux::Config::default, )? diff --git a/aquadoggo/src/network/utils.rs b/aquadoggo/src/network/utils.rs index 7bb667980..6f53f127b 100644 --- a/aquadoggo/src/network/utils.rs +++ b/aquadoggo/src/network/utils.rs @@ -10,7 +10,7 @@ use log::debug; use regex::Regex; use crate::network::behaviour::P2pandaBehaviour; -use crate::network::config::PeerAddress; +use crate::network::config::{PeerAddress, Transport}; pub fn to_quic_address(address: &Multiaddr) -> Option { let hay = address.to_string(); @@ -51,9 +51,15 @@ pub fn to_tcp_address(address: &Multiaddr) -> Option { pub fn is_known_peer_address( known_addresses: &mut [PeerAddress], peer_addresses: &[Multiaddr], + transport: Transport, ) -> Option { for address in known_addresses.iter_mut() { - if let Ok(addr) = address.quic_multiaddr() { + let address = match transport { + Transport::QUIC => address.quic_multiaddr(), + Transport::TCP => address.tcp_multiaddr(), + }; + + if let Ok(addr) = address { if peer_addresses.contains(&addr) { return Some(addr.clone()); } @@ -66,11 +72,17 @@ pub fn dial_known_peer( swarm: &mut Swarm, known_peers: &mut HashMap, address: &mut PeerAddress, + transport: Transport, ) { - // Get the peers quic multiaddress, this can error if the address was provided in the form - // of a domain name and we are not able to resolve it to a valid multiaddress (for example, + // Get the peers multiaddr, this can error if the address was provided in the form + // of a domain name and we are not able to resolve it to a valid address (for example, // if we are offline). - let address = match address.quic_multiaddr() { + let address = match transport { + Transport::QUIC => address.quic_multiaddr(), + Transport::TCP => address.tcp_multiaddr(), + }; + + let address = match address { Ok(address) => address, Err(e) => { debug!("Failed to resolve relay multiaddr: {}", e.to_string()); diff --git a/aquadoggo_cli/src/config.rs b/aquadoggo_cli/src/config.rs index 758beec51..bd92c42ff 100644 --- a/aquadoggo_cli/src/config.rs +++ b/aquadoggo_cli/src/config.rs @@ -112,10 +112,15 @@ struct Cli { #[serde(skip_serializing_if = "Option::is_none")] http_port: Option, + /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + #[arg(short = 'q', long, value_name = "TRANSPORT")] + #[serde(skip_serializing_if = "Option::is_none")] + pub transport: Option, + /// QUIC port for node-node communication and data replication. Defaults to 2022. - #[arg(short = 'q', long, value_name = "PORT")] + #[arg(short = 't', long, value_name = "PORT")] #[serde(skip_serializing_if = "Option::is_none")] - quic_port: Option, + node_port: Option, /// Path to folder where blobs (large binary files) are persisted. Defaults to a temporary /// directory. From e5d123dbdc7c1a097c3703d6b2b00986e2ee1cd9 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Mon, 24 Jun 2024 14:48:37 +0100 Subject: [PATCH 03/11] TCP port_reuse should be false --- aquadoggo/src/network/swarm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aquadoggo/src/network/swarm.rs b/aquadoggo/src/network/swarm.rs index a947502d1..79f87a0a6 100644 --- a/aquadoggo/src/network/swarm.rs +++ b/aquadoggo/src/network/swarm.rs @@ -14,7 +14,7 @@ pub async fn build_relay_swarm( let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() .with_tcp( - tcp::Config::default().port_reuse(true).nodelay(true), + tcp::Config::default().nodelay(true), noise::Config::new, yamux::Config::default, )? From ec2ac4f07c055e806735ad2a5522a79c5daddd8a Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Mon, 24 Jun 2024 15:43:11 +0100 Subject: [PATCH 04/11] Establish a private net over TCP when psk provided in NetworkConfig --- Cargo.lock | 68 +++++++++++++++++++++++++--- aquadoggo/Cargo.toml | 2 + aquadoggo/src/network/config.rs | 9 +++- aquadoggo/src/network/service.rs | 15 +++--- aquadoggo/src/network/swarm.rs | 78 +++++++++++++++++++++++--------- 5 files changed, 132 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c40661a2..0e31fb738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", "cpufeatures", "opaque-debug", ] @@ -56,7 +56,7 @@ checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" dependencies = [ "aead", "aes", - "cipher", + "cipher 0.3.0", "ctr", "ghash", "subtle", @@ -173,6 +173,7 @@ dependencies = [ "ctor", "deadqueue", "dynamic-graphql", + "either", "env_logger", "envy", "futures", @@ -952,7 +953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", "cpufeatures", "zeroize", ] @@ -965,7 +966,7 @@ checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", - "cipher", + "cipher 0.3.0", "poly1305", "zeroize", ] @@ -1006,6 +1007,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.3.14" @@ -1236,7 +1247,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" dependencies = [ - "cipher", + "cipher 0.3.0", ] [[package]] @@ -1543,9 +1554,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "encoding_rs" @@ -2305,6 +2316,15 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -2461,6 +2481,7 @@ dependencies = [ "libp2p-mdns", "libp2p-metrics", "libp2p-noise", + "libp2p-pnet", "libp2p-quic", "libp2p-relay", "libp2p-rendezvous", @@ -2803,6 +2824,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "libp2p-pnet" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2dcb82113064b0baf0a3b92d30ad61211ff66fff02f2973b569b77b2d1811a" +dependencies = [ + "futures", + "pin-project", + "rand 0.8.5", + "salsa20", + "sha3", + "tracing", +] + [[package]] name = "libp2p-quic" version = "0.10.2" @@ -4413,6 +4448,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -4562,6 +4606,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + [[package]] name = "signal-hook" version = "0.3.16" diff --git a/aquadoggo/Cargo.toml b/aquadoggo/Cargo.toml index 726e3b009..76d888ce3 100644 --- a/aquadoggo/Cargo.toml +++ b/aquadoggo/Cargo.toml @@ -33,6 +33,7 @@ deadqueue = { version = "0.2.3", default-features = false, features = [ "unlimited", ] } dynamic-graphql = "0.7.3" +either = "1.12.0" futures = "0.3.23" hex = "0.4.3" http = "0.2.9" @@ -42,6 +43,7 @@ libp2p = { version = "0.53.2", features = [ "macros", "mdns", "noise", + "pnet", "quic", "relay", "rendezvous", diff --git a/aquadoggo/src/network/config.rs b/aquadoggo/src/network/config.rs index a90d8e626..c7a8fe75a 100644 --- a/aquadoggo/src/network/config.rs +++ b/aquadoggo/src/network/config.rs @@ -6,6 +6,7 @@ use std::str::FromStr; use anyhow::Error; use libp2p::connection_limits::ConnectionLimits; use libp2p::multiaddr::Protocol; +use libp2p::pnet::PreSharedKey; use libp2p::{Multiaddr, PeerId}; use serde::{Deserialize, Deserializer, Serialize}; @@ -17,9 +18,12 @@ pub const NODE_NAMESPACE: &str = "aquadoggo"; /// Network config for the node. #[derive(Debug, Clone)] pub struct NetworkConfiguration { - /// protocol (TCP/QUIC) used for node-node communication and data replication. + /// protocol (TCP/QUIC) used for node-node communication and data replication. pub transport: Transport, + /// Establish a private net secured by this pre-shared key. + pub psk: Option, + /// QUIC or TCP port for node-node communication and data replication. pub port: u16, @@ -126,6 +130,7 @@ impl Default for NetworkConfiguration { fn default() -> Self { Self { transport: Transport::QUIC, + psk: None, port: 2022, mdns: true, direct_node_addresses: Vec::new(), @@ -239,7 +244,7 @@ impl std::fmt::Display for PeerAddress { } /// Enum representing transport protocol types. -#[derive(Debug, Clone, Copy, Default, Serialize)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)] pub enum Transport { #[default] /// UDP/QUIC transport protocol diff --git a/aquadoggo/src/network/service.rs b/aquadoggo/src/network/service.rs index 176fe2c25..b664001d4 100644 --- a/aquadoggo/src/network/service.rs +++ b/aquadoggo/src/network/service.rs @@ -23,8 +23,9 @@ use crate::manager::{ServiceReadySender, Shutdown}; use crate::network::behaviour::{Event, P2pandaBehaviour}; use crate::network::config::Transport; use crate::network::relay::Relay; +use crate::network::swarm::{build_quic_swarm, build_tcp_swarm}; use crate::network::utils::{dial_known_peer, is_known_peer_address}; -use crate::network::{identity, peers, swarm, utils, ShutdownHandler}; +use crate::network::{identity, peers, utils, ShutdownHandler}; use crate::{info_or_print, NetworkConfiguration}; /// Interval at which we attempt to dial known peers and relays. @@ -52,14 +53,10 @@ pub async fn network_service( info_or_print(&format!("Peer id: {local_peer_id}")); - // The swarm can be initiated with or without "relay" capabilities. - let mut swarm = if network_config.relay_mode { - info!("Networking service initializing with relay capabilities..."); - swarm::build_relay_swarm(&network_config, key_pair).await? - } else { - info!("Networking service initializing..."); - swarm::build_client_swarm(&network_config, key_pair).await? - }; + let mut swarm = match network_config.transport { + Transport::QUIC => build_quic_swarm(&network_config, key_pair), + Transport::TCP => build_tcp_swarm(&network_config, key_pair), + }?; match network_config.transport { Transport::QUIC => { diff --git a/aquadoggo/src/network/swarm.rs b/aquadoggo/src/network/swarm.rs index 79f87a0a6..8a6bd73bf 100644 --- a/aquadoggo/src/network/swarm.rs +++ b/aquadoggo/src/network/swarm.rs @@ -1,45 +1,79 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use anyhow::Result; +use either::Either; +use libp2p::core::upgrade::Version; use libp2p::identity::Keypair; -use libp2p::{noise, tcp, yamux, Swarm, SwarmBuilder}; +use libp2p::pnet::PnetConfig; +use libp2p::{noise, tcp, yamux, Swarm, SwarmBuilder, Transport}; use crate::network::behaviour::P2pandaBehaviour; use crate::network::NetworkConfiguration; -pub async fn build_relay_swarm( +pub fn build_tcp_swarm( network_config: &NetworkConfiguration, key_pair: Keypair, ) -> Result> { let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() - .with_tcp( - tcp::Config::default().nodelay(true), - noise::Config::new, - yamux::Config::default, - )? - .with_quic() - .with_behaviour(|key_pair| P2pandaBehaviour::new(network_config, key_pair, None).unwrap())? - .build(); + .with_other_transport(|key| { + let noise_config = noise::Config::new(key).unwrap(); + let yamux_config = yamux::Config::default(); + + let base_transport = tcp::tokio::Transport::new(tcp::Config::default().nodelay(true)); + let maybe_encrypted = match network_config.psk { + Some(psk) => Either::Left( + base_transport + .and_then(move |socket, _| PnetConfig::new(psk).handshake(socket)), + ), + None => Either::Right(base_transport), + }; + maybe_encrypted + .upgrade(Version::V1Lazy) + .authenticate(noise_config) + .multiplex(yamux_config) + })?; + + let swarm = if !network_config.relay_mode && !network_config.relay_addresses.is_empty() { + swarm + .with_relay_client(noise::Config::new, yamux::Config::default)? + .with_behaviour(|key_pair, relay_client| { + P2pandaBehaviour::new(network_config, key_pair, Some(relay_client)).unwrap() + })? + .build() + } else { + swarm + .with_behaviour(|key_pair| { + P2pandaBehaviour::new(network_config, key_pair, None).unwrap() + })? + .build() + }; + Ok(swarm) } -pub async fn build_client_swarm( +pub fn build_quic_swarm( network_config: &NetworkConfiguration, key_pair: Keypair, ) -> Result> { let swarm = SwarmBuilder::with_existing_identity(key_pair) .with_tokio() - .with_tcp( - tcp::Config::default().nodelay(true), - noise::Config::new, - yamux::Config::default, - )? - .with_quic() - .with_relay_client(noise::Config::new, yamux::Config::default)? - .with_behaviour(|key_pair, relay_client| { - P2pandaBehaviour::new(network_config, key_pair, Some(relay_client)).unwrap() - })? - .build(); + .with_quic(); + + let swarm = if !network_config.relay_mode && !network_config.relay_addresses.is_empty() { + swarm + .with_relay_client(noise::Config::new, yamux::Config::default)? + .with_behaviour(|key_pair, relay_client| { + P2pandaBehaviour::new(network_config, key_pair, Some(relay_client)).unwrap() + })? + .build() + } else { + swarm + .with_behaviour(|key_pair| { + P2pandaBehaviour::new(network_config, key_pair, None).unwrap() + })? + .build() + }; + Ok(swarm) } From 58ab0767ed7bdf0ce439eb9f666d7c710b4c4a39 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Mon, 24 Jun 2024 16:38:23 +0100 Subject: [PATCH 05/11] Initiate swarm with private net when psk provided in config --- aquadoggo/src/api/config_file.rs | 23 +++++++++++++++++++++-- aquadoggo/src/network/config.rs | 7 ++++++- aquadoggo/src/network/service.rs | 7 ++++++- aquadoggo_cli/src/config.rs | 20 +++++++++++++++++++- aquadoggo_cli/src/main.rs | 9 ++++++++- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/aquadoggo/src/api/config_file.rs b/aquadoggo/src/api/config_file.rs index 2021494ec..3053da776 100644 --- a/aquadoggo/src/api/config_file.rs +++ b/aquadoggo/src/api/config_file.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use std::sync::OnceLock; use anyhow::{anyhow, Result}; -use libp2p::PeerId; +use libp2p::{pnet::PreSharedKey, PeerId}; use p2panda_rs::schema::SchemaId; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tempfile::TempDir; @@ -116,7 +116,7 @@ pub struct ConfigFile { #[serde(default = "default_http_port")] pub http_port: u16, - /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. #[serde(default)] pub transport: Transport, @@ -124,6 +124,15 @@ pub struct ConfigFile { #[serde(default = "default_node_port")] pub node_port: u16, + /// Pre-shared key formatted as a 64 digit hexadecimal string. + /// + /// When provided a private network will be made with only peers knowing the psk being able + /// to form connections. + /// + /// WARNING: Private networks are only supported when using TCP for the transport layer. + #[serde(default)] + pub psk: Option, + /// Path to folder where blobs (large binary files) are persisted. Defaults to a temporary /// directory. /// @@ -219,6 +228,7 @@ impl Default for ConfigFile { fn default() -> Self { Self { transport: Transport::default(), + psk: None, log_level: default_log_level(), allow_schema_ids: UncheckedAllowList::default(), database_url: default_database_url(), @@ -298,6 +308,14 @@ impl TryFrom for Configuration { .map(From::from) .collect(); + // `PreSharedKey` expects to parse key string from a multi-line string in the following format. + let psk = if let Some(psk) = value.psk { + let formatted_psk = format!("/key/swarm/psk/1.0.0/\n/base16/\n{}", psk); + Some(PreSharedKey::from_str(&formatted_psk)?) + } else { + None + }; + Ok(Configuration { allow_schema_ids, database_url: value.database_url, @@ -307,6 +325,7 @@ impl TryFrom for Configuration { worker_pool_size: value.worker_pool_size, network: NetworkConfiguration { transport: value.transport, + psk, port: value.node_port, mdns: value.mdns, direct_node_addresses, diff --git a/aquadoggo/src/network/config.rs b/aquadoggo/src/network/config.rs index c7a8fe75a..73cda7f0a 100644 --- a/aquadoggo/src/network/config.rs +++ b/aquadoggo/src/network/config.rs @@ -21,7 +21,12 @@ pub struct NetworkConfiguration { /// protocol (TCP/QUIC) used for node-node communication and data replication. pub transport: Transport, - /// Establish a private net secured by this pre-shared key. + /// Pre-shared key formatted as a 64 digit hexadecimal string. + /// + /// When provided a private network will be made with only peers knowing the psk being able + /// to form connections. + /// + /// WARNING: Private networks are only supported when using TCP for the transport layer. pub psk: Option, /// QUIC or TCP port for node-node communication and data replication. diff --git a/aquadoggo/src/network/service.rs b/aquadoggo/src/network/service.rs index b664001d4..67d505a44 100644 --- a/aquadoggo/src/network/service.rs +++ b/aquadoggo/src/network/service.rs @@ -47,12 +47,17 @@ pub async fn network_service( tx: ServiceSender, tx_ready: ServiceReadySender, ) -> Result<()> { - let network_config = context.config.network.clone(); + let mut network_config = context.config.network.clone(); let key_pair = identity::to_libp2p_key_pair(&context.key_pair); let local_peer_id = key_pair.public().to_peer_id(); info_or_print(&format!("Peer id: {local_peer_id}")); + if network_config.psk.is_some() && network_config.transport == Transport::QUIC { + warn!("Private net not supported for QUIC transport protocol, switching to TCP"); + network_config.transport = Transport::TCP; + } + let mut swarm = match network_config.transport { Transport::QUIC => build_quic_swarm(&network_config, key_pair), Transport::TCP => build_tcp_swarm(&network_config, key_pair), diff --git a/aquadoggo_cli/src/config.rs b/aquadoggo_cli/src/config.rs index bd92c42ff..ab858e4bb 100644 --- a/aquadoggo_cli/src/config.rs +++ b/aquadoggo_cli/src/config.rs @@ -112,7 +112,7 @@ struct Cli { #[serde(skip_serializing_if = "Option::is_none")] http_port: Option, - /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. #[arg(short = 'q', long, value_name = "TRANSPORT")] #[serde(skip_serializing_if = "Option::is_none")] pub transport: Option, @@ -122,6 +122,16 @@ struct Cli { #[serde(skip_serializing_if = "Option::is_none")] node_port: Option, + /// Pre-shared key formatted as a 64 digit hexadecimal string. + /// + /// When provided a private network will be made with only peers knowing the psk being able + /// to form connections. + /// + /// WARNING: Private networks are only supported when using TCP for the transport layer. + #[arg(short = 'y', long, value_name = "PSK")] + #[serde(skip_serializing_if = "Option::is_none")] + pub psk: Option, + /// Path to folder where blobs (large binary files) are persisted. Defaults to a temporary /// directory. /// @@ -381,12 +391,19 @@ pub fn print_config( "disabled" }; + let pnet = if config.network.psk.is_some() { + "enabled" + } else { + "disabled" + }; + format!( r"Allow schema IDs: {} Database URL: {} mDNS: {} Private key: {} Relay mode: {} +Private Net: {} Node is ready! ", @@ -395,5 +412,6 @@ Node is ready! mdns.blue(), private_key.blue(), relay_mode.blue(), + pnet.blue() ) } diff --git a/aquadoggo_cli/src/main.rs b/aquadoggo_cli/src/main.rs index 7bd87b836..cc69b1164 100644 --- a/aquadoggo_cli/src/main.rs +++ b/aquadoggo_cli/src/main.rs @@ -8,7 +8,7 @@ use std::convert::TryInto; use std::str::FromStr; use anyhow::Context; -use aquadoggo::{AllowList, Configuration, Node}; +use aquadoggo::{AllowList, Configuration, Node, Transport}; use env_logger::WriteStyle; use log::{warn, LevelFilter}; @@ -73,6 +73,13 @@ async fn main() -> anyhow::Result<()> { /// Show some hopefully helpful warnings around common configuration issues. fn show_warnings(config: &Configuration, is_temporary_blobs_path: bool) { + if config.network.psk.is_some() && config.network.transport == Transport::QUIC { + warn!( + "Your node is configured with a pre-shared key and uses QUIC transport. Private + nets are not supported when using QUIC therefore TCP will be enforced. " + ); + } + match &config.allow_schema_ids { AllowList::Set(values) => { if values.is_empty() && !config.network.relay_mode { From cb859fe1facc3a5987685230edd42144e34d273a Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 08:21:08 +0100 Subject: [PATCH 06/11] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f56c00f9..41b0bcaed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Support private network secured by pre-shared key [#635](https://github.com/p2panda/aquadoggo/pull/635) + ### Changed - Update `libp2p` to version `0.53.2` and apply API changes [#631](https://github.com/p2panda/aquadoggo/pull/631) From 2869e7129754b61fc07675d46c5eebed11540541 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 08:42:16 +0100 Subject: [PATCH 07/11] Doc string fix --- aquadoggo/src/api/config_file.rs | 2 +- aquadoggo/src/network/config.rs | 2 +- aquadoggo_cli/src/config.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aquadoggo/src/api/config_file.rs b/aquadoggo/src/api/config_file.rs index 3053da776..b283849f6 100644 --- a/aquadoggo/src/api/config_file.rs +++ b/aquadoggo/src/api/config_file.rs @@ -116,7 +116,7 @@ pub struct ConfigFile { #[serde(default = "default_http_port")] pub http_port: u16, - /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + /// Protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. #[serde(default)] pub transport: Transport, diff --git a/aquadoggo/src/network/config.rs b/aquadoggo/src/network/config.rs index 73cda7f0a..eb419817e 100644 --- a/aquadoggo/src/network/config.rs +++ b/aquadoggo/src/network/config.rs @@ -18,7 +18,7 @@ pub const NODE_NAMESPACE: &str = "aquadoggo"; /// Network config for the node. #[derive(Debug, Clone)] pub struct NetworkConfiguration { - /// protocol (TCP/QUIC) used for node-node communication and data replication. + /// Protocol (TCP/QUIC) used for node-node communication and data replication. pub transport: Transport, /// Pre-shared key formatted as a 64 digit hexadecimal string. diff --git a/aquadoggo_cli/src/config.rs b/aquadoggo_cli/src/config.rs index ab858e4bb..698d1cd41 100644 --- a/aquadoggo_cli/src/config.rs +++ b/aquadoggo_cli/src/config.rs @@ -112,7 +112,7 @@ struct Cli { #[serde(skip_serializing_if = "Option::is_none")] http_port: Option, - /// protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. + /// Protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC. #[arg(short = 'q', long, value_name = "TRANSPORT")] #[serde(skip_serializing_if = "Option::is_none")] pub transport: Option, From 9bb5a0074bc0e88d9e8df62ac18d0b8f4a54f243 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 08:44:02 +0100 Subject: [PATCH 08/11] Don't need to differentiate between transports when detecting port --- aquadoggo/src/network/service.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/aquadoggo/src/network/service.rs b/aquadoggo/src/network/service.rs index 67d505a44..41840d899 100644 --- a/aquadoggo/src/network/service.rs +++ b/aquadoggo/src/network/service.rs @@ -147,11 +147,8 @@ struct EventLoop { /// Shutdown handler. shutdown_handler: ShutdownHandler, - /// Did we learn our own QUIC port yet. - learned_quic_port: bool, - - /// Did we learn our own TCP port yet. - learned_tcp_port: bool, + /// Did we learn our own port yet. + learned_port: bool, /// Did we learn our observed address yet. learned_observed_addr: bool, @@ -175,8 +172,7 @@ impl EventLoop { known_peers: HashMap::new(), relays: HashMap::new(), shutdown_handler, - learned_quic_port: false, - learned_tcp_port: false, + learned_port: false, learned_observed_addr: false, } } @@ -208,21 +204,21 @@ impl EventLoop { let event = event.expect("Swarm stream to be infinite"); match event { SwarmEvent::NewListenAddr { address, .. } => { - if !self.learned_quic_port { + if !self.learned_port { // Show only one QUIC address during the runtime of the node, otherwise // it might get too spammy if let Some(address) = utils::to_quic_address(&address) { info_or_print(&format!("Node is listening on 0.0.0.0:{} (QUIC)", address.port())); - self.learned_quic_port = true; + self.learned_port = true; } } - if !self.learned_tcp_port { + if !self.learned_port { // Show only one TCP address during the runtime of the node, otherwise // it might get too spammy if let Some(address) = utils::to_tcp_address(&address) { info_or_print(&format!("Node is listening on 0.0.0.0:{} (TCP)", address.port())); - self.learned_tcp_port = true; + self.learned_port = true; } } } From 36348082a88808a31486a6996218915a07fdf348 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 09:05:57 +0100 Subject: [PATCH 09/11] Update README --- aquadoggo_cli/README.md | 136 +++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 80 deletions(-) diff --git a/aquadoggo_cli/README.md b/aquadoggo_cli/README.md index 0070d925f..ba23b5d28 100644 --- a/aquadoggo_cli/README.md +++ b/aquadoggo_cli/README.md @@ -170,6 +170,19 @@ database_url = "sqlite:$HOME/.local/share/aquadoggo/db.sqlite3" blobs_base_path = "$HOME/.local/share/aquadoggo/blobs" ``` +#### Private Network + +> "I want only peers who know a pre-shared key to be able to join my network." + +```sh +# Generate a 64 digit hexadecimal string, for example on the command line like this +hexdump -vn64 -e'"%x"' /dev/urandom +# => + +# Pass the pre-shared key to your node via environment variables or config file +PSK= aquadoggo +``` + ### Configuration Check out the [`config.toml`] file for all configurations and documentation or @@ -184,64 +197,53 @@ Options: -c, --config Path to an optional "config.toml" file for further configuration. - When not set the program will try to find a `config.toml` file in the - same folder the program is executed in and otherwise in the regarding - operation systems XDG config directory - ("$HOME/.config/aquadoggo/config.toml" on Linux). + When not set the program will try to find a `config.toml` file in the same folder the program is executed in and otherwise in the regarding operation systems XDG config directory ("$HOME/.config/aquadoggo/config.toml" on Linux). + + [env: CONFIG=] -s, --allow-schema-ids [...] - List of schema ids which a node will replicate, persist and expose on - the GraphQL API. Separate multiple values with a whitespace. Defaults - to allow _any_ schemas ("*"). + List of schema ids which a node will replicate, persist and expose on the GraphQL API. Separate multiple values with a whitespace. Defaults to allow _any_ schemas ("*"). - When allowing a schema you automatically opt into announcing, - replicating and materializing documents connected to it, supporting - applications and networks which are dependent on this data. + When allowing a schema you automatically opt into announcing, replicating and materializing documents connected to it, supporting applications and networks which are dependent on this data. - It is recommended to set this list to all schema ids your own - application should support, including all important system schemas. + It is recommended to set this list to all schema ids your own application should support, including all important system schemas. - WARNING: When set to wildcard "*", your node will support _any_ - schemas it will encounter on the network. This is useful for - experimentation and local development but _not_ recommended for - production settings. + WARNING: When set to wildcard "*", your node will support _any_ schemas it will encounter on the network. This is useful for experimentation and local development but _not_ recommended for production settings. -d, --database-url - URL / connection string to PostgreSQL or SQLite database. Defaults to - an in-memory SQLite database. + URL / connection string to PostgreSQL or SQLite database. Defaults to an in-memory SQLite database. - WARNING: By default your node will not persist anything after - shutdown. Set a database connection url for production settings to - not loose data. + WARNING: By default your node will not persist anything after shutdown. Set a database connection url for production settings to not loose data. -p, --http-port - HTTP port for client-node communication, serving the GraphQL API. - Defaults to 2020 + HTTP port for client-node communication, serving the GraphQL API. Defaults to 2020 + + -q, --transport + Protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC + + -t, --node-port + QUIC port for node-node communication and data replication. Defaults to 2022 + + -y, --psk + Pre-shared key formatted as a 64 digit hexadecimal string. + + When provided a private network will be made with only peers knowing the psk being able to form connections. - -q, --quic-port - QUIC port for node-node communication and data replication. Defaults - to 2022 + WARNING: Private networks are only supported when using TCP for the transport layer. -f, --blobs-base-path - Path to folder where blobs (large binary files) are persisted. - Defaults to a temporary directory. + Path to folder where blobs (large binary files) are persisted. Defaults to a temporary directory. - WARNING: By default your node will not persist any blobs after - shutdown. Set a path for production settings to not loose data. + WARNING: By default your node will not persist any blobs after shutdown. Set a path for production settings to not loose data. -k, --private-key - Path to persist your ed25519 private key file. Defaults to an - ephemeral key only for this current session. + Path to persist your ed25519 private key file. Defaults to an ephemeral key only for this current session. - The key is used to identify you towards other nodes during network - discovery and replication. This key is _not_ used to create and sign - data. + The key is used to identify you towards other nodes during network discovery and replication. This key is _not_ used to create and sign data. - If a path is set, a key will be generated newly and stored under this - path when node starts for the first time. + If a path is set, a key will be generated newly and stored under this path when node starts for the first time. - When no path is set, your node will generate an ephemeral private key - on every start up and _not_ persist it. + When no path is set, your node will generate an ephemeral private key on every start up and _not_ persist it. -m, --mdns [] mDNS to discover other peers on the local network. Enabled by default @@ -251,74 +253,48 @@ Options: -n, --direct-node-addresses [...] List of known node addresses we want to connect to directly. - Make sure that nodes mentioned in this list are directly reachable - (they need to be hosted with a static IP Address). If you need to - connect to nodes with changing, dynamic IP addresses or even with - nodes behind a firewall or NAT, do not use this field but use at - least one relay. + Make sure that nodes mentioned in this list are directly reachable (they need to be hosted with a static IP Address). If you need to connect to nodes with changing, dynamic IP addresses or even with nodes behind a firewall or NAT, do not use this field but use at least one relay. -a, --allow-peer-ids [...] List of peers which are allowed to connect to your node. - If set then only nodes (identified by their peer id) contained in - this list will be able to connect to your node (via a relay or - directly). When not set any other node can connect to yours. + If set then only nodes (identified by their peer id) contained in this list will be able to connect to your node (via a relay or directly). When not set any other node can connect to yours. - Peer IDs identify nodes by using their hashed public keys. They do - _not_ represent authored data from clients and are only used to - authenticate nodes towards each other during networking. + Peer IDs identify nodes by using their hashed public keys. They do _not_ represent authored data from clients and are only used to authenticate nodes towards each other during networking. - Use this list for example for setups where the identifier of the - nodes you want to form a network with is known but you still need to - use relays as their IP addresses change dynamically. + Use this list for example for setups where the identifier of the nodes you want to form a network with is known but you still need to use relays as their IP addresses change dynamically. -b, --block-peer-ids [...] List of peers which will be blocked from connecting to your node. - If set then any peers (identified by their peer id) contained in this - list will be blocked from connecting to your node (via a relay or - directly). When an empty list is provided then there are no - restrictions on which nodes can connect to yours. + If set then any peers (identified by their peer id) contained in this list will be blocked from connecting to your node (via a relay or directly). When an empty list is provided then there are no restrictions on which nodes can connect to yours. - Block lists and allow lists are exclusive, which means that you - should _either_ use a block list _or_ an allow list depending on your - setup. + Block lists and allow lists are exclusive, which means that you should _either_ use a block list _or_ an allow list depending on your setup. - Use this list for example if you want to allow _any_ node to connect - to yours _except_ of a known number of excluded nodes. + Use this list for example if you want to allow _any_ node to connect to yours _except_ of a known number of excluded nodes. -r, --relay-addresses [...] List of relay addresses. - A relay helps discover other nodes on the internet (also known as - "rendesvouz" or "bootstrap" server) and helps establishing direct p2p - connections when node is behind a firewall or NAT (also known as - "holepunching"). + A relay helps discover other nodes on the internet (also known as "rendesvouz" or "bootstrap" server) and helps establishing direct p2p connections when node is behind a firewall or NAT (also known as "holepunching"). - WARNING: This will potentially expose your IP address on the network. - Do only connect to trusted relays or make sure your IP address is - hidden via a VPN or proxy if you're concerned about leaking your IP. + WARNING: This will potentially expose your IP address on the network. Do only connect to trusted relays or make sure your IP address is hidden via a VPN or proxy if you're concerned about leaking your IP. -e, --relay-mode [] Enable if node should also function as a relay. Disabled by default. Other nodes can use relays to aid discovery and establishing connectivity. - Relays _need_ to be hosted in a way where they can be reached - directly, for example with a static IP address through an VPS. + Relays _need_ to be hosted in a way where they can be reached directly, for example with a static IP address through an VPS. [possible values: true, false] -l, --log-level - Set log verbosity. Use this for learning more about how your node - behaves or for debugging. + Set log verbosity. Use this for learning more about how your node behaves or for debugging. - Possible log levels are: ERROR, WARN, INFO, DEBUG, TRACE. They are - scoped to "aquadoggo" by default. + Possible log levels are: ERROR, WARN, INFO, DEBUG, TRACE. They are scoped to "aquadoggo" by default. - If you want to adjust the scope for deeper inspection use a filter - value, for example "=TRACE" for logging _everything_ or - "aquadoggo=INFO,libp2p=DEBUG" etc. + If you want to adjust the scope for deeper inspection use a filter value, for example "=TRACE" for logging _everything_ or "aquadoggo=INFO,libp2p=DEBUG" etc. -h, --help Print help (see a summary with '-h') @@ -350,9 +326,9 @@ GNU Affero General Public License v3.0 [`AGPL-3.0-or-later`](LICENSE)
-*This project has received funding from the European Union’s Horizon 2020 +_This project has received funding from the European Union’s Horizon 2020 research and innovation programme within the framework of the NGI-POINTER -Project funded under grant agreement No 871528 and NGI-ASSURE No 957073* +Project funded under grant agreement No 871528 and NGI-ASSURE No 957073_ [`config.toml`]: config.toml [`p2panda`]: https://p2panda.org From 8273f7ff0e47d6e49aa82f18853c392a1c74bae6 Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 09:08:52 +0100 Subject: [PATCH 10/11] Fix README formatting --- aquadoggo_cli/README.md | 127 ++++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 37 deletions(-) diff --git a/aquadoggo_cli/README.md b/aquadoggo_cli/README.md index ba23b5d28..9a94b0085 100644 --- a/aquadoggo_cli/README.md +++ b/aquadoggo_cli/README.md @@ -172,7 +172,7 @@ blobs_base_path = "$HOME/.local/share/aquadoggo/blobs" #### Private Network -> "I want only peers who know a pre-shared key to be able to join my network." +> "I want only peers who know a pre-shared key to be able to join my network." ```sh # Generate a 64 digit hexadecimal string, for example on the command line like this @@ -183,6 +183,8 @@ hexdump -vn64 -e'"%x"' /dev/urandom PSK= aquadoggo ``` + + ### Configuration Check out the [`config.toml`] file for all configurations and documentation or @@ -197,53 +199,78 @@ Options: -c, --config Path to an optional "config.toml" file for further configuration. - When not set the program will try to find a `config.toml` file in the same folder the program is executed in and otherwise in the regarding operation systems XDG config directory ("$HOME/.config/aquadoggo/config.toml" on Linux). - - [env: CONFIG=] + When not set the program will try to find a `config.toml` file in the + same folder the program is executed in and otherwise in the regarding + operation systems XDG config directory + ("$HOME/.config/aquadoggo/config.toml" on Linux). -s, --allow-schema-ids [...] - List of schema ids which a node will replicate, persist and expose on the GraphQL API. Separate multiple values with a whitespace. Defaults to allow _any_ schemas ("*"). + List of schema ids which a node will replicate, persist and expose on + the GraphQL API. Separate multiple values with a whitespace. Defaults + to allow _any_ schemas ("*"). - When allowing a schema you automatically opt into announcing, replicating and materializing documents connected to it, supporting applications and networks which are dependent on this data. + When allowing a schema you automatically opt into announcing, + replicating and materializing documents connected to it, supporting + applications and networks which are dependent on this data. - It is recommended to set this list to all schema ids your own application should support, including all important system schemas. + It is recommended to set this list to all schema ids your own + application should support, including all important system schemas. - WARNING: When set to wildcard "*", your node will support _any_ schemas it will encounter on the network. This is useful for experimentation and local development but _not_ recommended for production settings. + WARNING: When set to wildcard "*", your node will support _any_ + schemas it will encounter on the network. This is useful for + experimentation and local development but _not_ recommended for + production settings. -d, --database-url - URL / connection string to PostgreSQL or SQLite database. Defaults to an in-memory SQLite database. + URL / connection string to PostgreSQL or SQLite database. Defaults to + an in-memory SQLite database. - WARNING: By default your node will not persist anything after shutdown. Set a database connection url for production settings to not loose data. + WARNING: By default your node will not persist anything after + shutdown. Set a database connection url for production settings to + not loose data. -p, --http-port - HTTP port for client-node communication, serving the GraphQL API. Defaults to 2020 + HTTP port for client-node communication, serving the GraphQL API. + Defaults to 2020 -q, --transport - Protocol (TCP/QUIC) used for node-node communication and data replication. Defaults to QUIC + Protocol (TCP/QUIC) used for node-node communication and data + replication. Defaults to QUIC -t, --node-port - QUIC port for node-node communication and data replication. Defaults to 2022 + QUIC port for node-node communication and data replication. Defaults + to 2022 -y, --psk Pre-shared key formatted as a 64 digit hexadecimal string. + + When provided a private network will be made with only peers knowing + the psk being able to form connections. + + WARNING: Private networks are only supported when using TCP for the + transport layer. - When provided a private network will be made with only peers knowing the psk being able to form connections. - - WARNING: Private networks are only supported when using TCP for the transport layer. -f, --blobs-base-path - Path to folder where blobs (large binary files) are persisted. Defaults to a temporary directory. + Path to folder where blobs (large binary files) are persisted. + Defaults to a temporary directory. - WARNING: By default your node will not persist any blobs after shutdown. Set a path for production settings to not loose data. + WARNING: By default your node will not persist any blobs after + shutdown. Set a path for production settings to not loose data. -k, --private-key - Path to persist your ed25519 private key file. Defaults to an ephemeral key only for this current session. + Path to persist your ed25519 private key file. Defaults to an + ephemeral key only for this current session. - The key is used to identify you towards other nodes during network discovery and replication. This key is _not_ used to create and sign data. + The key is used to identify you towards other nodes during network + discovery and replication. This key is _not_ used to create and sign + data. - If a path is set, a key will be generated newly and stored under this path when node starts for the first time. + If a path is set, a key will be generated newly and stored under this + path when node starts for the first time. - When no path is set, your node will generate an ephemeral private key on every start up and _not_ persist it. + When no path is set, your node will generate an ephemeral private key + on every start up and _not_ persist it. -m, --mdns [] mDNS to discover other peers on the local network. Enabled by default @@ -253,48 +280,74 @@ Options: -n, --direct-node-addresses [...] List of known node addresses we want to connect to directly. - Make sure that nodes mentioned in this list are directly reachable (they need to be hosted with a static IP Address). If you need to connect to nodes with changing, dynamic IP addresses or even with nodes behind a firewall or NAT, do not use this field but use at least one relay. + Make sure that nodes mentioned in this list are directly reachable + (they need to be hosted with a static IP Address). If you need to + connect to nodes with changing, dynamic IP addresses or even with + nodes behind a firewall or NAT, do not use this field but use at + least one relay. -a, --allow-peer-ids [...] List of peers which are allowed to connect to your node. - If set then only nodes (identified by their peer id) contained in this list will be able to connect to your node (via a relay or directly). When not set any other node can connect to yours. + If set then only nodes (identified by their peer id) contained in + this list will be able to connect to your node (via a relay or + directly). When not set any other node can connect to yours. - Peer IDs identify nodes by using their hashed public keys. They do _not_ represent authored data from clients and are only used to authenticate nodes towards each other during networking. + Peer IDs identify nodes by using their hashed public keys. They do + _not_ represent authored data from clients and are only used to + authenticate nodes towards each other during networking. - Use this list for example for setups where the identifier of the nodes you want to form a network with is known but you still need to use relays as their IP addresses change dynamically. + Use this list for example for setups where the identifier of the + nodes you want to form a network with is known but you still need to + use relays as their IP addresses change dynamically. -b, --block-peer-ids [...] List of peers which will be blocked from connecting to your node. - If set then any peers (identified by their peer id) contained in this list will be blocked from connecting to your node (via a relay or directly). When an empty list is provided then there are no restrictions on which nodes can connect to yours. + If set then any peers (identified by their peer id) contained in this + list will be blocked from connecting to your node (via a relay or + directly). When an empty list is provided then there are no + restrictions on which nodes can connect to yours. - Block lists and allow lists are exclusive, which means that you should _either_ use a block list _or_ an allow list depending on your setup. + Block lists and allow lists are exclusive, which means that you + should _either_ use a block list _or_ an allow list depending on your + setup. - Use this list for example if you want to allow _any_ node to connect to yours _except_ of a known number of excluded nodes. + Use this list for example if you want to allow _any_ node to connect + to yours _except_ of a known number of excluded nodes. -r, --relay-addresses [...] List of relay addresses. - A relay helps discover other nodes on the internet (also known as "rendesvouz" or "bootstrap" server) and helps establishing direct p2p connections when node is behind a firewall or NAT (also known as "holepunching"). + A relay helps discover other nodes on the internet (also known as + "rendesvouz" or "bootstrap" server) and helps establishing direct p2p + connections when node is behind a firewall or NAT (also known as + "holepunching"). - WARNING: This will potentially expose your IP address on the network. Do only connect to trusted relays or make sure your IP address is hidden via a VPN or proxy if you're concerned about leaking your IP. + WARNING: This will potentially expose your IP address on the network. + Do only connect to trusted relays or make sure your IP address is + hidden via a VPN or proxy if you're concerned about leaking your IP. -e, --relay-mode [] Enable if node should also function as a relay. Disabled by default. Other nodes can use relays to aid discovery and establishing connectivity. - Relays _need_ to be hosted in a way where they can be reached directly, for example with a static IP address through an VPS. + Relays _need_ to be hosted in a way where they can be reached + directly, for example with a static IP address through an VPS. [possible values: true, false] -l, --log-level - Set log verbosity. Use this for learning more about how your node behaves or for debugging. + Set log verbosity. Use this for learning more about how your node + behaves or for debugging. - Possible log levels are: ERROR, WARN, INFO, DEBUG, TRACE. They are scoped to "aquadoggo" by default. + Possible log levels are: ERROR, WARN, INFO, DEBUG, TRACE. They are + scoped to "aquadoggo" by default. - If you want to adjust the scope for deeper inspection use a filter value, for example "=TRACE" for logging _everything_ or "aquadoggo=INFO,libp2p=DEBUG" etc. + If you want to adjust the scope for deeper inspection use a filter + value, for example "=TRACE" for logging _everything_ or + "aquadoggo=INFO,libp2p=DEBUG" etc. -h, --help Print help (see a summary with '-h') @@ -326,9 +379,9 @@ GNU Affero General Public License v3.0 [`AGPL-3.0-or-later`](LICENSE)
-_This project has received funding from the European Union’s Horizon 2020 +*This project has received funding from the European Union’s Horizon 2020 research and innovation programme within the framework of the NGI-POINTER -Project funded under grant agreement No 871528 and NGI-ASSURE No 957073_ +Project funded under grant agreement No 871528 and NGI-ASSURE No 957073* [`config.toml`]: config.toml [`p2panda`]: https://p2panda.org From ebf263b3f9ba281543025d2d7a63b188119786ab Mon Sep 17 00:00:00 2001 From: Sam Andreae Date: Wed, 26 Jun 2024 09:11:36 +0100 Subject: [PATCH 11/11] Update example config file --- aquadoggo_cli/config.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aquadoggo_cli/config.toml b/aquadoggo_cli/config.toml index 9775a43af..d96a68ac4 100644 --- a/aquadoggo_cli/config.toml +++ b/aquadoggo_cli/config.toml @@ -92,11 +92,11 @@ database_max_connections = 32 # http_port = 2020 -# QUIC port for node-node communication and data replication. Defaults to 2022. +# Port for node-node communication and data replication. Defaults to 2022. # # When port is taken the node will automatically pick a random, free port. # -quic_port = 2022 +node_port = 2022 # ゚・。+☆ # BLOBS