From 31fbdb55d0d9435ed64c86f2aef0067e568af1a0 Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Mon, 9 Dec 2024 20:20:44 +0530 Subject: [PATCH] feat!: use a simple network id to differentiate between network --- Cargo.lock | 1 + ant-bootstrap/src/config.rs | 4 +- ant-cli/Cargo.toml | 1 + ant-cli/src/main.rs | 3 + ant-cli/src/opt.rs | 6 ++ ant-networking/src/driver.rs | 54 ++++++++----- ant-networking/src/event/swarm.rs | 11 ++- ant-node/src/bin/antnode/main.rs | 21 ++++- ant-protocol/src/version.rs | 130 ++++++++++++++++++++---------- autonomi/src/client/mod.rs | 2 +- 10 files changed, 160 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 999850c2d5..a4541780b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -763,6 +763,7 @@ dependencies = [ "ant-bootstrap", "ant-build-info", "ant-logging", + "ant-protocol", "autonomi", "clap", "color-eyre", diff --git a/ant-bootstrap/src/config.rs b/ant-bootstrap/src/config.rs index 52d85b7dee..252f107bb3 100644 --- a/ant-bootstrap/src/config.rs +++ b/ant-bootstrap/src/config.rs @@ -7,7 +7,7 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::error::{Error, Result}; -use ant_protocol::version::{get_key_version_str, get_truncate_version_str}; +use ant_protocol::version::{get_network_id, get_truncate_version_str}; use std::{ path::{Path, PathBuf}, time::Duration, @@ -118,7 +118,7 @@ fn default_cache_path() -> Result { std::fs::create_dir_all(&dir)?; - let network_id = format!("{}_{}", get_key_version_str(), get_truncate_version_str()); + let network_id = format!("{}_{}", get_network_id(), get_truncate_version_str()); let path = dir.join(format!("bootstrap_cache_{}.json", network_id)); Ok(path) diff --git a/ant-cli/Cargo.toml b/ant-cli/Cargo.toml index 40fa0f182b..77c9343190 100644 --- a/ant-cli/Cargo.toml +++ b/ant-cli/Cargo.toml @@ -27,6 +27,7 @@ harness = false ant-bootstrap = { path = "../ant-bootstrap", version = "0.1.0" } ant-build-info = { path = "../ant-build-info", version = "0.1.19" } ant-logging = { path = "../ant-logging", version = "0.2.40" } +ant-protocol = { path = "../ant-protocol", version = "0.17.15" } autonomi = { path = "../autonomi", version = "0.2.4", features = [ "fs", "vault", diff --git a/ant-cli/src/main.rs b/ant-cli/src/main.rs index b50092e538..c0404e9f75 100644 --- a/ant-cli/src/main.rs +++ b/ant-cli/src/main.rs @@ -34,6 +34,9 @@ use tracing::Level; async fn main() -> Result<()> { color_eyre::install().expect("Failed to initialise error handler"); let opt = Opt::parse(); + if let Some(network_id) = opt.network_id { + ant_protocol::version::set_network_id(network_id); + } let _log_guards = init_logging_and_metrics(&opt)?; #[cfg(feature = "metrics")] tokio::spawn(init_metrics(std::process::id())); diff --git a/ant-cli/src/opt.rs b/ant-cli/src/opt.rs index 3e84379fc0..3ffa1eb5f6 100644 --- a/ant-cli/src/opt.rs +++ b/ant-cli/src/opt.rs @@ -51,6 +51,12 @@ pub(crate) struct Opt { #[clap(long = "timeout", global = true, value_parser = |t: &str| -> Result { Ok(t.parse().map(Duration::from_secs)?) })] pub connection_timeout: Option, + /// Specify the network ID to use. This will allow you to run the CLI on a different network. + /// + /// By default, the network ID is set to 1, which represents the mainnet. + #[clap(long, verbatim_doc_comment)] + pub network_id: Option, + /// Prevent verification of data storage on the network. /// /// This may increase operation speed, but offers no guarantees that operations were successful. diff --git a/ant-networking/src/driver.rs b/ant-networking/src/driver.rs index 59a6c353ff..eb34b13e2a 100644 --- a/ant-networking/src/driver.rs +++ b/ant-networking/src/driver.rs @@ -35,7 +35,7 @@ use ant_protocol::{ messages::{ChunkProof, Nonce, Request, Response}, storage::{try_deserialize_record, RetryStrategy}, version::{ - get_key_version_str, IDENTIFY_CLIENT_VERSION_STR, IDENTIFY_NODE_VERSION_STR, + get_network_id, IDENTIFY_CLIENT_VERSION_STR, IDENTIFY_NODE_VERSION_STR, IDENTIFY_PROTOCOL_STR, REQ_RESPONSE_VERSION_STR, }, NetworkAddress, PrettyPrintKBucketKey, PrettyPrintRecordKey, @@ -267,16 +267,16 @@ pub(super) struct NodeBehaviour { #[derive(Debug)] pub struct NetworkBuilder { bootstrap_cache: Option, + concurrency_limit: Option, is_behind_home_network: bool, keypair: Keypair, - local: bool, listen_addr: Option, - request_timeout: Option, - concurrency_limit: Option, + local: bool, #[cfg(feature = "open-metrics")] metrics_registries: Option, #[cfg(feature = "open-metrics")] metrics_server_port: Option, + request_timeout: Option, #[cfg(feature = "upnp")] upnp: bool, } @@ -285,16 +285,16 @@ impl NetworkBuilder { pub fn new(keypair: Keypair, local: bool) -> Self { Self { bootstrap_cache: None, + concurrency_limit: None, is_behind_home_network: false, keypair, - local, listen_addr: None, - request_timeout: None, - concurrency_limit: None, + local, #[cfg(feature = "open-metrics")] metrics_registries: None, #[cfg(feature = "open-metrics")] metrics_server_port: None, + request_timeout: None, #[cfg(feature = "upnp")] upnp: false, } @@ -394,7 +394,7 @@ impl NetworkBuilder { check_and_wipe_storage_dir_if_necessary( root_dir.clone(), storage_dir_path.clone(), - get_key_version_str(), + get_network_id(), )?; // Configures the disk_store to store records under the provided path and increase the max record size @@ -431,7 +431,6 @@ impl NetworkBuilder { Some(store_cfg), false, ProtocolSupport::Full, - IDENTIFY_NODE_VERSION_STR.to_string(), #[cfg(feature = "upnp")] upnp, )?; @@ -482,7 +481,6 @@ impl NetworkBuilder { None, true, ProtocolSupport::Outbound, - IDENTIFY_CLIENT_VERSION_STR.to_string(), #[cfg(feature = "upnp")] false, )?; @@ -497,9 +495,13 @@ impl NetworkBuilder { record_store_cfg: Option, is_client: bool, req_res_protocol: ProtocolSupport, - identify_version: String, #[cfg(feature = "upnp")] upnp: bool, ) -> Result<(Network, mpsc::Receiver, SwarmDriver)> { + let identify_protocol_str = IDENTIFY_PROTOCOL_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_PROTOCOL_STR") + .clone(); + let peer_id = PeerId::from(self.keypair.public()); // vdash metric (if modified please notify at https://github.com/happybeing/vdash/issues): #[cfg(not(target_arch = "wasm32"))] @@ -563,7 +565,7 @@ impl NetworkBuilder { "The protocol version string that is used to connect to the correct network", Info::new(vec![( "identify_protocol_str".to_string(), - IDENTIFY_PROTOCOL_STR.to_string(), + identify_protocol_str.clone(), )]), ); @@ -577,14 +579,16 @@ impl NetworkBuilder { let request_response = { let cfg = RequestResponseConfig::default() .with_request_timeout(self.request_timeout.unwrap_or(REQUEST_TIMEOUT_DEFAULT_S)); + let req_res_version_str = REQ_RESPONSE_VERSION_STR + .read() + .expect("Failed to obtain read lock for REQ_RESPONSE_VERSION_STR") + .clone(); - info!( - "Building request response with {:?}", - REQ_RESPONSE_VERSION_STR.as_str() - ); + info!("Building request response with {req_res_version_str:?}",); request_response::cbor::Behaviour::new( [( - StreamProtocol::new(&REQ_RESPONSE_VERSION_STR), + StreamProtocol::try_from_owned(req_res_version_str) + .expect("StreamProtocol should start with a /"), req_res_protocol, )], cfg, @@ -640,12 +644,22 @@ impl NetworkBuilder { #[cfg(feature = "local")] let mdns = mdns::tokio::Behaviour::new(mdns_config, peer_id)?; + let agent_version = if is_client { + IDENTIFY_CLIENT_VERSION_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_CLIENT_VERSION_STR") + .clone() + } else { + IDENTIFY_NODE_VERSION_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_NODE_VERSION_STR") + .clone() + }; // Identify Behaviour - let identify_protocol_str = IDENTIFY_PROTOCOL_STR.to_string(); - info!("Building Identify with identify_protocol_str: {identify_protocol_str:?} and identify_version: {identify_version:?}"); + info!("Building Identify with identify_protocol_str: {identify_protocol_str:?} and identify_protocol_str: {identify_protocol_str:?}"); let identify = { let cfg = libp2p::identify::Config::new(identify_protocol_str, self.keypair.public()) - .with_agent_version(identify_version) + .with_agent_version(agent_version) // Enlength the identify interval from default 5 mins to 1 hour. .with_interval(RESEND_IDENTIFY_INVERVAL); libp2p::identify::Behaviour::new(cfg) diff --git a/ant-networking/src/event/swarm.rs b/ant-networking/src/event/swarm.rs index 84127c43d3..3bf65eb6d9 100644 --- a/ant-networking/src/event/swarm.rs +++ b/ant-networking/src/event/swarm.rs @@ -124,11 +124,13 @@ impl SwarmDriver { } => { debug!(conn_id=%connection_id, %peer_id, ?info, "identify: received info"); - if info.protocol_version != IDENTIFY_PROTOCOL_STR.to_string() { - warn!(?info.protocol_version, "identify: {peer_id:?} does not have the same protocol. Our IDENTIFY_PROTOCOL_STR: {:?}", IDENTIFY_PROTOCOL_STR.as_str()); + let our_identify_protocol = IDENTIFY_PROTOCOL_STR.read().expect("IDENTIFY_PROTOCOL_STR has been locked to write. A call to set_network_id performed. This should not happen.").to_string(); + + if info.protocol_version != our_identify_protocol { + warn!(?info.protocol_version, "identify: {peer_id:?} does not have the same protocol. Our IDENTIFY_PROTOCOL_STR: {our_identify_protocol:?}"); self.send_event(NetworkEvent::PeerWithUnsupportedProtocol { - our_protocol: IDENTIFY_PROTOCOL_STR.to_string(), + our_protocol: our_identify_protocol, their_protocol: info.protocol_version, }); // Block the peer from any further communication. @@ -143,8 +145,9 @@ impl SwarmDriver { return Ok(()); } + let our_agent_version = IDENTIFY_NODE_VERSION_STR.read().expect("IDENTIFY_NODE_VERSION_STR has been locked to write. A call to set_network_id performed. This should not happen.").to_string(); // if client, return. - if info.agent_version != IDENTIFY_NODE_VERSION_STR.to_string() { + if info.agent_version != our_agent_version { return Ok(()); } diff --git a/ant-node/src/bin/antnode/main.rs b/ant-node/src/bin/antnode/main.rs index 6246206211..ffa2a80c93 100644 --- a/ant-node/src/bin/antnode/main.rs +++ b/ant-node/src/bin/antnode/main.rs @@ -22,7 +22,7 @@ use ant_node::{Marker, NodeBuilder, NodeEvent, NodeEventsReceiver}; use ant_protocol::{ node::get_antnode_root_dir, node_rpc::{NodeCtrl, StopResult}, - version::IDENTIFY_PROTOCOL_STR, + version, }; use clap::{command, Parser}; use color_eyre::{eyre::eyre, Result}; @@ -128,6 +128,12 @@ struct Opt { #[clap(long, verbatim_doc_comment)] max_archived_log_files: Option, + /// Specify the network ID to use. This will allow you to run the node on a different network. + /// + /// By default, the network ID is set to 1, which represents the mainnet. + #[clap(long, verbatim_doc_comment)] + network_id: Option, + /// Specify the rewards address. /// The rewards address is the address that will receive the rewards for the node. /// It should be a valid EVM address. @@ -217,13 +223,20 @@ fn main() -> Result<()> { color_eyre::install()?; let opt = Opt::parse(); + if let Some(network_id) = opt.network_id { + version::set_network_id(network_id); + } + + let identify_protocol_str = version::IDENTIFY_PROTOCOL_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_PROTOCOL_STR"); if opt.version { println!( "{}", ant_build_info::version_string( "Autonomi Node", env!("CARGO_PKG_VERSION"), - Some(&IDENTIFY_PROTOCOL_STR) + Some(&identify_protocol_str) ) ); return Ok(()); @@ -240,7 +253,7 @@ fn main() -> Result<()> { } if opt.protocol_version { - println!("Network version: {}", *IDENTIFY_PROTOCOL_STR); + println!("Network version: {identify_protocol_str}"); return Ok(()); } @@ -279,7 +292,7 @@ fn main() -> Result<()> { ); info!("\n{}\n{}", msg, "=".repeat(msg.len())); - ant_build_info::log_version_info(env!("CARGO_PKG_VERSION"), &IDENTIFY_PROTOCOL_STR); + ant_build_info::log_version_info(env!("CARGO_PKG_VERSION"), &identify_protocol_str); debug!( "antnode built with git version: {}", ant_build_info::git_info() diff --git a/ant-protocol/src/version.rs b/ant-protocol/src/version.rs index 6606e74be0..3d5c92cfab 100644 --- a/ant-protocol/src/version.rs +++ b/ant-protocol/src/version.rs @@ -7,39 +7,83 @@ // permissions and limitations relating to use of the SAFE Network Software. use lazy_static::lazy_static; +use std::sync::RwLock; lazy_static! { + /// The network_id is used to differentiate between different networks. + /// The default is set to 1 and it represents the mainnet. + pub static ref NETWORK_ID: RwLock = RwLock::new(1); + /// The node version used during Identify Behaviour. - pub static ref IDENTIFY_NODE_VERSION_STR: String = - format!( - "safe/node/{}/{}", + pub static ref IDENTIFY_NODE_VERSION_STR: RwLock = + RwLock::new(format!( + "ant/node/{}/{}", get_truncate_version_str(), - get_key_version_str(), - ); + *NETWORK_ID.read().expect("Failed to obtain read lock for NETWORK_ID"), + )); /// The client version used during Identify Behaviour. - pub static ref IDENTIFY_CLIENT_VERSION_STR: String = - format!( - "safe/client/{}/{}", + pub static ref IDENTIFY_CLIENT_VERSION_STR: RwLock = + RwLock::new(format!( + "ant/client/{}/{}", get_truncate_version_str(), - get_key_version_str(), - ); + *NETWORK_ID.read().expect("Failed to obtain read lock for NETWORK_ID"), + )); /// The req/response protocol version - pub static ref REQ_RESPONSE_VERSION_STR: String = - format!( - "/safe/node/{}/{}", + pub static ref REQ_RESPONSE_VERSION_STR: RwLock = + RwLock::new(format!( + "/ant/{}/{}", get_truncate_version_str(), - get_key_version_str(), - ); + *NETWORK_ID.read().expect("Failed to obtain read lock for NETWORK_ID"), + )); /// The identify protocol version - pub static ref IDENTIFY_PROTOCOL_STR: String = - format!( - "safe/{}/{}", + pub static ref IDENTIFY_PROTOCOL_STR: RwLock = + RwLock::new(format!( + "ant/{}/{}", get_truncate_version_str(), - get_key_version_str(), - ); + *NETWORK_ID.read().expect("Failed to obtain read lock for NETWORK_ID"), + )); +} + +/// Update the NETWORK_ID and all the version strings that depend on it. +/// By default, the network id is set to 1 which represents the mainnet. +/// +/// This should be called before starting the node or client. +/// The values will be read often and this can cause issues if the values are changed after the node is started. +pub fn set_network_id(id: u8) { + let mut network_id = NETWORK_ID + .write() + .expect("Failed to obtain write lock for NETWORK_ID"); + *network_id = id; + + let mut node_version = IDENTIFY_NODE_VERSION_STR + .write() + .expect("Failed to obtain write lock for IDENTIFY_NODE_VERSION_STR"); + *node_version = format!("ant/node/{}/{}", get_truncate_version_str(), id); + let mut client_version = IDENTIFY_CLIENT_VERSION_STR + .write() + .expect("Failed to obtain write lock for IDENTIFY_CLIENT_VERSION_STR"); + *client_version = format!("ant/client/{}/{}", get_truncate_version_str(), id); + let mut req_response_version = REQ_RESPONSE_VERSION_STR + .write() + .expect("Failed to obtain write lock for REQ_RESPONSE_VERSION_STR"); + *req_response_version = format!("/ant/{}/{}", get_truncate_version_str(), id); + let mut identify_protocol = IDENTIFY_PROTOCOL_STR + .write() + .expect("Failed to obtain write lock for IDENTIFY_PROTOCOL_STR"); + *identify_protocol = format!("ant/{}/{}", get_truncate_version_str(), id); +} + +/// Get the current NETWORK_ID as string. +pub fn get_network_id() -> String { + format!( + "{}", + *NETWORK_ID + .read() + .expect("Failed to obtain read lock for NETWORK_ID") + ) } // Protocol support shall be downward compatible for patch only version update. @@ -54,42 +98,44 @@ pub fn get_truncate_version_str() -> String { } } -/// FIXME: Remove this once BEFORE next breaking release and fix this whole file -/// Get the PKs version string. -/// If the public key mis-configed via env variable, -/// it shall result in being rejected to join by the network -pub fn get_key_version_str() -> String { - // let mut f_k_str = FOUNDATION_PK.to_hex(); - // let _ = f_k_str.split_off(6); - // let mut g_k_str = GENESIS_PK.to_hex(); - // let _ = g_k_str.split_off(6); - // let mut n_k_str = NETWORK_ROYALTIES_PK.to_hex(); - // let _ = n_k_str.split_off(6); - // let s = format!("{f_k_str}_{g_k_str}_{n_k_str}"); - // dbg!(&s); - "b20c91_93f735_af451a".to_string() -} #[cfg(test)] mod tests { use super::*; #[test] fn test_print_version_strings() -> Result<(), Box> { - // Test and print all version strings println!( - "\nIDENTIFY_CLIENT_VERSION_STR: {}", + "\nIDENTIFY_NODE_VERSION_STR: {}", + *IDENTIFY_NODE_VERSION_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_NODE_VERSION_STR") + ); + println!( + "IDENTIFY_CLIENT_VERSION_STR: {}", *IDENTIFY_CLIENT_VERSION_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_CLIENT_VERSION_STR") + ); + println!( + "REQ_RESPONSE_VERSION_STR: {}", + *REQ_RESPONSE_VERSION_STR + .read() + .expect("Failed to obtain read lock for REQ_RESPONSE_VERSION_STR") + ); + println!( + "IDENTIFY_PROTOCOL_STR: {}", + *IDENTIFY_PROTOCOL_STR + .read() + .expect("Failed to obtain read lock for IDENTIFY_PROTOCOL_STR") ); - println!("REQ_RESPONSE_VERSION_STR: {}", *REQ_RESPONSE_VERSION_STR); - println!("IDENTIFY_PROTOCOL_STR: {}", *IDENTIFY_PROTOCOL_STR); // Test truncated version string let truncated = get_truncate_version_str(); println!("\nTruncated version: {truncated}"); - // Test key version string - let key_version = get_key_version_str(); - println!("\nKey version string: {key_version}"); + // Test network id string + let network_id = get_network_id(); + println!("Network ID string: {network_id}"); Ok(()) } diff --git a/autonomi/src/client/mod.rs b/autonomi/src/client/mod.rs index acc62981da..d14964f9f1 100644 --- a/autonomi/src/client/mod.rs +++ b/autonomi/src/client/mod.rs @@ -177,7 +177,7 @@ async fn handle_event_receiver( sender .send(Err(ConnectError::TimedOutWithIncompatibleProtocol( protocols, - IDENTIFY_PROTOCOL_STR.to_string(), + IDENTIFY_PROTOCOL_STR.read().expect("Failed to obtain read lock for IDENTIFY_PROTOCOL_STR. A call to set_network_id performed. This should not happen").clone(), ))) .expect("receiver should not close"); } else {