diff --git a/.github/workflows/benchmark-prs.yml b/.github/workflows/benchmark-prs.yml index eb27cf7ffc..16492523a0 100644 --- a/.github/workflows/benchmark-prs.yml +++ b/.github/workflows/benchmark-prs.yml @@ -47,7 +47,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs env: ANT_LOG: "all" with: @@ -219,7 +219,7 @@ jobs: - name: Stop the local network if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_benchmark diff --git a/.github/workflows/generate-benchmark-charts.yml b/.github/workflows/generate-benchmark-charts.yml index 5ec91d7641..d82a6c855e 100644 --- a/.github/workflows/generate-benchmark-charts.yml +++ b/.github/workflows/generate-benchmark-charts.yml @@ -50,7 +50,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -110,7 +110,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop platform: ubuntu-latest diff --git a/.github/workflows/memcheck.yml b/.github/workflows/memcheck.yml index e6556b9f57..c045eda45e 100644 --- a/.github/workflows/memcheck.yml +++ b/.github/workflows/memcheck.yml @@ -40,7 +40,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -166,7 +166,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_memcheck diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 60faed6af6..91b3a988d2 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -198,7 +198,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -222,7 +222,7 @@ jobs: # only these unit tests require a network, the rest are run above in unit test section - name: Run autonomi --tests - run: cargo test --package autonomi --tests -- --nocapture + run: cargo test --package autonomi --tests -- --nocapture --test-threads=1 env: ANT_LOG: "v" # only set the target dir for windows to bypass the linker issue. @@ -578,7 +578,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_e2e @@ -608,7 +608,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -643,7 +643,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: safe_test_logs_transaction @@ -682,7 +682,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -710,7 +710,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: safe_test_logs_transaction_simulation @@ -748,7 +748,7 @@ jobs: # timeout-minutes: 35 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -776,7 +776,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: safe_test_logs_token_distribution @@ -818,7 +818,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -855,7 +855,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_churn @@ -965,7 +965,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -1013,7 +1013,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_data_location @@ -1084,7 +1084,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -1230,7 +1230,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # platform: ubuntu-latest @@ -1280,7 +1280,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -1372,7 +1372,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop platform: ubuntu-latest @@ -1443,7 +1443,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -1590,7 +1590,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: safe_test_logs_heavy_replicate_bench diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 23a9b78f99..9c9b9a89e1 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -36,7 +36,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -211,7 +211,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_e2e @@ -319,7 +319,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -338,7 +338,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_churn @@ -472,7 +472,7 @@ jobs: timeout-minutes: 30 - name: Start a local network - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: start enable-evm-testnet: true @@ -501,7 +501,7 @@ jobs: - name: Stop the local network and upload logs if: always() - uses: maidsafe/ant-local-testnet-action@main + uses: maidsafe/ant-local-testnet-action@feat-addrs-logs with: action: stop log_file_prefix: safe_test_logs_data_location diff --git a/.github/workflows/node_man_tests.yml b/.github/workflows/node_man_tests.yml index b3de7a8f7c..f569b3c3dc 100644 --- a/.github/workflows/node_man_tests.yml +++ b/.github/workflows/node_man_tests.yml @@ -56,7 +56,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -81,7 +81,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: node_man_tests_user_mode @@ -109,7 +109,7 @@ jobs: # timeout-minutes: 30 # - name: Start a local network - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: start # interval: 2000 @@ -149,7 +149,7 @@ jobs: # - name: Stop the local network and upload logs # if: always() - # uses: maidsafe/ant-local-testnet-action@main + # uses: maidsafe/ant-local-testnet-action@feat-addrs-logs # with: # action: stop # log_file_prefix: node_man_tests_system_wide diff --git a/ant-bootstrap/src/initial_peers.rs b/ant-bootstrap/src/initial_peers.rs index 55b3f78e16..16f71890b0 100644 --- a/ant-bootstrap/src/initial_peers.rs +++ b/ant-bootstrap/src/initial_peers.rs @@ -79,8 +79,14 @@ pub struct PeersArgs { } impl PeersArgs { - /// Get bootstrap peers sorted by the failure rate. The peer with the lowest failure rate will be - /// the first in the list. + /// 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 `ANT_PEERS` + /// 3. Addresses from cache + /// 4. Addresses from network contacts URL pub async fn get_addrs( &self, config: Option, @@ -94,8 +100,14 @@ impl PeersArgs { .collect()) } - /// Get bootstrap peers sorted by the failure rate. The peer with the lowest failure rate will be - /// the first in the list. + /// 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 `ANT_PEERS` + /// 3. Addresses from cache + /// 4. Addresses from network contacts URL pub async fn get_bootstrap_addr( &self, config: Option, @@ -107,14 +119,21 @@ impl PeersArgs { return Ok(vec![]); } + let mut bootstrap_addresses = vec![]; + + // Read from ANT_PEERS environment variable if present + bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env()); + + if !bootstrap_addresses.is_empty() { + return Ok(bootstrap_addresses); + } + // If local mode is enabled, return empty store (will use mDNS) if self.local || cfg!(feature = "local") { info!("Local mode enabled, using only local discovery."); return Ok(vec![]); } - let mut bootstrap_addresses = vec![]; - // Add addrs from arguments if present for addr in &self.addrs { if let Some(addr) = craft_valid_multiaddr(addr, false) { @@ -124,8 +143,6 @@ impl PeersArgs { warn!("Invalid multiaddress format from arguments: {addr}"); } } - // Read from ANT_PEERS environment variable if present - bootstrap_addresses.extend(Self::read_bootstrap_addr_from_env()); if let Some(count) = count { if bootstrap_addresses.len() >= count { diff --git a/ant-networking/src/cmd.rs b/ant-networking/src/cmd.rs index 9a694f0650..6171fe0114 100644 --- a/ant-networking/src/cmd.rs +++ b/ant-networking/src/cmd.rs @@ -159,6 +159,15 @@ pub enum NetworkSwarmCmd { addr: Multiaddr, sender: oneshot::Sender>, }, + + /// Adds a peer address to the routing table. + /// + /// See [`libp2p::kad::Behaviour::add_address`] for more details. + AddPeerAddresses { + addresses: Vec<(PeerId, Multiaddr)>, + sender: oneshot::Sender<()>, + }, + // Get closest peers from the network GetClosestPeersToAddressFromNetwork { key: NetworkAddress, @@ -322,6 +331,12 @@ impl Debug for NetworkSwarmCmd { NetworkSwarmCmd::Dial { addr, .. } => { write!(f, "NetworkSwarmCmd::Dial {{ addr: {addr:?} }}") } + NetworkSwarmCmd::AddPeerAddresses { addresses, .. } => { + write!( + f, + "NetworkSwarmCmd::AddPeerAddresses {{ addresses: {addresses:?} }}" + ) + } NetworkSwarmCmd::GetNetworkRecord { key, cfg, .. } => { write!( f, @@ -488,6 +503,15 @@ impl SwarmDriver { Err(e) => sender.send(Err(e.into())), }; } + + NetworkSwarmCmd::AddPeerAddresses { addresses, sender } => { + cmd_string = "AddPeerAddresses"; + for (peer, addr) in addresses { + let _update = self.swarm.behaviour_mut().kademlia.add_address(&peer, addr); + } + let _ = sender.send(()); + } + NetworkSwarmCmd::GetClosestPeersToAddressFromNetwork { key, sender } => { cmd_string = "GetClosestPeersToAddressFromNetwork"; let query_id = self diff --git a/ant-networking/src/lib.rs b/ant-networking/src/lib.rs index c43cdcdf8e..2fcd94f342 100644 --- a/ant-networking/src/lib.rs +++ b/ant-networking/src/lib.rs @@ -221,6 +221,15 @@ impl Network { receiver.await? } + /// Adds a peer address to the routing table. + /// + /// See [`libp2p::kad::Behaviour::add_address`] for more details. + pub async fn add_peer_addresses(&self, addresses: Vec<(PeerId, Multiaddr)>) -> Result<()> { + let (sender, receiver) = oneshot::channel(); + self.send_network_swarm_cmd(NetworkSwarmCmd::AddPeerAddresses { addresses, sender }); + Ok(receiver.await?) + } + /// Returns the closest peers to the given `XorName`, sorted by their distance to the xor_name. /// Excludes the client's `PeerId` while calculating the closest peers. pub async fn client_get_all_close_peers_in_range_or_close_group( diff --git a/autonomi/src/client/mod.rs b/autonomi/src/client/mod.rs index fae0a87ba8..bd1b5ce878 100644 --- a/autonomi/src/client/mod.rs +++ b/autonomi/src/client/mod.rs @@ -34,13 +34,13 @@ pub mod wasm; mod rate_limiter; mod utils; -use ant_bootstrap::{BootstrapCacheConfig, BootstrapCacheStore}; +use ant_bootstrap::{BootstrapCacheConfig, BootstrapCacheStore, PeersArgs}; pub use ant_evm::Amount; use ant_evm::EvmNetwork; use ant_networking::{interval, multiaddr_is_global, Network, NetworkBuilder, NetworkEvent}; use ant_protocol::{version::IDENTIFY_PROTOCOL_STR, CLOSE_GROUP_SIZE}; -use libp2p::{identity::Keypair, Multiaddr}; +use libp2p::{identity::Keypair, multiaddr::Protocol, Multiaddr}; use std::{collections::HashSet, sync::Arc, time::Duration}; use tokio::sync::mpsc; @@ -71,6 +71,17 @@ pub struct Client { pub(crate) evm_network: EvmNetwork, } +/// Configuration for [`Client::init_with_config`]. +#[derive(Debug, Clone, Default)] +pub struct ClientConfig { + /// Whether we're expected to connect to a local network. + pub local: bool, + /// List of peers to connect to. + /// + /// If not provided, the client will use the default bootstrap peers. + pub peers: Option>, +} + /// Error returned by [`Client::connect`]. #[derive(Debug, thiserror::Error)] pub enum ConnectError { @@ -83,6 +94,62 @@ pub enum ConnectError { } impl Client { + pub async fn init() -> Result { + Self::init_with_config(ClientConfig::default()).await + } + + pub async fn init_with_config(config: ClientConfig) -> Result { + let (network, event_receiver) = build_client_and_run_swarm(config.local); + + let peers_args = PeersArgs { + disable_mainnet_contacts: config.local, + ..Default::default() + }; + + let peers = if let Some(peers) = config.peers { + peers + } else { + match peers_args.get_addrs(None, None).await { + Ok(peers) => peers, + Err(e) => return Err(e), + } + }; + + let peers_len = peers.len(); + // Add peers to the routing table. + let peers_with_p2p: Vec<_> = peers + .into_iter() + .filter_map(|addr| { + addr.iter().find_map(|p| match p { + Protocol::P2p(id) => Some((id, addr.clone())), + _ => None, + }) + }) + .collect(); + if peers_with_p2p.len() < peers_len { + tracing::warn!("Some bootstrap addresses have no peer ID, skipping them"); + } + + let network_clone = network.clone(); + let _handle = ant_networking::target_arch::spawn(async move { + if let Err(err) = network_clone.add_peer_addresses(peers_with_p2p).await { + error!("Failed to add addresses with err: {err:?}"); + } + }); + + let (sender, receiver) = futures::channel::oneshot::channel(); + ant_networking::target_arch::spawn(handle_event_receiver(event_receiver, sender)); + + let _ = receiver.await.expect("sender should not close"); + debug!("Client is connected to the network"); + + Ok(Self { + network, + client_event_sender: Arc::new(None), + evm_network: Default::default(), + }) + } + /// Connect to the network. /// /// This will timeout after [`CONNECT_TIMEOUT_SECS`] secs. diff --git a/autonomi/tests/put.rs b/autonomi/tests/put.rs index f5d411e691..c434c1c545 100644 --- a/autonomi/tests/put.rs +++ b/autonomi/tests/put.rs @@ -7,15 +7,13 @@ // permissions and limitations relating to use of the SAFE Network Software. use ant_logging::LogBuilder; -use autonomi::Client; +use autonomi::{client::ClientConfig, Client}; use eyre::Result; -use std::time::Duration; use test_utils::{evm::get_funded_wallet, gen_random_data, peers_from_env}; -use tokio::time::sleep; #[tokio::test] -async fn put() -> Result<()> { - let _log_appender_guard = LogBuilder::init_single_threaded_tokio_test("put", false); +async fn put_1() -> Result<()> { + let _log_appender_guard = LogBuilder::init_single_threaded_tokio_test("put_1", false); let client = Client::connect(&peers_from_env()?).await?; let wallet = get_funded_wallet(); @@ -23,7 +21,25 @@ async fn put() -> Result<()> { let addr = client.data_put_public(data.clone(), wallet.into()).await?; - sleep(Duration::from_secs(10)).await; + let data_fetched = client.data_get_public(addr).await?; + assert_eq!(data, data_fetched, "data fetched should match data put"); + + Ok(()) +} + +#[tokio::test] +async fn put_2() -> Result<()> { + let _log_appender_guard = LogBuilder::init_single_threaded_tokio_test("put_2", false); + + let client = Client::init_with_config(ClientConfig { + local: true, + ..Default::default() + }) + .await?; + let wallet = get_funded_wallet(); + let data = gen_random_data(1024 * 1024 * 10); + + let addr = client.data_put_public(data.clone(), wallet.into()).await?; let data_fetched = client.data_get_public(addr).await?; assert_eq!(data, data_fetched, "data fetched should match data put");