diff --git a/Cargo.lock b/Cargo.lock index 872fcc8820..9e388b2350 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", @@ -1095,6 +1096,7 @@ dependencies = [ name = "ant-service-management" version = "0.4.3" dependencies = [ + "ant-bootstrap", "ant-evm", "ant-logging", "ant-protocol", diff --git a/ant-bootstrap/src/cache_store.rs b/ant-bootstrap/src/cache_store.rs index c435fbec23..eabffd6164 100644 --- a/ant-bootstrap/src/cache_store.rs +++ b/ant-bootstrap/src/cache_store.rs @@ -181,15 +181,21 @@ impl BootstrapCacheStore { /// Create a empty CacheStore from the given peers argument. /// This also modifies the cfg if provided based on the PeersArgs. /// And also performs some actions based on the PeersArgs. + /// + /// `PeersArgs::bootstrap_cache_dir` will take precedence over the path provided inside `config`. pub fn new_from_peers_args( peers_arg: &PeersArgs, - cfg: Option, + config: Option, ) -> Result { - let config = if let Some(cfg) = cfg { + let mut config = if let Some(cfg) = config { cfg } else { BootstrapCacheConfig::default_config()? }; + if let Some(bootstrap_cache_path) = peers_arg.get_bootstrap_cache_path()? { + config.cache_file_path = bootstrap_cache_path; + } + let mut store = Self::new(config)?; // If it is the first node, clear the cache. diff --git a/ant-bootstrap/src/config.rs b/ant-bootstrap/src/config.rs index 52d85b7dee..b2c88561be 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,8 +118,13 @@ fn default_cache_path() -> Result { std::fs::create_dir_all(&dir)?; - let network_id = format!("{}_{}", get_key_version_str(), get_truncate_version_str()); - let path = dir.join(format!("bootstrap_cache_{}.json", network_id)); + let path = dir.join(cache_file_name()); Ok(path) } + +/// Returns the name of the cache file +pub fn cache_file_name() -> String { + let network_id = format!("{}_{}", get_network_id(), get_truncate_version_str()); + format!("bootstrap_cache_{network_id}.json") +} diff --git a/ant-bootstrap/src/contacts.rs b/ant-bootstrap/src/contacts.rs index 83262fbc1a..24d9ac9bcf 100644 --- a/ant-bootstrap/src/contacts.rs +++ b/ant-bootstrap/src/contacts.rs @@ -95,7 +95,6 @@ impl ContactsFetcher { self.endpoints ); let mut bootstrap_addresses = Vec::new(); - let mut last_error = None; let mut fetches = stream::iter(self.endpoints.clone()) .map(|endpoint| async move { @@ -131,37 +130,16 @@ impl ContactsFetcher { } Err(e) => { warn!("Failed to fetch bootstrap addrs from {}: {}", endpoint, e); - last_error = Some(e); } } } - if bootstrap_addresses.is_empty() { - last_error.map_or_else( - || { - warn!("No bootstrap addrs found from any endpoint and no errors reported"); - Err(Error::NoBootstrapAddressesFound( - "No valid peers found from any endpoint".to_string(), - )) - }, - |e| { - warn!( - "No bootstrap addrs found from any endpoint. Last error: {}", - e - ); - Err(Error::NoBootstrapAddressesFound(format!( - "No valid bootstrap addrs found from any endpoint: {e}", - ))) - }, - ) - } else { - info!( - "Successfully discovered {} total addresses. First few: {:?}", - bootstrap_addresses.len(), - bootstrap_addresses.iter().take(3).collect::>() - ); - Ok(bootstrap_addresses) - } + info!( + "Successfully discovered {} total addresses. First few: {:?}", + bootstrap_addresses.len(), + bootstrap_addresses.iter().take(3).collect::>() + ); + Ok(bootstrap_addresses) } /// Fetch the list of multiaddrs from a single endpoint @@ -244,20 +222,13 @@ impl ContactsFetcher { }) .collect::>(); - if bootstrap_addresses.is_empty() { - warn!("No valid peers found in JSON response"); - Err(Error::NoBootstrapAddressesFound( - "No valid peers found in JSON response".to_string(), - )) - } else { - info!( - "Successfully parsed {} valid peers from JSON", - bootstrap_addresses.len() - ); - Ok(bootstrap_addresses) - } + info!( + "Successfully parsed {} valid peers from JSON", + bootstrap_addresses.len() + ); + Ok(bootstrap_addresses) } - Err(e) => { + Err(_err) => { info!("Attempting to parse response as plain text"); // Try parsing as plain text with one multiaddr per line // example of contacts file exists in resources/network-contacts-examples @@ -266,20 +237,11 @@ impl ContactsFetcher { .filter_map(|str| craft_valid_multiaddr_from_str(str, ignore_peer_id)) .collect::>(); - if bootstrap_addresses.is_empty() { - warn!( - "No valid bootstrap addrs found in plain text response. Previous Json error: {e:?}" - ); - Err(Error::NoBootstrapAddressesFound( - "No valid bootstrap addrs found in plain text response".to_string(), - )) - } else { - info!( - "Successfully parsed {} valid bootstrap addrs from plain text", - bootstrap_addresses.len() - ); - Ok(bootstrap_addresses) - } + info!( + "Successfully parsed {} valid bootstrap addrs from plain text", + bootstrap_addresses.len() + ); + Ok(bootstrap_addresses) } } } @@ -387,24 +349,6 @@ mod tests { assert_eq!(addrs[0].addr, valid_addr); } - #[tokio::test] - async fn test_empty_response() { - let mock_server = MockServer::start().await; - - Mock::given(method("GET")) - .and(path("/")) - .respond_with(ResponseTemplate::new(200).set_body_string("")) - .mount(&mock_server) - .await; - - let mut fetcher = ContactsFetcher::new().unwrap(); - fetcher.endpoints = vec![mock_server.uri().parse().unwrap()]; - - let result = fetcher.fetch_bootstrap_addresses().await; - - assert!(matches!(result, Err(Error::NoBootstrapAddressesFound(_)))); - } - #[tokio::test] async fn test_whitespace_and_empty_lines() { let mock_server = MockServer::start().await; diff --git a/ant-bootstrap/src/error.rs b/ant-bootstrap/src/error.rs index 77002702e5..a2eedfeee5 100644 --- a/ant-bootstrap/src/error.rs +++ b/ant-bootstrap/src/error.rs @@ -16,10 +16,12 @@ pub enum Error { FailedToParseCacheData, #[error("Could not obtain data directory")] CouldNotObtainDataDir, + #[error("Invalid bootstrap cache directory")] + InvalidBootstrapCacheDir, #[error("Could not obtain bootstrap addresses from {0} after {1} retries")] FailedToObtainAddrsFromUrl(String, usize), - #[error("No Bootstrap Addresses found: {0}")] - NoBootstrapAddressesFound(String), + #[error("Failed to parse Url")] + FailedToParseUrl, #[error("IO error: {0}")] Io(#[from] std::io::Error), #[error("JSON error: {0}")] diff --git a/ant-bootstrap/src/initial_peers.rs b/ant-bootstrap/src/initial_peers.rs index 07d0cd3b24..afa983b0de 100644 --- a/ant-bootstrap/src/initial_peers.rs +++ b/ant-bootstrap/src/initial_peers.rs @@ -7,19 +7,22 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{ + config::cache_file_name, craft_valid_multiaddr, craft_valid_multiaddr_from_str, error::{Error, Result}, BootstrapAddr, BootstrapCacheConfig, BootstrapCacheStore, ContactsFetcher, }; use clap::Args; use libp2p::Multiaddr; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; use url::Url; /// The name of the environment variable that can be used to pass peers to the node. pub const ANT_PEERS_ENV: &str = "ANT_PEERS"; /// Command line arguments for peer configuration -#[derive(Args, Debug, Clone, Default)] +#[derive(Args, Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct PeersArgs { /// Set to indicate this is the first node in a new network /// @@ -41,16 +44,15 @@ pub struct PeersArgs { long = "peer", value_name = "multiaddr", value_delimiter = ',', - conflicts_with = "first", - value_parser = parse_multiaddr_str + conflicts_with = "first" )] pub addrs: Vec, /// Specify the URL to fetch the network contacts from. /// /// The URL can point to a text file containing Multiaddresses separated by newline character, or /// a bootstrap cache JSON file. - #[clap(long, conflicts_with = "first")] - pub network_contacts_url: Option, + #[clap(long, conflicts_with = "first", value_delimiter = ',')] + pub network_contacts_url: Vec, /// Set to indicate this is a local network. You could also set the `local` feature flag to set this to true. /// /// This would use mDNS for peer discovery. @@ -59,38 +61,55 @@ pub struct PeersArgs { /// Set to indicate this is a testnet. /// /// This disables fetching peers from the mainnet network contacts. - #[clap(name = "testnet", long, conflicts_with = "network_contacts_url")] + #[clap(name = "testnet", long)] pub disable_mainnet_contacts: bool, - /// Set to not load the bootstrap addresses from the local cache. #[clap(long, default_value = "false")] pub ignore_cache: bool, + /// The directory to load and store the bootstrap cache. If not provided, the default path will be used. + /// + /// The JSON filename will be derived automatically from the network ID + /// + /// The default location is platform specific: + /// - Linux: $HOME/.local/share/autonomi/bootstrap_cache/bootstrap_cache_.json + /// - macOS: $HOME/Library/Application Support/autonomi/bootstrap_cache/bootstrap_cache_.json + /// - Windows: C:\Users\\AppData\Roaming\autonomi\bootstrap_cache\bootstrap_cache_.json + #[clap(long)] + pub bootstrap_cache_dir: Option, } + impl PeersArgs { - /// Get bootstrap peers + /// Get bootstrap peers sorted by the failure rate. The peer with the lowest failure rate will be + /// the first in the list. /// Order of precedence: /// 1. Addresses from arguments /// 2. Addresses from environment variable SAFE_PEERS - /// 3. Addresses from cache + /// 3. Addresses from cache. `Self::bootstrap_cache_dir` will take precedence over the path provided inside `config` /// 4. Addresses from network contacts URL - pub async fn get_addrs(&self, config: Option) -> Result> { + pub async fn get_addrs( + &self, + config: Option, + count: Option, + ) -> Result> { Ok(self - .get_bootstrap_addr(config) + .get_bootstrap_addr(config, count) .await? .into_iter() .map(|addr| addr.addr) .collect()) } - /// Get bootstrap peers + /// Get bootstrap peers sorted by the failure rate. The peer with the lowest failure rate will be + /// the first in the list. /// Order of precedence: /// 1. Addresses from arguments /// 2. Addresses from environment variable SAFE_PEERS - /// 3. Addresses from cache + /// 3. Addresses from cache. `Self::bootstrap_cache_dir` will take precedence over the path provided inside `config` /// 4. Addresses from network contacts URL pub async fn get_bootstrap_addr( &self, config: Option, + count: Option, ) -> Result> { // If this is the first node, return an empty list if self.first { @@ -115,33 +134,25 @@ impl PeersArgs { warn!("Invalid multiaddress format from arguments: {addr}"); } } - // Read from ANT_PEERS environment variable if present - if let Ok(addrs) = std::env::var(ANT_PEERS_ENV) { - for addr_str in addrs.split(',') { - if let Some(addr) = craft_valid_multiaddr_from_str(addr_str, false) { - info!("Adding addr from environment variable: {addr}"); - bootstrap_addresses.push(BootstrapAddr::new(addr)); - } else { - warn!("Invalid multiaddress format from environment variable: {addr_str}"); - } - } - } + bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env()); // If we have a network contacts URL, fetch addrs from there. - if let Some(url) = self.network_contacts_url.clone() { - info!("Fetching bootstrap address from network contacts URL: {url}",); - let contacts_fetcher = ContactsFetcher::with_endpoints(vec![url])?; + if !self.network_contacts_url.is_empty() { + info!( + "Fetching bootstrap address from network contacts URLs: {:?}", + self.network_contacts_url + ); + let addrs = self + .network_contacts_url + .iter() + .map(|url| url.parse::().map_err(|_| Error::FailedToParseUrl)) + .collect::>>()?; + let contacts_fetcher = ContactsFetcher::with_endpoints(addrs)?; let addrs = contacts_fetcher.fetch_bootstrap_addresses().await?; bootstrap_addresses.extend(addrs); } - // Return here if we fetched peers from the args - if !bootstrap_addresses.is_empty() { - bootstrap_addresses.sort_by_key(|addr| addr.failure_rate() as u64); - return Ok(bootstrap_addresses); - } - // load from cache if present if !self.ignore_cache { let cfg = if let Some(config) = config { @@ -149,7 +160,10 @@ impl PeersArgs { } else { BootstrapCacheConfig::default_config().ok() }; - if let Some(cfg) = cfg { + if let Some(mut cfg) = cfg { + if let Some(file_path) = self.get_bootstrap_cache_path()? { + cfg.cache_file_path = file_path; + } info!("Loading bootstrap addresses from cache"); if let Ok(data) = BootstrapCacheStore::load_cache_data(&cfg) { bootstrap_addresses = data @@ -166,11 +180,6 @@ impl PeersArgs { } } - if !bootstrap_addresses.is_empty() { - bootstrap_addresses.sort_by_key(|addr| addr.failure_rate() as u64); - return Ok(bootstrap_addresses); - } - if !self.disable_mainnet_contacts { let contacts_fetcher = ContactsFetcher::with_mainnet_endpoints()?; let addrs = contacts_fetcher.fetch_bootstrap_addresses().await?; @@ -179,14 +188,54 @@ impl PeersArgs { if !bootstrap_addresses.is_empty() { bootstrap_addresses.sort_by_key(|addr| addr.failure_rate() as u64); + if let Some(count) = count { + bootstrap_addresses.truncate(count); + } Ok(bootstrap_addresses) } else { error!("No initial bootstrap peers found through any means"); Err(Error::NoBootstrapPeersFound) } } -} -pub fn parse_multiaddr_str(addr: &str) -> std::result::Result { - addr.parse::() + pub fn read_addr_from_env() -> Vec { + Self::read_bootstrap_addr_from_env() + .into_iter() + .map(|addr| addr.addr) + .collect() + } + + pub fn read_bootstrap_addr_from_env() -> Vec { + let mut bootstrap_addresses = Vec::new(); + // Read from ANT_PEERS environment variable if present + if let Ok(addrs) = std::env::var(ANT_PEERS_ENV) { + for addr_str in addrs.split(',') { + if let Some(addr) = craft_valid_multiaddr_from_str(addr_str, false) { + info!("Adding addr from environment variable: {addr}"); + bootstrap_addresses.push(BootstrapAddr::new(addr)); + } else { + warn!("Invalid multiaddress format from environment variable: {addr_str}"); + } + } + } + bootstrap_addresses + } + + /// Get the path to the bootstrap cache JSON file if `Self::bootstrap_cache_dir` is set + pub fn get_bootstrap_cache_path(&self) -> Result> { + if let Some(dir) = &self.bootstrap_cache_dir { + if dir.is_file() { + return Err(Error::InvalidBootstrapCacheDir); + } + + if !dir.exists() { + std::fs::create_dir_all(dir)?; + } + + let path = dir.join(cache_file_name()); + Ok(Some(path)) + } else { + Ok(None) + } + } } diff --git a/ant-bootstrap/tests/address_format_tests.rs b/ant-bootstrap/tests/address_format_tests.rs index 55d9246b8b..88369f4cd8 100644 --- a/ant-bootstrap/tests/address_format_tests.rs +++ b/ant-bootstrap/tests/address_format_tests.rs @@ -45,13 +45,14 @@ async fn test_multiaddr_format_parsing() -> Result<(), Box Result<(), Box let args = PeersArgs { first: false, addrs: vec![], - network_contacts_url: Some(format!("{}/peers", mock_server.uri()).parse()?), + network_contacts_url: vec![format!("{}/peers", mock_server.uri()).parse()?], local: false, - disable_mainnet_contacts: false, - ignore_cache: false, + disable_mainnet_contacts: true, + ignore_cache: true, + bootstrap_cache_dir: None, }; - let addrs = args.get_bootstrap_addr(None).await?; + let addrs = args.get_bootstrap_addr(None, None).await?; assert_eq!( addrs.len(), 2, diff --git a/ant-bootstrap/tests/cli_integration_tests.rs b/ant-bootstrap/tests/cli_integration_tests.rs index 1afee9176e..98341ae452 100644 --- a/ant-bootstrap/tests/cli_integration_tests.rs +++ b/ant-bootstrap/tests/cli_integration_tests.rs @@ -31,13 +31,14 @@ async fn test_first_flag() -> Result<(), Box> { let args = PeersArgs { first: true, addrs: vec![], - network_contacts_url: None, + network_contacts_url: vec![], local: false, disable_mainnet_contacts: false, ignore_cache: false, + bootstrap_cache_dir: None, }; - let addrs = args.get_addrs(Some(config)).await?; + let addrs = args.get_addrs(Some(config), None).await?; assert!(addrs.is_empty(), "First node should have no addrs"); @@ -56,13 +57,14 @@ async fn test_peer_argument() -> Result<(), Box> { let args = PeersArgs { first: false, addrs: vec![peer_addr.clone()], - network_contacts_url: None, + network_contacts_url: vec![], local: false, disable_mainnet_contacts: true, ignore_cache: false, + bootstrap_cache_dir: None, }; - let addrs = args.get_addrs(None).await?; + let addrs = args.get_addrs(None, None).await?; assert_eq!(addrs.len(), 1, "Should have one addr"); assert_eq!(addrs[0], peer_addr, "Should have the correct address"); @@ -90,13 +92,14 @@ async fn test_network_contacts_fallback() -> Result<(), Box Result<(), Box> { let args = PeersArgs { first: false, addrs: vec![], - network_contacts_url: None, + network_contacts_url: vec![], local: true, disable_mainnet_contacts: false, ignore_cache: false, + bootstrap_cache_dir: None, }; - let addrs = args.get_addrs(Some(config)).await?; + let addrs = args.get_addrs(Some(config), None).await?; assert!(addrs.is_empty(), "Local mode should have no peers"); @@ -155,13 +159,14 @@ async fn test_test_network_peers() -> Result<(), Box> { let args = PeersArgs { first: false, addrs: vec![peer_addr.clone()], - network_contacts_url: None, + network_contacts_url: vec![], local: false, disable_mainnet_contacts: true, ignore_cache: false, + bootstrap_cache_dir: None, }; - let addrs = args.get_addrs(Some(config)).await?; + let addrs = args.get_addrs(Some(config), None).await?; assert_eq!(addrs.len(), 1, "Should have exactly one test network peer"); assert_eq!( diff --git a/ant-cli/Cargo.toml b/ant-cli/Cargo.toml index 8f605ec14c..c6eecb42f6 100644 --- a/ant-cli/Cargo.toml +++ b/ant-cli/Cargo.toml @@ -26,6 +26,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/access/network.rs b/ant-cli/src/access/network.rs index acf7acfae6..8c428e06d3 100644 --- a/ant-cli/src/access/network.rs +++ b/ant-cli/src/access/network.rs @@ -13,7 +13,7 @@ use color_eyre::Result; use color_eyre::Section; pub async fn get_peers(peers: PeersArgs) -> Result> { - peers.get_addrs(None).await + peers.get_addrs(None, Some(100)).await .wrap_err("Please provide valid Network peers to connect to") .with_suggestion(|| format!("make sure you've provided network peers using the --peers option or the {ANT_PEERS_ENV} env var")) .with_suggestion(|| "a peer address looks like this: /ip4/42.42.42.42/udp/4242/quic-v1/p2p/B64nodePeerIDvdjb3FAJF4ks3moreBase64CharsHere") 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 5319892dc3..e1ac2d3d13 100644 --- a/ant-networking/src/driver.rs +++ b/ant-networking/src/driver.rs @@ -37,7 +37,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, @@ -268,16 +268,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, } @@ -286,16 +286,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, } @@ -395,7 +395,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 @@ -432,7 +432,6 @@ impl NetworkBuilder { Some(store_cfg), false, ProtocolSupport::Full, - IDENTIFY_NODE_VERSION_STR.to_string(), #[cfg(feature = "upnp")] upnp, )?; @@ -472,7 +471,6 @@ impl NetworkBuilder { None, true, ProtocolSupport::Outbound, - IDENTIFY_CLIENT_VERSION_STR.to_string(), #[cfg(feature = "upnp")] false, )?; @@ -487,9 +485,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"))] @@ -553,7 +555,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(), )]), ); @@ -567,14 +569,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, @@ -630,12 +634,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-manager/src/add_services/config.rs b/ant-node-manager/src/add_services/config.rs index 046b29d79b..7aac0eaeb6 100644 --- a/ant-node-manager/src/add_services/config.rs +++ b/ant-node-manager/src/add_services/config.rs @@ -6,10 +6,11 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. +use ant_bootstrap::PeersArgs; use ant_evm::{EvmNetwork, RewardsAddress}; use ant_logging::LogFormat; +use ant_service_management::node::push_arguments_from_peers_args; use color_eyre::{eyre::eyre, Result}; -use libp2p::Multiaddr; use service_manager::{ServiceInstallCtx, ServiceLabel}; use std::{ ffi::OsString, @@ -71,22 +72,21 @@ impl PortRange { pub struct InstallNodeServiceCtxBuilder { pub antnode_path: PathBuf, pub autostart: bool, - pub bootstrap_peers: Vec, pub data_dir_path: PathBuf, pub env_variables: Option>, pub evm_network: EvmNetwork, - pub genesis: bool, pub home_network: bool, - pub local: bool, pub log_dir_path: PathBuf, pub log_format: Option, pub name: String, + pub network_id: Option, pub max_archived_log_files: Option, pub max_log_files: Option, pub metrics_port: Option, pub node_ip: Option, pub node_port: Option, pub owner: Option, + pub peers_args: PeersArgs, pub rewards_address: RewardsAddress, pub rpc_socket_addr: SocketAddr, pub service_user: Option, @@ -105,15 +105,14 @@ impl InstallNodeServiceCtxBuilder { OsString::from(self.log_dir_path.to_string_lossy().to_string()), ]; - if self.genesis { - args.push(OsString::from("--first")); + push_arguments_from_peers_args(&self.peers_args, &mut args); + if let Some(id) = self.network_id { + args.push(OsString::from("--network-id")); + args.push(OsString::from(id.to_string())); } if self.home_network { args.push(OsString::from("--home-network")); } - if self.local { - args.push(OsString::from("--local")); - } if let Some(log_format) = self.log_format { args.push(OsString::from("--log-format")); args.push(OsString::from(log_format.as_str())); @@ -146,17 +145,6 @@ impl InstallNodeServiceCtxBuilder { args.push(OsString::from(log_files.to_string())); } - if !self.bootstrap_peers.is_empty() { - let peers_str = self - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } - args.push(OsString::from("--rewards-address")); args.push(OsString::from(self.rewards_address.to_string())); @@ -192,22 +180,21 @@ pub struct AddNodeServiceOptions { pub antnode_src_path: PathBuf, pub auto_restart: bool, pub auto_set_nat_flags: bool, - pub bootstrap_peers: Vec, pub count: Option, pub delete_antnode_src: bool, pub enable_metrics_server: bool, pub env_variables: Option>, pub evm_network: EvmNetwork, - pub genesis: bool, pub home_network: bool, - pub local: bool, pub log_format: Option, pub max_archived_log_files: Option, pub max_log_files: Option, pub metrics_port: Option, + pub network_id: Option, pub node_ip: Option, pub node_port: Option, pub owner: Option, + pub peers_args: PeersArgs, pub rewards_address: RewardsAddress, pub rpc_address: Option, pub rpc_port: Option, @@ -223,7 +210,6 @@ pub struct AddNodeServiceOptions { pub struct InstallAuditorServiceCtxBuilder { pub auditor_path: PathBuf, pub beta_encryption_key: Option, - pub bootstrap_peers: Vec, pub env_variables: Option>, pub log_dir_path: PathBuf, pub name: String, @@ -237,16 +223,6 @@ impl InstallAuditorServiceCtxBuilder { OsString::from(self.log_dir_path.to_string_lossy().to_string()), ]; - if !self.bootstrap_peers.is_empty() { - let peers_str = self - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } if let Some(beta_encryption_key) = self.beta_encryption_key { args.push(OsString::from("--beta-encryption-key")); args.push(OsString::from(beta_encryption_key)); @@ -267,7 +243,6 @@ impl InstallAuditorServiceCtxBuilder { #[derive(Debug, PartialEq)] pub struct InstallFaucetServiceCtxBuilder { - pub bootstrap_peers: Vec, pub env_variables: Option>, pub faucet_path: PathBuf, pub local: bool, @@ -283,17 +258,6 @@ impl InstallFaucetServiceCtxBuilder { OsString::from(self.log_dir_path.to_string_lossy().to_string()), ]; - if !self.bootstrap_peers.is_empty() { - let peers_str = self - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } - args.push(OsString::from("server")); Ok(ServiceInstallCtx { @@ -313,7 +277,6 @@ pub struct AddAuditorServiceOptions { pub auditor_install_bin_path: PathBuf, pub auditor_src_bin_path: PathBuf, pub beta_encryption_key: Option, - pub bootstrap_peers: Vec, pub env_variables: Option>, pub service_log_dir_path: PathBuf, pub user: String, @@ -321,7 +284,6 @@ pub struct AddAuditorServiceOptions { } pub struct AddFaucetServiceOptions { - pub bootstrap_peers: Vec, pub env_variables: Option>, pub faucet_install_bin_path: PathBuf, pub faucet_src_bin_path: PathBuf, @@ -352,22 +314,21 @@ mod tests { InstallNodeServiceCtxBuilder { antnode_path: PathBuf::from("/bin/antnode"), autostart: true, - bootstrap_peers: vec![], data_dir_path: PathBuf::from("/data"), env_variables: None, evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, - local: false, log_dir_path: PathBuf::from("/logs"), log_format: None, - name: "test-node".to_string(), max_archived_log_files: None, max_log_files: None, metrics_port: None, + name: "test-node".to_string(), + network_id: None, node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124") .unwrap(), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080), @@ -379,7 +340,6 @@ mod tests { fn create_custom_evm_network_builder() -> InstallNodeServiceCtxBuilder { InstallNodeServiceCtxBuilder { autostart: true, - bootstrap_peers: vec![], data_dir_path: PathBuf::from("/data"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -393,18 +353,18 @@ mod tests { ) .unwrap(), }), - genesis: false, home_network: false, - local: false, log_dir_path: PathBuf::from("/logs"), log_format: None, - name: "test-node".to_string(), max_archived_log_files: None, max_log_files: None, metrics_port: None, + name: "test-node".to_string(), + network_id: None, node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124") .unwrap(), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080), @@ -417,7 +377,6 @@ mod tests { fn create_builder_with_all_options_enabled() -> InstallNodeServiceCtxBuilder { InstallNodeServiceCtxBuilder { autostart: true, - bootstrap_peers: vec![], data_dir_path: PathBuf::from("/data"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -431,18 +390,18 @@ mod tests { ) .unwrap(), }), - genesis: false, home_network: false, - local: false, log_dir_path: PathBuf::from("/logs"), log_format: None, - name: "test-node".to_string(), max_archived_log_files: Some(10), max_log_files: Some(10), metrics_port: None, + name: "test-node".to_string(), + network_id: Some(5), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124") .unwrap(), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080), @@ -525,19 +484,22 @@ mod tests { #[test] fn build_should_assign_expected_values_when_all_options_are_enabled() { let mut builder = create_builder_with_all_options_enabled(); - builder.genesis = true; builder.home_network = true; - builder.local = true; builder.log_format = Some(LogFormat::Json); builder.upnp = true; builder.node_ip = Some(Ipv4Addr::new(192, 168, 1, 1)); builder.node_port = Some(12345); builder.metrics_port = Some(9090); builder.owner = Some("test-owner".to_string()); - builder.bootstrap_peers = vec![ + builder.peers_args.addrs = vec![ "/ip4/127.0.0.1/tcp/8080".parse().unwrap(), "/ip4/192.168.1.1/tcp/8081".parse().unwrap(), ]; + builder.peers_args.first = true; + builder.peers_args.local = true; + builder.peers_args.network_contacts_url = vec!["http://localhost:8080".parse().unwrap()]; + builder.peers_args.ignore_cache = true; + builder.peers_args.disable_mainnet_contacts = true; builder.service_user = Some("antnode-user".to_string()); let result = builder.build().unwrap(); @@ -550,8 +512,16 @@ mod tests { "--log-output-dest", "/logs", "--first", - "--home-network", "--local", + "--peer", + "/ip4/127.0.0.1/tcp/8080,/ip4/192.168.1.1/tcp/8081", + "--network-contacts-url", + "http://localhost:8080", + "--testnet", + "--ignore-cache", + "--network-id", + "5", + "--home-network", "--log-format", "json", "--upnp", @@ -567,8 +537,6 @@ mod tests { "10", "--max-log-files", "10", - "--peer", - "/ip4/127.0.0.1/tcp/8080,/ip4/192.168.1.1/tcp/8081", "--rewards-address", "0x03B770D9cD32077cC0bF330c13C114a87643B124", "evm-custom", diff --git a/ant-node-manager/src/add_services/mod.rs b/ant-node-manager/src/add_services/mod.rs index f3b77d4649..76e8d46c12 100644 --- a/ant-node-manager/src/add_services/mod.rs +++ b/ant-node-manager/src/add_services/mod.rs @@ -48,7 +48,7 @@ pub async fn add_node( service_control: &dyn ServiceControl, verbosity: VerbosityLevel, ) -> Result> { - if options.genesis { + if options.peers_args.first { if let Some(count) = options.count { if count > 1 { error!("A genesis node can only be added as a single node"); @@ -56,7 +56,7 @@ pub async fn add_node( } } - let genesis_node = node_registry.nodes.iter().find(|n| n.genesis); + let genesis_node = node_registry.nodes.iter().find(|n| n.peers_args.first); if genesis_node.is_some() { error!("A genesis node already exists"); return Err(eyre!("A genesis node already exists")); @@ -98,30 +98,11 @@ pub async fn add_node( .to_string_lossy() .to_string(); - { - let mut should_save = false; - let new_bootstrap_peers: Vec<_> = options - .bootstrap_peers - .iter() - .filter(|peer| !node_registry.bootstrap_peers.contains(peer)) - .collect(); - if !new_bootstrap_peers.is_empty() { - node_registry - .bootstrap_peers - .extend(new_bootstrap_peers.into_iter().cloned()); - should_save = true; - } - - if options.env_variables.is_some() { - node_registry - .environment_variables - .clone_from(&options.env_variables); - should_save = true; - } - - if should_save { - node_registry.save()?; - } + if options.env_variables.is_some() { + node_registry + .environment_variables + .clone_from(&options.env_variables); + node_registry.save()?; } let mut added_service_data = vec![]; @@ -219,22 +200,21 @@ pub async fn add_node( let install_ctx = InstallNodeServiceCtxBuilder { autostart: options.auto_restart, - bootstrap_peers: options.bootstrap_peers.clone(), data_dir_path: service_data_dir_path.clone(), env_variables: options.env_variables.clone(), evm_network: options.evm_network.clone(), - genesis: options.genesis, home_network: options.home_network, - local: options.local, log_dir_path: service_log_dir_path.clone(), log_format: options.log_format, max_archived_log_files: options.max_archived_log_files, max_log_files: options.max_log_files, metrics_port: metrics_free_port, name: service_name.clone(), + network_id: options.network_id, node_ip: options.node_ip, node_port, owner: owner.clone(), + peers_args: options.peers_args.clone(), rewards_address: options.rewards_address, rpc_socket_addr, antnode_path: service_antnode_path.clone(), @@ -260,15 +240,14 @@ pub async fn add_node( connected_peers: None, data_dir_path: service_data_dir_path.clone(), evm_network: options.evm_network.clone(), - genesis: options.genesis, home_network: options.home_network, listen_addr: None, - local: options.local, log_dir_path: service_log_dir_path.clone(), log_format: options.log_format, max_archived_log_files: options.max_archived_log_files, max_log_files: options.max_log_files, metrics_port: metrics_free_port, + network_id: options.network_id, node_ip: options.node_ip, node_port, number: node_number, @@ -277,6 +256,7 @@ pub async fn add_node( rpc_socket_addr, owner: owner.clone(), peer_id: None, + peers_args: options.peers_args.clone(), pid: None, service_name, status: ServiceStatus::Added, @@ -381,7 +361,6 @@ pub fn add_auditor( let install_ctx = InstallAuditorServiceCtxBuilder { auditor_path: install_options.auditor_install_bin_path.clone(), beta_encryption_key: install_options.beta_encryption_key.clone(), - bootstrap_peers: install_options.bootstrap_peers.clone(), env_variables: install_options.env_variables.clone(), log_dir_path: install_options.service_log_dir_path.clone(), name: "auditor".to_string(), @@ -525,7 +504,6 @@ pub fn add_faucet( )?; let install_ctx = InstallFaucetServiceCtxBuilder { - bootstrap_peers: install_options.bootstrap_peers.clone(), env_variables: install_options.env_variables.clone(), faucet_path: install_options.faucet_install_bin_path.clone(), local: install_options.local, diff --git a/ant-node-manager/src/add_services/tests.rs b/ant-node-manager/src/add_services/tests.rs index 8a413a331e..58eaf31162 100644 --- a/ant-node-manager/src/add_services/tests.rs +++ b/ant-node-manager/src/add_services/tests.rs @@ -16,6 +16,7 @@ use crate::{ }, VerbosityLevel, }; +use ant_bootstrap::PeersArgs; use ant_evm::{AttoTokens, CustomNetwork, EvmNetwork, RewardsAddress}; use ant_service_management::{auditor::AuditorServiceData, control::ServiceControl}; use ant_service_management::{error::Result as ServiceControlResult, NatDetectionStatus}; @@ -25,7 +26,6 @@ use ant_service_management::{ use assert_fs::prelude::*; use assert_matches::assert_matches; use color_eyre::Result; -use libp2p::Multiaddr; use mockall::{mock, predicate::*, Sequence}; use predicates::prelude::*; use service_manager::ServiceInstallCtx; @@ -97,7 +97,6 @@ async fn add_genesis_node_should_use_latest_version_and_add_one_service() -> Res save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -110,9 +109,18 @@ async fn add_genesis_node_should_use_latest_version_and_add_one_service() -> Res .returning(|| Ok(8081)) .in_sequence(&mut seq); + let peers_args = PeersArgs { + first: true, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -124,18 +132,18 @@ async fn add_genesis_node_should_use_latest_version_and_add_one_service() -> Res "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: true, home_network: false, - local: true, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, name: "antnode1".to_string(), + network_id: None, node_ip: None, node_port: None, owner: None, + peers_args: peers_args.clone(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir @@ -157,21 +165,20 @@ async fn add_genesis_node_should_use_latest_version_and_add_one_service() -> Res AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: true, home_network: false, - local: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args, rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -207,7 +214,7 @@ async fn add_genesis_node_should_use_latest_version_and_add_one_service() -> Res node_reg_path.assert(predicates::path::is_file()); assert_eq!(node_registry.nodes.len(), 1); - assert!(node_registry.nodes[0].genesis); + assert!(node_registry.nodes[0].peers_args.first); assert_eq!(node_registry.nodes[0].version, latest_version); assert_eq!(node_registry.nodes[0].service_name, "antnode1"); assert_eq!(node_registry.nodes[0].user, Some(get_username())); @@ -254,6 +261,16 @@ async fn add_genesis_node_should_return_an_error_if_there_is_already_a_genesis_n let mock_service_control = MockServiceControl::new(); let latest_version = "0.96.4"; + + let peers_args = PeersArgs { + first: true, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; let mut node_registry = NodeRegistry { auditor: None, faucet: None, @@ -272,21 +289,21 @@ async fn add_genesis_node_should_return_an_error_if_there_is_already_a_genesis_n "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: true, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, - pid: None, - peer_id: None, owner: None, + peer_id: None, + peers_args: peers_args.clone(), + pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", )?, @@ -300,7 +317,6 @@ async fn add_genesis_node_should_return_an_error_if_there_is_already_a_genesis_n user_mode: false, version: latest_version.to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -319,21 +335,20 @@ async fn add_genesis_node_should_return_an_error_if_there_is_already_a_genesis_n AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: true, home_network: false, - local: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args, rpc_address: Some(custom_rpc_address), rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -384,10 +399,18 @@ async fn add_genesis_node_should_return_an_error_if_count_is_greater_than_1() -> save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; + let peers_args = PeersArgs { + first: true, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; let latest_version = "0.96.4"; let temp_dir = assert_fs::TempDir::new()?; @@ -402,21 +425,20 @@ async fn add_genesis_node_should_return_an_error_if_count_is_greater_than_1() -> AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: true, home_network: false, - local: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args, rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -467,7 +489,6 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -492,7 +513,6 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -504,18 +524,18 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir .to_path_buf() @@ -542,7 +562,6 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( .in_sequence(&mut seq); let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode2"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -554,18 +573,18 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode2"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode2".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8083), antnode_path: node_data_dir @@ -593,7 +612,6 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, data_dir_path: node_data_dir.to_path_buf().join("antnode3"), - bootstrap_peers: vec![], env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { rpc_url_http: "http://localhost:8545".parse()?, @@ -604,18 +622,18 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_format: None, log_dir_path: node_logs_dir.to_path_buf().join("antnode3"), max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode3".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8085), antnode_path: node_data_dir @@ -638,21 +656,20 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -739,14 +756,16 @@ async fn add_node_should_use_latest_version_and_add_three_services() -> Result<( } #[tokio::test] -async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Result<()> { +async fn add_node_should_update_the_environment_variables_inside_node_registry() -> Result<()> { let tmp_data_dir = assert_fs::TempDir::new()?; let node_reg_path = tmp_data_dir.child("node_reg.json"); let mut mock_service_control = MockServiceControl::new(); - let mut old_peers = vec![Multiaddr::from_str("/ip4/64.227.35.186/udp/33188/quic-v1/p2p/12D3KooWDrx4zfUuJgz7jSusC28AZRDRbj7eo3WKZigPsw9tVKs3")?]; - let new_peers = vec![Multiaddr::from_str("/ip4/178.62.78.116/udp/45442/quic-v1/p2p/12D3KooWLH4E68xFqoSKuF2JPQQhzaAg7GNvN1vpxoLMgJq6Zqz8")?]; + let env_variables = Some(vec![ + ("ANT_LOG".to_owned(), "all".to_owned()), + ("RUST_LOG".to_owned(), "libp2p=debug".to_owned()), + ]); let mut node_registry = NodeRegistry { auditor: None, @@ -754,7 +773,6 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: old_peers.clone(), environment_variables: None, daemon: None, }; @@ -774,12 +792,10 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re .times(1) .returning(|| Ok(12001)) .in_sequence(&mut seq); - let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: new_peers.clone(), data_dir_path: node_data_dir.to_path_buf().join("antnode1"), - env_variables: None, + env_variables: env_variables.clone(), evm_network: EvmNetwork::Custom(CustomNetwork { rpc_url_http: "http://localhost:8545".parse()?, payment_token_address: RewardsAddress::from_str( @@ -789,18 +805,18 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), antnode_path: node_data_dir @@ -811,7 +827,6 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re upnp: false, } .build()?; - mock_service_control .expect_install() .times(1) @@ -823,25 +838,24 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: new_peers.clone(), count: None, delete_antnode_src: true, enable_metrics_server: false, - env_variables: None, - local: false, - genesis: false, + env_variables: env_variables.clone(), home_network: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, - antnode_src_path: antnode_download_path.to_path_buf(), antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), service_data_dir_path: node_data_dir.to_path_buf(), service_log_dir_path: node_logs_dir.to_path_buf(), upnp: false, @@ -871,8 +885,7 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re node_data_dir.assert(predicate::path::is_dir()); node_logs_dir.assert(predicate::path::is_dir()); - old_peers.extend(new_peers); - assert_eq!(node_registry.bootstrap_peers, old_peers); + assert_eq!(node_registry.environment_variables, env_variables); assert_eq!(node_registry.nodes.len(), 1); assert_eq!(node_registry.nodes[0].version, latest_version); @@ -897,30 +910,64 @@ async fn add_node_should_update_the_bootstrap_peers_inside_node_registry() -> Re } #[tokio::test] -async fn add_node_should_update_the_environment_variables_inside_node_registry() -> Result<()> { +async fn add_new_node_should_add_another_service() -> Result<()> { let tmp_data_dir = assert_fs::TempDir::new()?; let node_reg_path = tmp_data_dir.child("node_reg.json"); let mut mock_service_control = MockServiceControl::new(); - let env_variables = Some(vec![ - ("ANT_LOG".to_owned(), "all".to_owned()), - ("RUST_LOG".to_owned(), "libp2p=debug".to_owned()), - ]); - + let latest_version = "0.96.4"; let mut node_registry = NodeRegistry { auditor: None, faucet: None, save_path: node_reg_path.to_path_buf(), nat_status: None, - nodes: vec![], - bootstrap_peers: vec![], + nodes: vec![NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: None, + peers_args: PeersArgs::default(), + pid: None, + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: PathBuf::from("/var/antctl/services/antnode1/antnode"), + service_name: "antnode1".to_string(), + status: ServiceStatus::Added, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: latest_version.to_string(), + }], environment_variables: None, daemon: None, }; - let latest_version = "0.96.4"; let temp_dir = assert_fs::TempDir::new()?; - let node_data_dir = temp_dir.child("data"); + let node_data_dir = temp_dir.child("antnode1"); node_data_dir.create_dir_all()?; let node_logs_dir = temp_dir.child("logs"); node_logs_dir.create_dir_all()?; @@ -928,17 +975,15 @@ async fn add_node_should_update_the_environment_variables_inside_node_registry() antnode_download_path.write_binary(b"fake antnode bin")?; let mut seq = Sequence::new(); - mock_service_control .expect_get_available_port() .times(1) - .returning(|| Ok(12001)) + .returning(|| Ok(8083)) .in_sequence(&mut seq); let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], - data_dir_path: node_data_dir.to_path_buf().join("antnode1"), - env_variables: env_variables.clone(), + data_dir_path: node_data_dir.to_path_buf().join("antnode2"), + env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { rpc_url_http: "http://localhost:8545".parse()?, payment_token_address: RewardsAddress::from_str( @@ -948,28 +993,29 @@ async fn add_node_should_update_the_environment_variables_inside_node_registry() "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, - log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), + log_dir_path: node_logs_dir.to_path_buf().join("antnode2"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - name: "antnode1".to_string(), + network_id: None, + name: "antnode2".to_string(), node_ip: None, node_port: None, - owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, - rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8083), + owner: None, antnode_path: node_data_dir .to_path_buf() - .join("antnode1") + .join("antnode2") .join(ANTNODE_FILE_NAME), service_user: Some(get_username()), upnp: false, } .build()?; + mock_service_control .expect_install() .times(1) @@ -981,25 +1027,24 @@ async fn add_node_should_update_the_environment_variables_inside_node_registry() AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, - env_variables: env_variables.clone(), - genesis: false, + env_variables: None, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, - antnode_dir_path: temp_dir.to_path_buf(), antnode_src_path: antnode_download_path.to_path_buf(), + antnode_dir_path: temp_dir.to_path_buf(), service_data_dir_path: node_data_dir.to_path_buf(), service_log_dir_path: node_logs_dir.to_path_buf(), upnp: false, @@ -1025,94 +1070,1128 @@ async fn add_node_should_update_the_environment_variables_inside_node_registry() ) .await?; - antnode_download_path.assert(predicate::path::missing()); - node_data_dir.assert(predicate::path::is_dir()); - node_logs_dir.assert(predicate::path::is_dir()); - - assert_eq!(node_registry.environment_variables, env_variables); - - assert_eq!(node_registry.nodes.len(), 1); - assert_eq!(node_registry.nodes[0].version, latest_version); - assert_eq!(node_registry.nodes[0].service_name, "antnode1"); - assert_eq!(node_registry.nodes[0].user, Some(get_username())); - assert_eq!(node_registry.nodes[0].number, 1); + assert_eq!(node_registry.nodes.len(), 2); + assert_eq!(node_registry.nodes[1].version, latest_version); + assert_eq!(node_registry.nodes[1].service_name, "antnode2"); + assert_eq!(node_registry.nodes[1].user, Some(get_username())); + assert_eq!(node_registry.nodes[1].number, 2); assert_eq!( - node_registry.nodes[0].rpc_socket_addr, - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001) + node_registry.nodes[1].rpc_socket_addr, + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8083) ); assert_eq!( - node_registry.nodes[0].log_dir_path, - node_logs_dir.to_path_buf().join("antnode1") + node_registry.nodes[1].log_dir_path, + node_logs_dir.to_path_buf().join("antnode2") + ); + assert_eq!( + node_registry.nodes[1].data_dir_path, + node_data_dir.to_path_buf().join("antnode2") ); + assert_matches!(node_registry.nodes[0].status, ServiceStatus::Added); + assert!(!node_registry.nodes[0].auto_restart); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_first_arg() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: true, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--first"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert!(node_registry.nodes[0].peers_args.first); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_peers_args() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![ + "/ip4/127.0.0.1/tcp/8080/p2p/12D3KooWRBhwfeP2Y4TCx1SM6s9rUoHhR5STiGwxBhgFRcw3UERE" + .parse()?, + ], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--peer"), + OsString::from( + "/ip4/127.0.0.1/tcp/8080/p2p/12D3KooWRBhwfeP2Y4TCx1SM6s9rUoHhR5STiGwxBhgFRcw3UERE"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert_eq!(node_registry.nodes[0].peers_args.addrs.len(), 1); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_local_arg() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: true, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--local"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert!(node_registry.nodes[0].peers_args.local); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_network_contacts_url_arg() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![ + "http://localhost:8080/contacts".to_string(), + "http://localhost:8081/contacts".to_string(), + ], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--network-contacts-url"), + OsString::from("http://localhost:8080/contacts,http://localhost:8081/contacts"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert_eq!( + node_registry.nodes[0].peers_args.network_contacts_url.len(), + 2 + ); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_testnet_arg() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: true, + ignore_cache: false, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--testnet"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert!(node_registry.nodes[0].peers_args.disable_mainnet_contacts); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_ignore_cache_arg() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: true, + bootstrap_cache_dir: None, + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--ignore-cache"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); + assert!(node_registry.nodes[0].peers_args.ignore_cache); + + Ok(()) +} + +#[tokio::test] +async fn add_node_should_create_service_file_with_custom_bootstrap_cache_path() -> Result<()> { + let tmp_data_dir = assert_fs::TempDir::new()?; + let node_reg_path = tmp_data_dir.child("node_reg.json"); + + let mut mock_service_control = MockServiceControl::new(); + + let mut node_registry = NodeRegistry { + auditor: None, + faucet: None, + save_path: node_reg_path.to_path_buf(), + nat_status: None, + nodes: vec![], + environment_variables: None, + daemon: None, + }; + let latest_version = "0.96.4"; + let temp_dir = assert_fs::TempDir::new()?; + let node_data_dir = temp_dir.child("data"); + node_data_dir.create_dir_all()?; + let node_logs_dir = temp_dir.child("logs"); + node_logs_dir.create_dir_all()?; + let antnode_download_path = temp_dir.child(ANTNODE_FILE_NAME); + antnode_download_path.write_binary(b"fake antnode bin")?; + + let peers_args = PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: Some(PathBuf::from("/path/to/bootstrap/cache")), + }; + + let mut seq = Sequence::new(); + + mock_service_control + .expect_get_available_port() + .times(1) + .returning(|| Ok(12001)) + .in_sequence(&mut seq); + + mock_service_control + .expect_install() + .times(1) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--bootstrap-cache-dir"), + OsString::from("/path/to/bootstrap/cache"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) + .returning(|_, _| Ok(())) + .in_sequence(&mut seq); + + add_node( + AddNodeServiceOptions { + auto_restart: false, + auto_set_nat_flags: false, + count: None, + delete_antnode_src: true, + enable_metrics_server: false, + env_variables: None, + home_network: false, + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + owner: None, + peers_args: peers_args.clone(), + rpc_address: None, + rpc_port: None, + antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), + service_data_dir_path: node_data_dir.to_path_buf(), + service_log_dir_path: node_logs_dir.to_path_buf(), + upnp: false, + user: Some(get_username()), + user_mode: false, + version: latest_version.to_string(), + evm_network: EvmNetwork::Custom(CustomNetwork { + rpc_url_http: "http://localhost:8545".parse()?, + payment_token_address: RewardsAddress::from_str( + "0x5FbDB2315678afecb367f032d93F642f64180aa3", + )?, + data_payments_address: RewardsAddress::from_str( + "0x8464135c8F25Da09e49BC8782676a84730C318bC", + )?, + }), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + }, + &mut node_registry, + &mock_service_control, + VerbosityLevel::Normal, + ) + .await?; + + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].peers_args, peers_args); assert_eq!( - node_registry.nodes[0].data_dir_path, - node_data_dir.to_path_buf().join("antnode1") + node_registry.nodes[0].peers_args.bootstrap_cache_dir, + Some(PathBuf::from("/path/to/bootstrap/cache")) ); - assert_matches!(node_registry.nodes[0].status, ServiceStatus::Added); Ok(()) } #[tokio::test] -async fn add_new_node_should_add_another_service() -> Result<()> { +async fn add_node_should_create_service_file_with_network_id() -> Result<()> { let tmp_data_dir = assert_fs::TempDir::new()?; let node_reg_path = tmp_data_dir.child("node_reg.json"); let mut mock_service_control = MockServiceControl::new(); - let latest_version = "0.96.4"; let mut node_registry = NodeRegistry { auditor: None, faucet: None, save_path: node_reg_path.to_path_buf(), nat_status: None, - nodes: vec![NodeServiceData { - auto_restart: false, - connected_peers: None, - data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), - evm_network: EvmNetwork::Custom(CustomNetwork { - rpc_url_http: "http://localhost:8545".parse()?, - payment_token_address: RewardsAddress::from_str( - "0x5FbDB2315678afecb367f032d93F642f64180aa3", - )?, - data_payments_address: RewardsAddress::from_str( - "0x8464135c8F25Da09e49BC8782676a84730C318bC", - )?, - }), - genesis: true, - home_network: false, - listen_addr: None, - local: false, - log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), - log_format: None, - max_archived_log_files: None, - max_log_files: None, - metrics_port: None, - node_ip: None, - node_port: None, - number: 1, - owner: None, - peer_id: None, - pid: None, - rewards_address: RewardsAddress::from_str( - "0x03B770D9cD32077cC0bF330c13C114a87643B124", - )?, - reward_balance: Some(AttoTokens::zero()), - rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), - antnode_path: PathBuf::from("/var/antctl/services/antnode1/antnode"), - service_name: "antnode1".to_string(), - status: ServiceStatus::Added, - upnp: false, - user: Some("ant".to_string()), - user_mode: false, - version: latest_version.to_string(), - }], - bootstrap_peers: vec![], + nodes: vec![], environment_variables: None, daemon: None, }; + let latest_version = "0.96.4"; let temp_dir = assert_fs::TempDir::new()?; - let node_data_dir = temp_dir.child("antnode1"); + let node_data_dir = temp_dir.child("data"); node_data_dir.create_dir_all()?; let node_logs_dir = temp_dir.child("logs"); node_logs_dir.create_dir_all()?; @@ -1120,52 +2199,62 @@ async fn add_new_node_should_add_another_service() -> Result<()> { antnode_download_path.write_binary(b"fake antnode bin")?; let mut seq = Sequence::new(); + mock_service_control .expect_get_available_port() .times(1) - .returning(|| Ok(8083)) + .returning(|| Ok(12001)) .in_sequence(&mut seq); - let install_ctx = InstallNodeServiceCtxBuilder { - autostart: false, - bootstrap_peers: vec![], - data_dir_path: node_data_dir.to_path_buf().join("antnode2"), - env_variables: None, - evm_network: EvmNetwork::Custom(CustomNetwork { - rpc_url_http: "http://localhost:8545".parse()?, - payment_token_address: RewardsAddress::from_str( - "0x5FbDB2315678afecb367f032d93F642f64180aa3", - )?, - data_payments_address: RewardsAddress::from_str( - "0x8464135c8F25Da09e49BC8782676a84730C318bC", - )?, - }), - genesis: false, - home_network: false, - local: false, - log_dir_path: node_logs_dir.to_path_buf().join("antnode2"), - log_format: None, - max_archived_log_files: None, - max_log_files: None, - metrics_port: None, - name: "antnode2".to_string(), - node_ip: None, - node_port: None, - rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, - rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8083), - owner: None, - antnode_path: node_data_dir - .to_path_buf() - .join("antnode2") - .join(ANTNODE_FILE_NAME), - service_user: Some(get_username()), - upnp: false, - } - .build()?; mock_service_control .expect_install() .times(1) - .with(eq(install_ctx), eq(false)) + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:12001"), + OsString::from("--root-dir"), + OsString::from( + node_data_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--log-output-dest"), + OsString::from( + node_logs_dir + .to_path_buf() + .join("antnode1") + .to_string_lossy() + .to_string(), + ), + OsString::from("--network-id"), + OsString::from("5"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-custom"), + OsString::from("--rpc-url"), + OsString::from("http://localhost:8545/"), + OsString::from("--payment-token-address"), + OsString::from("0x5FbDB2315678afecb367f032d93F642f64180aa3"), + OsString::from("--data-payments-address"), + OsString::from("0x8464135c8F25Da09e49BC8782676a84730C318bC"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: node_data_dir + .to_path_buf() + .join("antnode1") + .join(ANTNODE_FILE_NAME), + username: Some(get_username()), + working_directory: None, + }), + eq(false), + ) .returning(|_, _| Ok(())) .in_sequence(&mut seq); @@ -1173,25 +2262,24 @@ async fn add_new_node_should_add_another_service() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: Some(5), node_ip: None, node_port: None, + owner: None, + peers_args: Default::default(), rpc_address: None, rpc_port: None, - antnode_src_path: antnode_download_path.to_path_buf(), antnode_dir_path: temp_dir.to_path_buf(), + antnode_src_path: antnode_download_path.to_path_buf(), service_data_dir_path: node_data_dir.to_path_buf(), service_log_dir_path: node_logs_dir.to_path_buf(), upnp: false, @@ -1217,25 +2305,12 @@ async fn add_new_node_should_add_another_service() -> Result<()> { ) .await?; - assert_eq!(node_registry.nodes.len(), 2); - assert_eq!(node_registry.nodes[1].version, latest_version); - assert_eq!(node_registry.nodes[1].service_name, "antnode2"); - assert_eq!(node_registry.nodes[1].user, Some(get_username())); - assert_eq!(node_registry.nodes[1].number, 2); - assert_eq!( - node_registry.nodes[1].rpc_socket_addr, - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8083) - ); - assert_eq!( - node_registry.nodes[1].log_dir_path, - node_logs_dir.to_path_buf().join("antnode2") - ); - assert_eq!( - node_registry.nodes[1].data_dir_path, - node_data_dir.to_path_buf().join("antnode2") - ); - assert_matches!(node_registry.nodes[0].status, ServiceStatus::Added); - assert!(!node_registry.nodes[0].auto_restart); + antnode_download_path.assert(predicate::path::missing()); + node_data_dir.assert(predicate::path::is_dir()); + node_logs_dir.assert(predicate::path::is_dir()); + assert_eq!(node_registry.nodes.len(), 1); + assert_eq!(node_registry.nodes[0].version, latest_version); + assert_eq!(node_registry.nodes[0].network_id, Some(5)); Ok(()) } @@ -1253,7 +2328,6 @@ async fn add_node_should_use_custom_ip() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -1332,21 +2406,20 @@ async fn add_node_should_use_custom_ip() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: Some(custom_ip), node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -1399,7 +2472,6 @@ async fn add_node_should_use_custom_ports_for_one_service() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -1423,7 +2495,6 @@ async fn add_node_should_use_custom_ports_for_one_service() -> Result<()> { .in_sequence(&mut seq); let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -1435,18 +2506,18 @@ async fn add_node_should_use_custom_ports_for_one_service() -> Result<()> { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: Some(custom_port), owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), antnode_path: node_data_dir @@ -1469,21 +2540,20 @@ async fn add_node_should_use_custom_ports_for_one_service() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Single(custom_port)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -1536,7 +2606,6 @@ async fn add_node_should_use_a_custom_port_range() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -1729,21 +2798,20 @@ async fn add_node_should_use_a_custom_port_range() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Range(12000, 12002)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -1807,20 +2875,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_is_used() -> R "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_format: None, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: Some(12000), number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1835,7 +2903,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_is_used() -> R user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -1852,21 +2919,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_is_used() -> R AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Single(12000)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -1928,19 +2994,19 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_in_range_is_us "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_format: None, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: Some(12000), - number: 1, owner: None, + peers_args: PeersArgs::default(), + number: 1, peer_id: None, pid: None, rewards_address: RewardsAddress::from_str( @@ -1956,7 +3022,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_in_range_is_us user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -1973,21 +3038,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_port_in_range_is_us AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Range(12000, 12002)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2037,7 +3101,6 @@ async fn add_node_should_return_an_error_if_port_and_node_count_do_not_match() - save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2054,21 +3117,20 @@ async fn add_node_should_return_an_error_if_port_and_node_count_do_not_match() - AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(2), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Range(12000, 12002)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_src_path: antnode_download_path.to_path_buf(), @@ -2123,7 +3185,6 @@ async fn add_node_should_return_an_error_if_multiple_services_are_specified_with save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2140,21 +3201,20 @@ async fn add_node_should_return_an_error_if_multiple_services_are_specified_with AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(2), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: Some(PortRange::Single(12000)), + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2210,7 +3270,6 @@ async fn add_node_should_set_random_ports_if_enable_metrics_server_is_true() -> save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2288,21 +3347,20 @@ async fn add_node_should_set_random_ports_if_enable_metrics_server_is_true() -> AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: true, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2349,7 +3407,6 @@ async fn add_node_should_set_max_archived_log_files() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2428,21 +3485,20 @@ async fn add_node_should_set_max_archived_log_files() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: Some(20), max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2490,7 +3546,6 @@ async fn add_node_should_set_max_log_files() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2569,21 +3624,20 @@ async fn add_node_should_set_max_log_files() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: Some(20), metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2631,7 +3685,6 @@ async fn add_node_should_use_a_custom_port_range_for_metrics_server() -> Result< save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2824,21 +3877,20 @@ async fn add_node_should_use_a_custom_port_range_for_metrics_server() -> Result< AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(PortRange::Range(12000, 12002)), - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -2899,20 +3951,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_is_use "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(12000), + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2927,7 +3979,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_is_use user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -2944,21 +3995,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_is_use AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(PortRange::Single(12000)), - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -3021,20 +4071,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_in_ran "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(12000), + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3049,7 +4099,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_in_ran user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3066,21 +4115,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_metrics_port_in_ran AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(PortRange::Range(12000, 12002)), - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -3132,7 +4180,6 @@ async fn add_node_should_use_a_custom_port_range_for_the_rpc_server() -> Result< save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3304,21 +4351,20 @@ async fn add_node_should_use_a_custom_port_range_for_the_rpc_server() -> Result< AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(3), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: Some(PortRange::Range(20000, 20002)), antnode_dir_path: temp_dir.to_path_buf(), @@ -3390,20 +4436,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_is_used() "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3418,7 +4464,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_is_used() user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3435,21 +4480,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_is_used() AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: Some(PortRange::Single(8081)), antnode_dir_path: temp_dir.to_path_buf(), @@ -3512,20 +4556,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_in_range_i "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3540,7 +4584,6 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_in_range_i user_mode: false, version: "0.98.1".to_string(), }], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3557,21 +4600,20 @@ async fn add_node_should_return_an_error_if_duplicate_custom_rpc_port_in_range_i AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(2), delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: Some(PortRange::Range(8081, 8082)), antnode_dir_path: temp_dir.to_path_buf(), @@ -3623,7 +4665,6 @@ async fn add_node_should_disable_upnp_and_home_network_if_nat_status_is_public() save_path: node_reg_path.to_path_buf(), nat_status: Some(NatDetectionStatus::Public), nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3646,7 +4687,6 @@ async fn add_node_should_disable_upnp_and_home_network_if_nat_status_is_public() let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -3658,18 +4698,18 @@ async fn add_node_should_disable_upnp_and_home_network_if_nat_status_is_public() "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), antnode_path: node_data_dir @@ -3691,21 +4731,20 @@ async fn add_node_should_disable_upnp_and_home_network_if_nat_status_is_public() AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: true, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - local: false, - genesis: false, home_network: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -3754,7 +4793,6 @@ async fn add_node_should_enable_upnp_if_nat_status_is_upnp() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: Some(NatDetectionStatus::UPnP), nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3777,7 +4815,6 @@ async fn add_node_should_enable_upnp_if_nat_status_is_upnp() -> Result<()> { let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -3789,18 +4826,18 @@ async fn add_node_should_enable_upnp_if_nat_status_is_upnp() -> Result<()> { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), antnode_path: node_data_dir @@ -3822,21 +4859,20 @@ async fn add_node_should_enable_upnp_if_nat_status_is_upnp() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: true, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - local: false, - genesis: false, home_network: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -3885,7 +4921,6 @@ async fn add_node_should_enable_home_network_if_nat_status_is_private() -> Resul save_path: node_reg_path.to_path_buf(), nat_status: Some(NatDetectionStatus::Private), nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -3908,7 +4943,6 @@ async fn add_node_should_enable_home_network_if_nat_status_is_private() -> Resul let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -3920,18 +4954,18 @@ async fn add_node_should_enable_home_network_if_nat_status_is_private() -> Resul "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: true, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12001), antnode_path: node_data_dir @@ -3953,21 +4987,20 @@ async fn add_node_should_enable_home_network_if_nat_status_is_private() -> Resul AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: true, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - local: false, - genesis: false, home_network: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -4017,7 +5050,6 @@ async fn add_node_should_return_an_error_if_nat_status_is_none_but_auto_set_nat_ save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -4042,21 +5074,20 @@ async fn add_node_should_return_an_error_if_nat_status_is_none_but_auto_set_nat_ AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: true, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - local: false, - genesis: false, home_network: true, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -4115,7 +5146,6 @@ async fn add_auditor_should_add_an_auditor_service() -> Result<()> { auditor_download_path.write_binary(b"fake auditor bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: None, faucet: None, @@ -4150,7 +5180,6 @@ async fn add_auditor_should_add_an_auditor_service() -> Result<()> { add_auditor( AddAuditorServiceOptions { - bootstrap_peers: vec![], beta_encryption_key: None, env_variables: Some(vec![("ANT_LOG".to_string(), "all".to_string())]), auditor_src_bin_path: auditor_download_path.to_path_buf(), @@ -4202,7 +5231,6 @@ async fn add_auditor_should_return_an_error_if_a_auditor_service_was_already_cre auditor_download_path.write_binary(b"fake auditor bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: Some(AuditorServiceData { auditor_path: auditor_download_path.to_path_buf(), @@ -4222,7 +5250,6 @@ async fn add_auditor_should_return_an_error_if_a_auditor_service_was_already_cre let result = add_auditor( AddAuditorServiceOptions { - bootstrap_peers: vec![], beta_encryption_key: None, env_variables: Some(vec![("ANT_LOG".to_string(), "all".to_string())]), auditor_src_bin_path: auditor_download_path.to_path_buf(), @@ -4265,7 +5292,6 @@ async fn add_auditor_should_include_beta_encryption_key_if_specified() -> Result auditor_download_path.write_binary(b"fake auditor bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: None, faucet: None, @@ -4302,7 +5328,6 @@ async fn add_auditor_should_include_beta_encryption_key_if_specified() -> Result add_auditor( AddAuditorServiceOptions { - bootstrap_peers: vec![], beta_encryption_key: Some("test".to_string()), env_variables: Some(vec![("ANT_LOG".to_string(), "all".to_string())]), auditor_src_bin_path: auditor_download_path.to_path_buf(), @@ -4355,7 +5380,6 @@ async fn add_faucet_should_add_a_faucet_service() -> Result<()> { faucet_download_path.write_binary(b"fake faucet bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: None, faucet: None, @@ -4391,7 +5415,6 @@ async fn add_faucet_should_add_a_faucet_service() -> Result<()> { add_faucet( AddFaucetServiceOptions { - bootstrap_peers: vec![], env_variables: Some(vec![("ANT_LOG".to_string(), "all".to_string())]), faucet_src_bin_path: faucet_download_path.to_path_buf(), faucet_install_bin_path: faucet_install_path.to_path_buf(), @@ -4443,7 +5466,6 @@ async fn add_faucet_should_return_an_error_if_a_faucet_service_was_already_creat faucet_download_path.write_binary(b"fake faucet bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: None, faucet: Some(FaucetServiceData { @@ -4464,7 +5486,6 @@ async fn add_faucet_should_return_an_error_if_a_faucet_service_was_already_creat let result = add_faucet( AddFaucetServiceOptions { - bootstrap_peers: vec![], env_variables: Some(vec![("ANT_LOG".to_string(), "all".to_string())]), faucet_src_bin_path: faucet_download_path.to_path_buf(), faucet_install_bin_path: faucet_install_path.to_path_buf(), @@ -4506,7 +5527,6 @@ async fn add_daemon_should_add_a_daemon_service() -> Result<()> { daemon_download_path.write_binary(b"fake daemon bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: None, auditor: None, faucet: None, @@ -4584,7 +5604,6 @@ async fn add_daemon_should_return_an_error_if_a_daemon_service_was_already_creat daemon_download_path.write_binary(b"fake daemon bin")?; let mut node_registry = NodeRegistry { - bootstrap_peers: vec![], daemon: Some(DaemonServiceData { daemon_path: PathBuf::from("/usr/local/bin/antctld"), endpoint: Some(SocketAddr::new( @@ -4644,7 +5663,6 @@ async fn add_node_should_not_delete_the_source_binary_if_path_arg_is_used() -> R save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -4669,7 +5687,6 @@ async fn add_node_should_not_delete_the_source_binary_if_path_arg_is_used() -> R let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -4681,18 +5698,18 @@ async fn add_node_should_not_delete_the_source_binary_if_path_arg_is_used() -> R "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir @@ -4715,21 +5732,20 @@ async fn add_node_should_not_delete_the_source_binary_if_path_arg_is_used() -> R AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -4777,7 +5793,6 @@ async fn add_node_should_apply_the_home_network_flag_if_it_is_used() -> Result<( save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -4802,12 +5817,9 @@ async fn add_node_should_apply_the_home_network_flag_if_it_is_used() -> Result<( let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, - genesis: false, home_network: true, - local: false, evm_network: EvmNetwork::Custom(CustomNetwork { rpc_url_http: "http://localhost:8545".parse()?, payment_token_address: RewardsAddress::from_str( @@ -4822,10 +5834,12 @@ async fn add_node_should_apply_the_home_network_flag_if_it_is_used() -> Result<( max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir @@ -4848,21 +5862,20 @@ async fn add_node_should_apply_the_home_network_flag_if_it_is_used() -> Result<( AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: true, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -4910,7 +5923,6 @@ async fn add_node_should_add_the_node_in_user_mode() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -4935,7 +5947,6 @@ async fn add_node_should_add_the_node_in_user_mode() -> Result<()> { let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -4947,18 +5958,18 @@ async fn add_node_should_add_the_node_in_user_mode() -> Result<()> { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: true, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir @@ -4981,21 +5992,20 @@ async fn add_node_should_add_the_node_in_user_mode() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: true, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -5041,7 +6051,6 @@ async fn add_node_should_add_the_node_with_upnp_enabled() -> Result<()> { save_path: node_reg_path.to_path_buf(), nat_status: None, nodes: vec![], - bootstrap_peers: vec![], environment_variables: None, daemon: None, }; @@ -5065,7 +6074,6 @@ async fn add_node_should_add_the_node_with_upnp_enabled() -> Result<()> { let install_ctx = InstallNodeServiceCtxBuilder { autostart: false, - bootstrap_peers: vec![], data_dir_path: node_data_dir.to_path_buf().join("antnode1"), env_variables: None, evm_network: EvmNetwork::Custom(CustomNetwork { @@ -5077,18 +6085,18 @@ async fn add_node_should_add_the_node_with_upnp_enabled() -> Result<()> { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: true, - local: false, log_dir_path: node_logs_dir.to_path_buf().join("antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, name: "antnode1".to_string(), node_ip: None, node_port: None, owner: None, + peers_args: PeersArgs::default(), rewards_address: RewardsAddress::from_str("0x03B770D9cD32077cC0bF330c13C114a87643B124")?, rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), antnode_path: node_data_dir @@ -5111,21 +6119,20 @@ async fn add_node_should_add_the_node_with_upnp_enabled() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: Some(1), delete_antnode_src: false, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: true, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: None, + network_id: None, node_ip: None, node_port: None, + owner: None, + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -5177,7 +6184,6 @@ async fn add_node_should_assign_an_owner_in_lowercase() -> Result<()> { let mut node_registry = NodeRegistry { auditor: None, - bootstrap_peers: vec![], daemon: None, environment_variables: None, faucet: None, @@ -5250,21 +6256,20 @@ async fn add_node_should_assign_an_owner_in_lowercase() -> Result<()> { AddNodeServiceOptions { auto_restart: false, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: Some("Discord_Username".to_string()), + network_id: None, node_ip: None, node_port: None, + owner: Some("Discord_Username".to_string()), + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), @@ -5318,7 +6323,6 @@ async fn add_node_should_auto_restart() -> Result<()> { let mut node_registry = NodeRegistry { auditor: None, - bootstrap_peers: vec![], daemon: None, environment_variables: None, faucet: None, @@ -5391,21 +6395,20 @@ async fn add_node_should_auto_restart() -> Result<()> { AddNodeServiceOptions { auto_restart: true, auto_set_nat_flags: false, - bootstrap_peers: vec![], count: None, delete_antnode_src: true, enable_metrics_server: false, env_variables: None, - genesis: false, home_network: false, - local: false, log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, - owner: Some("discord_username".to_string()), + network_id: None, node_ip: None, node_port: None, + owner: Some("discord_username".to_string()), + peers_args: PeersArgs::default(), rpc_address: None, rpc_port: None, antnode_dir_path: temp_dir.to_path_buf(), diff --git a/ant-node-manager/src/bin/cli/main.rs b/ant-node-manager/src/bin/cli/main.rs index 14b84e55f7..b440cb09d8 100644 --- a/ant-node-manager/src/bin/cli/main.rs +++ b/ant-node-manager/src/bin/cli/main.rs @@ -172,6 +172,11 @@ pub enum SubCmd { /// services, which in this case would be 5. The range must also go from lower to higher. #[clap(long, value_parser = PortRange::parse)] metrics_port: Option, + /// Specify the network ID to use for the services. 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 IP address for the antnode service(s). /// /// If not set, we bind to all the available network interfaces. @@ -1075,6 +1080,7 @@ async fn main() -> Result<()> { max_archived_log_files, max_log_files, metrics_port, + network_id, node_ip, node_port, owner, @@ -1097,12 +1103,12 @@ async fn main() -> Result<()> { env_variables, Some(evm_network.try_into()?), home_network, - peers.local, log_dir_path, log_format, max_archived_log_files, max_log_files, metrics_port, + network_id, node_ip, node_port, owner, diff --git a/ant-node-manager/src/cmd/local.rs b/ant-node-manager/src/cmd/local.rs index cdf0bd375c..2f0b3b465b 100644 --- a/ant-node-manager/src/cmd/local.rs +++ b/ant-node-manager/src/cmd/local.rs @@ -36,7 +36,7 @@ pub async fn join( log_format: Option, owner: Option, owner_prefix: Option, - peers_args: PeersArgs, + _peers_args: PeersArgs, rpc_port: Option, rewards_address: RewardsAddress, evm_network: Option, @@ -70,21 +70,6 @@ pub async fn join( ) .await?; - // If no peers are obtained we will attempt to join the existing local network, if one - // is running. - let peers = match peers_args.get_addrs(None).await { - Ok(peers) => Some(peers), - Err(err) => match err { - ant_bootstrap::error::Error::NoBootstrapPeersFound => { - warn!("PeersNotObtained, peers is set to None"); - None - } - _ => { - error!("Failed to obtain peers: {err:?}"); - return Err(err.into()); - } - }, - }; let options = LocalNetworkOptions { antnode_bin_path, enable_metrics_server, @@ -95,7 +80,7 @@ pub async fn join( node_port, owner, owner_prefix, - peers, + peers: None, rpc_port, skip_validation, log_format, diff --git a/ant-node-manager/src/cmd/node.rs b/ant-node-manager/src/cmd/node.rs index d21de2b45e..5ab42c0ea8 100644 --- a/ant-node-manager/src/cmd/node.rs +++ b/ant-node-manager/src/cmd/node.rs @@ -44,16 +44,16 @@ pub async fn add( env_variables: Option>, evm_network: Option, home_network: bool, - local: bool, log_dir_path: Option, log_format: Option, max_archived_log_files: Option, max_log_files: Option, metrics_port: Option, + network_id: Option, node_ip: Option, node_port: Option, owner: Option, - peers_args: PeersArgs, + mut peers_args: PeersArgs, rewards_address: RewardsAddress, rpc_address: Option, rpc_port: Option, @@ -84,6 +84,11 @@ pub async fn add( config::get_service_data_dir_path(data_dir_path, service_user.clone())?; let service_log_dir_path = config::get_service_log_dir_path(ReleaseType::AntNode, log_dir_path, service_user.clone())?; + let bootstrap_cache_dir = if let Some(user) = &service_user { + Some(config::get_bootstrap_cache_owner_path(user)?) + } else { + None + }; let mut node_registry = NodeRegistry::load(&config::get_node_registry_path()?)?; let release_repo = ::default_config(); @@ -105,54 +110,27 @@ pub async fn add( debug!("Parsing peers from PeersArgs"); - // Handle the `PeersNotObtained` error to make the `--peer` argument optional for the node - // manager. - // - // Since any application making use of the node manager can enable the `network-contacts` feature on - // ant_peers_acquisition, we might end up getting having a huge peer list, and that's problematic for - // service definition files. - // Thus make use of get_peers_exclude_network_contacts() instead of get_peers() to make sure we only - // parse the --peers and ANT_PEERS env var. - - // If the `antnode` binary we're using has `network-contacts` enabled (which is the case for released binaries), - // it's fine if the service definition doesn't call `antnode` with a `--peer` argument. - let is_first = peers_args.first; - let bootstrap_peers = match peers_args.get_addrs(None).await { - Ok(peers) => { - info!("Obtained peers of length {}", peers.len()); - peers.into_iter().take(10).collect::>() - } - Err(err) => match err { - ant_bootstrap::error::Error::NoBootstrapPeersFound => { - info!("No bootstrap peers obtained, setting empty vec."); - Vec::new() - } - _ => { - error!("Error obtaining peers: {err:?}"); - return Err(err.into()); - } - }, - }; + peers_args.addrs.extend(PeersArgs::read_addr_from_env()); + peers_args.bootstrap_cache_dir = bootstrap_cache_dir; let options = AddNodeServiceOptions { auto_restart, auto_set_nat_flags, - bootstrap_peers, count, delete_antnode_src: src_path.is_none(), enable_metrics_server, evm_network: evm_network.unwrap_or(EvmNetwork::ArbitrumOne), env_variables, - genesis: is_first, home_network, - local, log_format, max_archived_log_files, max_log_files, metrics_port, + network_id, node_ip, node_port, owner, + peers_args, rewards_address, rpc_address, rpc_port, @@ -535,7 +513,6 @@ pub async fn upgrade( }; let options = UpgradeOptions { auto_restart: false, - bootstrap_peers: node_registry.bootstrap_peers.clone(), env_variables: env_variables.clone(), force: use_force, start_service: !do_not_start, @@ -613,16 +590,16 @@ pub async fn maintain_n_running_nodes( env_variables: Option>, evm_network: Option, home_network: bool, - local: bool, log_dir_path: Option, log_format: Option, max_archived_log_files: Option, max_log_files: Option, metrics_port: Option, + network_id: Option, node_ip: Option, node_port: Option, owner: Option, - peers: PeersArgs, + peers_args: PeersArgs, rewards_address: RewardsAddress, rpc_address: Option, rpc_port: Option, @@ -718,16 +695,16 @@ pub async fn maintain_n_running_nodes( env_variables.clone(), evm_network.clone(), home_network, - local, log_dir_path.clone(), log_format, max_archived_log_files, max_log_files, metrics_port.clone(), + network_id, node_ip, Some(PortRange::Single(port)), owner.clone(), - peers.clone(), + peers_args.clone(), rewards_address, rpc_address, rpc_port.clone(), diff --git a/ant-node-manager/src/config.rs b/ant-node-manager/src/config.rs index f0c47f7ab2..946afdf5ab 100644 --- a/ant-node-manager/src/config.rs +++ b/ant-node-manager/src/config.rs @@ -159,6 +159,22 @@ pub fn get_service_data_dir_path( Ok(path) } +/// Get the bootstrap cache owner path +#[cfg(unix)] +pub fn get_bootstrap_cache_owner_path(owner: &str) -> Result { + let path = PathBuf::from("/var/antctl/bootstrap_cache"); + + create_owned_dir(path.clone(), owner)?; + Ok(path) +} + +#[cfg(windows)] +pub fn get_bootstrap_cache_owner_path(_owner: &str) -> Result { + let path = PathBuf::from("C:\\ProgramData\\antctl\\bootstrap_cache"); + std::fs::create_dir_all(&path)?; + Ok(path) +} + /// Get the logging directory for the service. /// /// It's a little counter-intuitive, but the owner will be `None` in the case of a user-mode diff --git a/ant-node-manager/src/lib.rs b/ant-node-manager/src/lib.rs index 696eb93463..8b2aaee95b 100644 --- a/ant-node-manager/src/lib.rs +++ b/ant-node-manager/src/lib.rs @@ -649,6 +649,7 @@ fn format_status_without_colour(status: &ServiceStatus) -> String { #[cfg(test)] mod tests { use super::*; + use ant_bootstrap::PeersArgs; use ant_evm::{AttoTokens, CustomNetwork, EvmNetwork, RewardsAddress}; use ant_logging::LogFormat; use ant_service_management::{ @@ -759,20 +760,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -873,15 +874,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -889,6 +889,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -952,15 +953,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -968,6 +968,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1071,15 +1072,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1087,6 +1087,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1163,20 +1164,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1265,20 +1266,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1366,20 +1367,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1437,15 +1438,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1453,6 +1453,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1500,20 +1501,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1561,15 +1562,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1577,6 +1577,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1625,20 +1626,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, peer_id: None, + peers_args: PeersArgs::default(), pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1700,15 +1701,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1716,6 +1716,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1840,15 +1841,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1856,6 +1856,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1880,7 +1881,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -1942,15 +1942,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -1958,6 +1957,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -1983,7 +1983,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -2089,15 +2088,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -2105,6 +2103,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2130,7 +2129,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: true, start_service: true, @@ -2248,15 +2246,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -2264,6 +2261,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2289,7 +2287,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: false, @@ -2402,15 +2399,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -2418,6 +2414,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2442,7 +2439,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -2557,15 +2553,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -2573,6 +2568,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2598,7 +2594,6 @@ mod tests { let upgrade_result = service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -2630,6 +2625,1392 @@ mod tests { Ok(()) } + #[tokio::test] + async fn upgrade_should_retain_the_first_flag() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--first"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: true, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert!(service_manager.service.service_data.peers_args.first); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_peers_arg() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--peer"), + OsString::from( + "/ip4/127.0.0.1/tcp/8080/p2p/12D3KooWRBhwfeP2Y4TCx1SM6s9rUoHhR5STiGwxBhgFRcw3UERE" + ), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, +network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![ + "/ip4/127.0.0.1/tcp/8080/p2p/12D3KooWRBhwfeP2Y4TCx1SM6s9rUoHhR5STiGwxBhgFRcw3UERE" + .parse()?, + ], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert!(!service_manager + .service + .service_data + .peers_args + .addrs + .is_empty()); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_network_id_arg() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--network-id"), + OsString::from("5"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: Some(5), + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: Default::default(), + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert_eq!(service_manager.service.service_data.network_id, Some(5)); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_local_flag() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--local"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: true, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert!(service_manager.service.service_data.peers_args.local); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_network_contacts_url_arg() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--network-contacts-url"), + OsString::from("http://localhost:8080/contacts.json,http://localhost:8081/contacts.json"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![ + "http://localhost:8080/contacts.json".to_string(), + "http://localhost:8081/contacts.json".to_string(), + ], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert_eq!( + service_manager + .service + .service_data + .peers_args + .network_contacts_url + .len(), + 2 + ); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_testnet_flag() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--testnet"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: true, + ignore_cache: false, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert!( + service_manager + .service + .service_data + .peers_args + .disable_mainnet_contacts + ); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_ignore_cache_flag() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--ignore-cache"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: true, + bootstrap_cache_dir: None, + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert!(service_manager.service.service_data.peers_args.ignore_cache); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_custom_bootstrap_cache_path() -> Result<()> { + let current_version = "0.1.0"; + let target_version = "0.2.0"; + + let tmp_data_dir = assert_fs::TempDir::new()?; + let current_install_dir = tmp_data_dir.child("antnode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("antnode"); + current_node_bin.write_binary(b"fake antnode binary")?; + let target_node_bin = tmp_data_dir.child("antnode"); + target_node_bin.write_binary(b"fake antnode binary")?; + + let mut mock_service_control = MockServiceControl::new(); + let mut mock_rpc_client = MockRpcClient::new(); + + // before binary upgrade + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(1000)); + mock_service_control + .expect_stop() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_install() + .with( + eq(ServiceInstallCtx { + args: vec![ + OsString::from("--rpc"), + OsString::from("127.0.0.1:8081"), + OsString::from("--root-dir"), + OsString::from("/var/antctl/services/antnode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/antnode/antnode1"), + OsString::from("--bootstrap-cache-dir"), + OsString::from("/var/antctl/services/antnode1/bootstrap_cache"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), + OsString::from("evm-arbitrum-one"), + ], + autostart: false, + contents: None, + environment: None, + label: "antnode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("ant".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("antnode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + mock_service_control + .expect_wait() + .with(eq(3000)) + .times(1) + .returning(|_| ()); + mock_service_control + .expect_get_process_pid() + .with(eq(current_node_bin.to_path_buf().clone())) + .times(1) + .returning(|_| Ok(100)); + + mock_rpc_client.expect_node_info().times(1).returning(|| { + Ok(NodeInfo { + pid: 2000, + peer_id: PeerId::from_str("12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR")?, + data_path: PathBuf::from("/var/antctl/services/antnode1"), + log_path: PathBuf::from("/var/log/antnode/antnode1"), + version: target_version.to_string(), + uptime: std::time::Duration::from_secs(1), // the service was just started + wallet_balance: 0, + }) + }); + mock_rpc_client + .expect_network_info() + .times(1) + .returning(|| { + Ok(NetworkInfo { + connected_peers: Vec::new(), + listeners: Vec::new(), + }) + }); + + let mut service_data = NodeServiceData { + auto_restart: false, + connected_peers: None, + data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), + evm_network: EvmNetwork::ArbitrumOne, + home_network: false, + listen_addr: None, + log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + network_id: None, + node_ip: None, + node_port: None, + number: 1, + owner: None, + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + peers_args: PeersArgs { + first: false, + addrs: vec![], + network_contacts_url: vec![], + local: false, + disable_mainnet_contacts: false, + ignore_cache: false, + bootstrap_cache_dir: Some(PathBuf::from( + "/var/antctl/services/antnode1/bootstrap_cache", + )), + }, + pid: Some(1000), + rewards_address: RewardsAddress::from_str( + "0x03B770D9cD32077cC0bF330c13C114a87643B124", + )?, + reward_balance: Some(AttoTokens::zero()), + rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), + antnode_path: current_node_bin.to_path_buf(), + service_name: "antnode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("ant".to_string()), + user_mode: false, + version: current_version.to_string(), + }; + let service = NodeService::new(&mut service_data, Box::new(mock_rpc_client)); + + let mut service_manager = ServiceManager::new( + service, + Box::new(mock_service_control), + VerbosityLevel::Normal, + ); + + service_manager + .upgrade(UpgradeOptions { + auto_restart: false, + env_variables: None, + force: false, + start_service: true, + target_bin_path: target_node_bin.to_path_buf(), + target_version: Version::parse(target_version).unwrap(), + }) + .await?; + + assert_eq!( + service_manager + .service + .service_data + .peers_args + .bootstrap_cache_dir, + Some(PathBuf::from( + "/var/antctl/services/antnode1/bootstrap_cache" + )) + ); + + Ok(()) + } + #[tokio::test] async fn upgrade_should_retain_the_upnp_flag() -> Result<()> { let current_version = "0.1.0"; @@ -2737,15 +4118,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -2753,6 +4133,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2778,7 +4159,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -2900,15 +4280,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: Some(LogFormat::Json), max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, owner: None, @@ -2916,6 +4295,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -2941,7 +4321,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3066,15 +4445,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: true, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -3082,6 +4460,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3107,7 +4486,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3229,15 +4607,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, number: 1, node_ip: Some(Ipv4Addr::new(192, 168, 1, 1)), node_port: None, @@ -3245,6 +4622,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3270,7 +4648,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3395,15 +4772,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, number: 1, node_ip: None, node_port: Some(12000), @@ -3411,6 +4787,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3436,7 +4813,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3557,15 +4933,14 @@ mod tests { auto_restart: false, connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: Some(20), max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -3573,6 +4948,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), reward_balance: Some(AttoTokens::zero()), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), @@ -3599,7 +4975,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3723,15 +5098,14 @@ mod tests { auto_restart: false, connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: Some(20), metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -3739,6 +5113,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), reward_balance: Some(AttoTokens::zero()), rpc_socket_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081), @@ -3765,7 +5140,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -3887,15 +5261,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(12000), + network_id: None, node_ip: None, node_port: None, number: 1, @@ -3903,6 +5276,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -3928,7 +5302,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4053,15 +5426,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: Some(12000), + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4069,6 +5441,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4094,7 +5467,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4219,15 +5591,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4235,6 +5606,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4260,7 +5632,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4385,15 +5756,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4401,6 +5771,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4426,7 +5797,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: true, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4562,15 +5932,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4578,6 +5947,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4604,7 +5974,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: true, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4740,15 +6109,14 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4756,6 +6124,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4782,7 +6151,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: true, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4906,15 +6274,14 @@ mod tests { connected_peers: None, data_dir_path: PathBuf::from("/var/antctl/services/antnode1"), evm_network: EvmNetwork::ArbitrumOne, - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, @@ -4922,6 +6289,7 @@ mod tests { peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", )?), + peers_args: PeersArgs::default(), pid: Some(1000), rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -4950,7 +6318,6 @@ mod tests { service_manager .upgrade(UpgradeOptions { auto_restart: false, - bootstrap_peers: Vec::new(), env_variables: None, force: false, start_service: true, @@ -4992,21 +6359,21 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: log_dir.to_path_buf(), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, - pid: None, + peers_args: PeersArgs::default(), peer_id: None, + pid: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", )?, @@ -5061,19 +6428,19 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, + peers_args: PeersArgs::default(), pid: Some(1000), peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", @@ -5145,19 +6512,19 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: PathBuf::from("/var/log/antnode/antnode1"), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, + peers_args: PeersArgs::default(), pid: Some(1000), peer_id: Some(PeerId::from_str( "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", @@ -5224,20 +6591,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: log_dir.to_path_buf(), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, pid: None, + peers_args: PeersArgs::default(), peer_id: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", @@ -5301,20 +6668,20 @@ mod tests { "0x8464135c8F25Da09e49BC8782676a84730C318bC", )?, }), - genesis: false, home_network: false, listen_addr: None, - local: false, log_dir_path: log_dir.to_path_buf(), log_format: None, max_archived_log_files: None, max_log_files: None, metrics_port: None, + network_id: None, node_ip: None, node_port: None, number: 1, owner: None, pid: None, + peers_args: PeersArgs::default(), peer_id: None, rewards_address: RewardsAddress::from_str( "0x03B770D9cD32077cC0bF330c13C114a87643B124", diff --git a/ant-node-manager/src/local.rs b/ant-node-manager/src/local.rs index e1fa3d4290..6acd1d6531 100644 --- a/ant-node-manager/src/local.rs +++ b/ant-node-manager/src/local.rs @@ -11,6 +11,7 @@ use crate::helpers::{ check_port_availability, get_bin_version, get_start_port_if_applicable, increment_port_option, }; +use ant_bootstrap::PeersArgs; use ant_evm::{EvmNetwork, RewardsAddress}; use ant_logging::LogFormat; use ant_service_management::{ @@ -38,7 +39,7 @@ pub trait Launcher { #[allow(clippy::too_many_arguments)] fn launch_node( &self, - bootstrap_peers: Vec, + first: bool, log_format: Option, metrics_port: Option, node_port: Option, @@ -62,7 +63,7 @@ impl Launcher for LocalSafeLauncher { fn launch_node( &self, - bootstrap_peers: Vec, + first: bool, log_format: Option, metrics_port: Option, node_port: Option, @@ -78,13 +79,8 @@ impl Launcher for LocalSafeLauncher { args.push(owner); } - if bootstrap_peers.is_empty() { + if first { args.push("--first".to_string()) - } else { - for peer in bootstrap_peers { - args.push("--peer".to_string()); - args.push(peer.to_string()); - } } if let Some(log_format) = log_format { @@ -296,8 +292,7 @@ pub async fn run_network( let owner = get_node_owner(&options.owner_prefix, &options.owner, &number); let node = run_node( RunNodeOptions { - bootstrap_peers: vec![], - genesis: true, + first: true, metrics_port: metrics_free_port, node_port, interval: options.interval, @@ -345,8 +340,7 @@ pub async fn run_network( let owner = get_node_owner(&options.owner_prefix, &options.owner, &number); let node = run_node( RunNodeOptions { - bootstrap_peers: bootstrap_peers.clone(), - genesis: false, + first: false, metrics_port: metrics_free_port, node_port, interval: options.interval, @@ -386,8 +380,7 @@ pub async fn run_network( } pub struct RunNodeOptions { - pub bootstrap_peers: Vec, - pub genesis: bool, + pub first: bool, pub interval: u64, pub log_format: Option, pub metrics_port: Option, @@ -408,7 +401,7 @@ pub async fn run_node( info!("Launching node {}...", run_options.number); println!("Launching node {}...", run_options.number); launcher.launch_node( - run_options.bootstrap_peers.clone(), + run_options.first, run_options.log_format, run_options.metrics_port, run_options.node_port, @@ -435,20 +428,28 @@ pub async fn run_node( connected_peers, data_dir_path: node_info.data_path, evm_network: run_options.evm_network.unwrap_or(EvmNetwork::ArbitrumOne), - genesis: run_options.genesis, home_network: false, listen_addr: Some(listen_addrs), - local: true, log_dir_path: node_info.log_path, log_format: run_options.log_format, max_archived_log_files: None, max_log_files: None, metrics_port: run_options.metrics_port, + network_id: None, node_ip: None, node_port: run_options.node_port, number: run_options.number, owner: run_options.owner, peer_id: Some(peer_id), + peers_args: PeersArgs { + first: run_options.first, + addrs: vec![], + network_contacts_url: vec![], + local: true, + disable_mainnet_contacts: true, + ignore_cache: true, + bootstrap_cache_dir: None, + }, pid: Some(node_info.pid), rewards_address: run_options.rewards_address, reward_balance: None, @@ -564,7 +565,7 @@ mod tests { mock_launcher .expect_launch_node() .with( - eq(vec![]), + eq(true), eq(None), eq(None), eq(None), @@ -611,8 +612,7 @@ mod tests { let node = run_node( RunNodeOptions { - bootstrap_peers: vec![], - genesis: true, + first: true, interval: 100, log_format: None, metrics_port: None, @@ -629,7 +629,7 @@ mod tests { ) .await?; - assert!(node.genesis); + assert!(node.peers_args.first); assert_eq!(node.version, "0.100.12"); assert_eq!(node.service_name, "antnode-local1"); assert_eq!( diff --git a/ant-node-manager/src/rpc.rs b/ant-node-manager/src/rpc.rs index 5cc357c2e8..1af38833ff 100644 --- a/ant-node-manager/src/rpc.rs +++ b/ant-node-manager/src/rpc.rs @@ -64,22 +64,21 @@ pub async fn restart_node_service( let install_ctx = InstallNodeServiceCtxBuilder { antnode_path: current_node_clone.antnode_path.clone(), autostart: current_node_clone.auto_restart, - bootstrap_peers: node_registry.bootstrap_peers.clone(), data_dir_path: current_node_clone.data_dir_path.clone(), env_variables: node_registry.environment_variables.clone(), evm_network: current_node_clone.evm_network.clone(), - genesis: current_node_clone.genesis, home_network: current_node_clone.home_network, - local: current_node_clone.local, log_dir_path: current_node_clone.log_dir_path.clone(), log_format: current_node_clone.log_format, max_archived_log_files: current_node_clone.max_archived_log_files, max_log_files: current_node_clone.max_log_files, metrics_port: None, - owner: current_node_clone.owner.clone(), name: current_node_clone.service_name.clone(), + network_id: current_node_clone.network_id, node_ip: current_node_clone.node_ip, node_port: current_node_clone.get_antnode_port(), + owner: current_node_clone.owner.clone(), + peers_args: current_node_clone.peers_args.clone(), rewards_address: current_node_clone.rewards_address, rpc_socket_addr: current_node_clone.rpc_socket_addr, service_user: current_node_clone.user.clone(), @@ -181,22 +180,21 @@ pub async fn restart_node_service( let install_ctx = InstallNodeServiceCtxBuilder { autostart: current_node_clone.auto_restart, - bootstrap_peers: node_registry.bootstrap_peers.clone(), data_dir_path: data_dir_path.clone(), env_variables: node_registry.environment_variables.clone(), evm_network: current_node_clone.evm_network.clone(), - genesis: current_node_clone.genesis, home_network: current_node_clone.home_network, - local: current_node_clone.local, log_dir_path: log_dir_path.clone(), log_format: current_node_clone.log_format, name: new_service_name.clone(), max_archived_log_files: current_node_clone.max_archived_log_files, max_log_files: current_node_clone.max_log_files, metrics_port: None, + network_id: current_node_clone.network_id, node_ip: current_node_clone.node_ip, node_port: None, owner: None, + peers_args: current_node_clone.peers_args.clone(), rewards_address: current_node_clone.rewards_address, rpc_socket_addr: current_node_clone.rpc_socket_addr, antnode_path: antnode_path.clone(), @@ -214,20 +212,20 @@ pub async fn restart_node_service( connected_peers: None, data_dir_path, evm_network: current_node_clone.evm_network, - genesis: current_node_clone.genesis, home_network: current_node_clone.home_network, listen_addr: None, - local: current_node_clone.local, log_dir_path, log_format: current_node_clone.log_format, max_archived_log_files: current_node_clone.max_archived_log_files, max_log_files: current_node_clone.max_log_files, metrics_port: None, + network_id: current_node_clone.network_id, node_ip: current_node_clone.node_ip, node_port: None, number: new_node_number as u16, owner: None, peer_id: None, + peers_args: current_node_clone.peers_args.clone(), pid: None, rewards_address: current_node_clone.rewards_address, reward_balance: current_node_clone.reward_balance, diff --git a/ant-node/src/bin/antnode/main.rs b/ant-node/src/bin/antnode/main.rs index 6246206211..db40d00101 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() @@ -295,7 +308,7 @@ fn main() -> Result<()> { // another process with these args. #[cfg(feature = "metrics")] rt.spawn(init_metrics(std::process::id())); - let initial_peres = rt.block_on(opt.peers.get_addrs(None))?; + let initial_peres = rt.block_on(opt.peers.get_addrs(None, Some(100)))?; debug!("Node's owner set to: {:?}", opt.owner); let restart_options = rt.block_on(async move { let mut node_builder = NodeBuilder::new( 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/ant-service-management/Cargo.toml b/ant-service-management/Cargo.toml index 918543468e..45c8a8d6b5 100644 --- a/ant-service-management/Cargo.toml +++ b/ant-service-management/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/maidsafe/autonomi" version = "0.4.3" [dependencies] +ant-bootstrap = { path = "../ant-bootstrap", version = "0.1.0" } ant-evm = { path = "../ant-evm", version = "0.1.4" } ant-logging = { path = "../ant-logging", version = "0.2.40" } ant-protocol = { path = "../ant-protocol", version = "0.17.15", features = ["rpc"] } diff --git a/ant-service-management/src/auditor.rs b/ant-service-management/src/auditor.rs index 7df0bcb46c..cea9273395 100644 --- a/ant-service-management/src/auditor.rs +++ b/ant-service-management/src/auditor.rs @@ -54,17 +54,6 @@ impl ServiceStateActions for AuditorService<'_> { OsString::from(self.service_data.log_dir_path.to_string_lossy().to_string()), ]; - if !options.bootstrap_peers.is_empty() { - let peers_str = options - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } - args.push(OsString::from("server")); Ok(ServiceInstallCtx { diff --git a/ant-service-management/src/faucet.rs b/ant-service-management/src/faucet.rs index 097db24f6a..7aa0d15b30 100644 --- a/ant-service-management/src/faucet.rs +++ b/ant-service-management/src/faucet.rs @@ -55,17 +55,6 @@ impl ServiceStateActions for FaucetService<'_> { OsString::from(self.service_data.log_dir_path.to_string_lossy().to_string()), ]; - if !options.bootstrap_peers.is_empty() { - let peers_str = options - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } - args.push(OsString::from("server")); Ok(ServiceInstallCtx { diff --git a/ant-service-management/src/lib.rs b/ant-service-management/src/lib.rs index 406f608631..1e4c970808 100644 --- a/ant-service-management/src/lib.rs +++ b/ant-service-management/src/lib.rs @@ -23,7 +23,6 @@ pub mod antctl_proto { use async_trait::async_trait; use auditor::AuditorServiceData; -use libp2p::Multiaddr; use semver::Version; use serde::{Deserialize, Serialize}; use service_manager::ServiceInstallCtx; @@ -68,7 +67,6 @@ pub enum UpgradeResult { #[derive(Clone, Debug, Eq, PartialEq)] pub struct UpgradeOptions { pub auto_restart: bool, - pub bootstrap_peers: Vec, pub env_variables: Option>, pub force: bool, pub start_service: bool, @@ -103,7 +101,6 @@ pub struct StatusSummary { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NodeRegistry { pub auditor: Option, - pub bootstrap_peers: Vec, pub daemon: Option, pub environment_variables: Option>, pub faucet: Option, @@ -139,7 +136,6 @@ impl NodeRegistry { debug!("Loading default node registry as {path:?} does not exist"); return Ok(NodeRegistry { auditor: None, - bootstrap_peers: vec![], daemon: None, environment_variables: None, faucet: None, @@ -162,7 +158,6 @@ impl NodeRegistry { if contents.is_empty() { return Ok(NodeRegistry { auditor: None, - bootstrap_peers: vec![], daemon: None, environment_variables: None, faucet: None, diff --git a/ant-service-management/src/node.rs b/ant-service-management/src/node.rs index e268976226..3c281ba4b7 100644 --- a/ant-service-management/src/node.rs +++ b/ant-service-management/src/node.rs @@ -7,6 +7,7 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{error::Result, rpc::RpcActions, ServiceStateActions, ServiceStatus, UpgradeOptions}; +use ant_bootstrap::PeersArgs; use ant_evm::{AttoTokens, EvmNetwork, RewardsAddress}; use ant_logging::LogFormat; use ant_protocol::get_port_from_multiaddr; @@ -71,16 +72,15 @@ impl ServiceStateActions for NodeService<'_> { OsString::from(self.service_data.log_dir_path.to_string_lossy().to_string()), ]; - if self.service_data.genesis { - args.push(OsString::from("--first")); - } - if self.service_data.local { - args.push(OsString::from("--local")); - } + push_arguments_from_peers_args(&self.service_data.peers_args, &mut args); if let Some(log_fmt) = self.service_data.log_format { args.push(OsString::from("--log-format")); args.push(OsString::from(log_fmt.as_str())); } + if let Some(id) = self.service_data.network_id { + args.push(OsString::from("--network-id")); + args.push(OsString::from(id.to_string())); + } if self.service_data.upnp { args.push(OsString::from("--upnp")); } @@ -115,17 +115,6 @@ impl ServiceStateActions for NodeService<'_> { args.push(OsString::from(owner)); } - if !options.bootstrap_peers.is_empty() { - let peers_str = options - .bootstrap_peers - .iter() - .map(|peer| peer.to_string()) - .collect::>() - .join(","); - args.push(OsString::from("--peer")); - args.push(OsString::from(peers_str)); - } - args.push(OsString::from("--rewards-address")); args.push(OsString::from( self.service_data.rewards_address.to_string(), @@ -291,10 +280,8 @@ pub struct NodeServiceData { pub data_dir_path: PathBuf, #[serde(default)] pub evm_network: EvmNetwork, - pub genesis: bool, pub home_network: bool, pub listen_addr: Option>, - pub local: bool, pub log_dir_path: PathBuf, pub log_format: Option, pub max_archived_log_files: Option, @@ -303,6 +290,7 @@ pub struct NodeServiceData { pub metrics_port: Option, #[serde(default)] pub owner: Option, + pub network_id: Option, #[serde(default)] pub node_ip: Option, #[serde(default)] @@ -313,6 +301,7 @@ pub struct NodeServiceData { deserialize_with = "deserialize_peer_id" )] pub peer_id: Option, + pub peers_args: PeersArgs, pub pid: Option, #[serde(default)] pub rewards_address: RewardsAddress, @@ -404,3 +393,44 @@ impl NodeServiceData { None } } + +/// Pushes arguments from the `PeersArgs` struct to the provided `args` vector. +pub fn push_arguments_from_peers_args(peers_args: &PeersArgs, args: &mut Vec) { + if peers_args.first { + args.push(OsString::from("--first")); + } + if peers_args.local { + args.push(OsString::from("--local")); + } + if !peers_args.addrs.is_empty() { + let peers_str = peers_args + .addrs + .iter() + .map(|peer| peer.to_string()) + .collect::>() + .join(","); + args.push(OsString::from("--peer")); + args.push(OsString::from(peers_str)); + } + if !peers_args.network_contacts_url.is_empty() { + args.push(OsString::from("--network-contacts-url")); + args.push(OsString::from( + peers_args + .network_contacts_url + .iter() + .map(|url| url.to_string()) + .collect::>() + .join(","), + )); + } + if peers_args.disable_mainnet_contacts { + args.push(OsString::from("--testnet")); + } + if peers_args.ignore_cache { + args.push(OsString::from("--ignore-cache")); + } + if let Some(path) = &peers_args.bootstrap_cache_dir { + args.push(OsString::from("--bootstrap-cache-dir")); + args.push(OsString::from(path.to_string_lossy().to_string())); + } +} 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 { diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 49fd1c1b32..735f049fea 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -418,7 +418,7 @@ async fn scale_down_nodes(config: &NodeConfig, count: u16) { None, Some(EvmNetwork::ArbitrumSepolia), config.home_network, - false, + None, None, None, None, @@ -492,7 +492,7 @@ async fn add_nodes( None, Some(EvmNetwork::ArbitrumSepolia), config.home_network, - false, + None, None, None, None,