From 05b7710d431d76abc89692278f418892b6d2ad1a Mon Sep 17 00:00:00 2001 From: qima Date: Thu, 31 Oct 2024 23:30:09 +0800 Subject: [PATCH 01/24] Revert "Revert "Revert "Merge pull request #2224 from joshuef/RangeBasedGets""" This reverts commit 49115fd211e3417f4d613c18a73cda898adb682d. --- .github/workflows/merge.yml | 245 +++++++------- sn_networking/src/bootstrap.rs | 120 ++++++- sn_networking/src/cmd.rs | 175 ++++------ sn_networking/src/driver.rs | 149 +++------ sn_networking/src/error.rs | 14 +- sn_networking/src/event/kad.rs | 343 +++++++------------- sn_networking/src/event/request_response.rs | 167 +++++----- sn_networking/src/event/swarm.rs | 39 +-- sn_networking/src/lib.rs | 235 ++------------ sn_networking/src/network_discovery.rs | 37 +-- sn_networking/src/record_store.rs | 28 +- sn_networking/src/record_store_api.rs | 14 +- sn_networking/src/replication_fetcher.rs | 64 +--- sn_networking/src/transfers.rs | 34 +- sn_node/src/put_validation.rs | 13 +- sn_node/src/replication.rs | 120 +++++-- sn_node/tests/double_spend.rs | 196 +++++------ sn_node/tests/storage_payments.rs | 257 +++++++-------- sn_node/tests/verify_data_location.rs | 22 +- sn_node/tests/verify_routing_table.rs | 2 +- sn_protocol/src/error.rs | 3 - sn_protocol/src/storage.rs | 5 +- sn_protocol/src/storage/header.rs | 27 -- sn_transfers/src/wallet/error.rs | 10 - 24 files changed, 969 insertions(+), 1350 deletions(-) diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index db89c867be..9142383db4 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -535,19 +535,15 @@ jobs: # platform: ${{ matrix.os }} # build: true - # # incase the faucet is not ready yet - # - name: 30s sleep for faucet completion - # run: sleep 30 - - # - name: Check SAFE_PEERS was set - # shell: bash - # run: | - # if [[ -z "$SAFE_PEERS" ]]; then - # echo "The SAFE_PEERS variable has not been set" - # exit 1 - # else - # echo "SAFE_PEERS has been set to $SAFE_PEERS" - # fi + # - name: Check SAFE_PEERS was set + # shell: bash + # run: | + # if [[ -z "$SAFE_PEERS" ]]; then + # echo "The SAFE_PEERS variable has not been set" + # exit 1 + # else + # echo "SAFE_PEERS has been set to $SAFE_PEERS" + # fi # - name: execute token_distribution tests # run: cargo test --release --features=local,distribution token_distribution -- --nocapture --test-threads=1 @@ -798,7 +794,7 @@ jobs: uses: maidsafe/sn-local-testnet-action@main with: action: stop - log_file_prefix: safe_test_logs_data_location_routing_table + log_file_prefix: safe_test_logs_data_location platform: ${{ matrix.os }} - name: Verify restart of nodes using rg @@ -899,15 +895,15 @@ jobs: # echo "SAFE_PEERS has been set to $SAFE_PEERS" # fi - # - name: Create and fund a wallet first time - # run: | - # ~/safe --log-output-dest=data-dir wallet create --no-password - # ~/faucet --log-output-dest=data-dir send 100000000 $(~/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 1>first.txt - # echo "----------" - # cat first.txt - # env: - # SN_LOG: "all" - # timeout-minutes: 5 + # - name: Create and fund a wallet first time + # run: | + # ~/safe --log-output-dest=data-dir wallet create --no-password + # ~/faucet --log-output-dest=data-dir send 100000000 $(~/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 1>first.txt + # echo "----------" + # cat first.txt + # env: + # SN_LOG: "all" + # timeout-minutes: 5 # - name: Move faucet log to the working folder # run: | @@ -1158,6 +1154,7 @@ jobs: # runs-on: ubuntu-latest # env: # CLIENT_DATA_PATH: /home/runner/.local/share/safe/autonomi + # steps: # - uses: actions/checkout@v4 @@ -1234,28 +1231,14 @@ jobs: # echo "SAFE_PEERS has been set to $SAFE_PEERS" # fi - # - name: Sleep 15s - # shell: bash - # run: sleep 15 - - # - name: Check faucet has been funded - # shell: bash - # run: | - # cash_note_count=$(ls -l /home/runner/.local/share/safe/test_faucet/wallet/cash_notes/ | wc -l) - # echo $cash_note_count - # if [ "$cash_note_count" -eq 0 ]; then - # echo "Error: Expected at least 1 cash note, but found $cash_note_count" - # exit 1 - # fi - - # - name: Create and fund a wallet to pay for files storage - # run: | - # ./target/release/safe --log-output-dest=data-dir wallet create --no-password - # ./target/release/faucet --log-output-dest=data-dir send 100000000 $(./target/release/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 > transfer_hex - # ./target/release/safe --log-output-dest=data-dir wallet receive --file transfer_hex - # env: - # SN_LOG: "all" - # timeout-minutes: 5 + # - name: Create and fund a wallet to pay for files storage + # run: | + # ./target/release/safe --log-output-dest=data-dir wallet create --no-password + # ./target/release/faucet --log-output-dest=data-dir send 100000000 $(./target/release/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 > transfer_hex + # ./target/release/safe --log-output-dest=data-dir wallet receive --file transfer_hex + # env: + # SN_LOG: "all" + # timeout-minutes: 5 # - name: Start a client to upload first file # run: ./target/release/safe --log-output-dest=data-dir files upload "./test_data_1.tar.gz" --retry-strategy quick @@ -1263,32 +1246,29 @@ jobs: # SN_LOG: "all" # timeout-minutes: 5 - # - name: Check current directories - # run: | - # pwd - # ls $CLIENT_DATA_PATH/ -l - # ls $CLIENT_DATA_PATH/wallet -l - # ls $CLIENT_DATA_PATH/wallet/cash_notes -l - # timeout-minutes: 1 - - # - name: Ensure no leftover cash_notes and payment files - # run: | - # expected_cash_notes_files="1" - # expected_payment_files="0" - # cash_note_files=$(ls $CLIENT_DATA_PATH/wallet/cash_notes | wc -l) - # echo "Find $cash_note_files cash_note files" - # if [ $expected_cash_notes_files -lt $cash_note_files ]; then - # echo "Got too many cash_note files leftover: $cash_note_files" - # exit 1 - # fi - # ls $CLIENT_DATA_PATH/wallet/payments -l - # payment_files=$(ls $CLIENT_DATA_PATH/wallet/payments | wc -l) - # if [ $expected_payment_files -lt $payment_files ]; then - # echo "Got too many payment files leftover: $payment_files" - # exit 1 - # fi - - # timeout-minutes: 10 + # - name: Ensure no leftover cash_notes and payment files + # run: | + # expected_cash_notes_files="1" + # expected_payment_files="0" + # pwd + # ls $CLIENT_DATA_PATH/ -l + # ls $CLIENT_DATA_PATH/wallet -l + # ls $CLIENT_DATA_PATH/wallet/cash_notes -l + # cash_note_files=$(ls $CLIENT_DATA_PATH/wallet/cash_notes | wc -l) + # echo "Find $cash_note_files cash_note files" + # if [ $expected_cash_notes_files -lt $cash_note_files ]; then + # echo "Got too many cash_note files leftover: $cash_note_files" + # exit 1 + # fi + # ls $CLIENT_DATA_PATH/wallet/payments -l + # payment_files=$(ls $CLIENT_DATA_PATH/wallet/payments | wc -l) + # if [ $expected_payment_files -lt $payment_files ]; then + # echo "Got too many payment files leftover: $payment_files" + # exit 1 + # fi + # env: + # CLIENT_DATA_PATH: /home/runner/.local/share/safe/client + # timeout-minutes: 10 # - name: Wait for certain period # run: sleep 300 @@ -1300,49 +1280,52 @@ jobs: # SN_LOG: "all" # timeout-minutes: 10 - # - name: Ensure no leftover cash_notes and payment files - # run: | - # expected_cash_notes_files="1" - # expected_payment_files="0" - # pwd - # ls $CLIENT_DATA_PATH/ -l - # ls $CLIENT_DATA_PATH/wallet -l - # ls $CLIENT_DATA_PATH/wallet/cash_notes -l - # cash_note_files=$(find $CLIENT_DATA_PATH/wallet/cash_notes -type f | wc -l) - # if (( $(echo "$cash_note_files > $expected_cash_notes_files" | bc -l) )); then - # echo "Got too many cash_note files leftover: $cash_note_files when we expected $expected_cash_notes_files" - # exit 1 - # fi - # ls $CLIENT_DATA_PATH/wallet/payments -l - # payment_files=$(find $CLIENT_DATA_PATH/wallet/payments -type f | wc -l) - # if (( $(echo "$payment_files > $expected_payment_files" | bc -l) )); then - # echo "Got too many payment files leftover: $payment_files" - # exit 1 - # fi - # timeout-minutes: 10 + # - name: Ensure no leftover cash_notes and payment files + # run: | + # expected_cash_notes_files="1" + # expected_payment_files="0" + # pwd + # ls $CLIENT_DATA_PATH/ -l + # ls $CLIENT_DATA_PATH/wallet -l + # ls $CLIENT_DATA_PATH/wallet/cash_notes -l + # cash_note_files=$(find $CLIENT_DATA_PATH/wallet/cash_notes -type f | wc -l) + # if (( $(echo "$cash_note_files > $expected_cash_notes_files" | bc -l) )); then + # echo "Got too many cash_note files leftover: $cash_note_files when we expected $expected_cash_notes_files" + # exit 1 + # fi + # ls $CLIENT_DATA_PATH/wallet/payments -l + # payment_files=$(find $CLIENT_DATA_PATH/wallet/payments -type f | wc -l) + # if (( $(echo "$payment_files > $expected_payment_files" | bc -l) )); then + # echo "Got too many payment files leftover: $payment_files" + # exit 1 + # fi + # env: + # CLIENT_DATA_PATH: /home/runner/.local/share/safe/client + # timeout-minutes: 10 # - name: Wait for certain period # run: sleep 300 # timeout-minutes: 6 - # # Start a different client to avoid local wallet slow down with more payments handled. - # - name: Start a different client - # run: | - # pwd - # mv $CLIENT_DATA_PATH $SAFE_DATA_PATH/client_first - # ls -l $SAFE_DATA_PATH - # ls -l $SAFE_DATA_PATH/client_first - # mkdir $SAFE_DATA_PATH/client - # ls -l $SAFE_DATA_PATH - # mv $SAFE_DATA_PATH/client_first/logs $CLIENT_DATA_PATH/logs - # ls -l $CLIENT_DATA_PATH - # ./target/release/safe --log-output-dest=data-dir wallet create --no-password - # ./target/release/faucet --log-output-dest=data-dir send 100000000 $(./target/release/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 > transfer_hex - # ./target/release/safe --log-output-dest=data-dir wallet receive --file transfer_hex - # env: - # SN_LOG: "all" - # SAFE_DATA_PATH: /home/runner/.local/share/safe - # timeout-minutes: 25 + # # Start a different client to avoid local wallet slow down with more payments handled. + # - name: Start a different client + # run: | + # pwd + # mv $CLIENT_DATA_PATH $SAFE_DATA_PATH/client_first + # ls -l $SAFE_DATA_PATH + # ls -l $SAFE_DATA_PATH/client_first + # mkdir $SAFE_DATA_PATH/client + # ls -l $SAFE_DATA_PATH + # mv $SAFE_DATA_PATH/client_first/logs $CLIENT_DATA_PATH/logs + # ls -l $CLIENT_DATA_PATH + # ./target/release/safe --log-output-dest=data-dir wallet create --no-password + # ./target/release/faucet --log-output-dest=data-dir send 100000000 $(./target/release/safe --log-output-dest=data-dir wallet address | tail -n 1) | tail -n 1 > transfer_hex + # ./target/release/safe --log-output-dest=data-dir wallet receive --file transfer_hex + # env: + # SN_LOG: "all" + # SAFE_DATA_PATH: /home/runner/.local/share/safe + # CLIENT_DATA_PATH: /home/runner/.local/share/safe/client + # timeout-minutes: 25 # - name: Use second client to upload third file # run: ./target/release/safe --log-output-dest=data-dir files upload "./test_data_3.tar.gz" --retry-strategy quick @@ -1350,27 +1333,29 @@ jobs: # SN_LOG: "all" # timeout-minutes: 10 - # - name: Ensure no leftover cash_notes and payment files - # run: | - # expected_cash_notes_files="1" - # expected_payment_files="0" - # pwd - # ls $CLIENT_DATA_PATH/ -l - # ls $CLIENT_DATA_PATH/wallet -l - # ls $CLIENT_DATA_PATH/wallet/cash_notes -l - # cash_note_files=$(ls $CLIENT_DATA_PATH/wallet/cash_notes | wc -l) - # echo "Find $cash_note_files cash_note files" - # if [ $expected_cash_notes_files -lt $cash_note_files ]; then - # echo "Got too many cash_note files leftover: $cash_note_files" - # exit 1 - # fi - # ls $CLIENT_DATA_PATH/wallet/payments -l - # payment_files=$(ls $CLIENT_DATA_PATH/wallet/payments | wc -l) - # if [ $expected_payment_files -lt $payment_files ]; then - # echo "Got too many payment files leftover: $payment_files" - # exit 1 - # fi - # timeout-minutes: 10 + # - name: Ensure no leftover cash_notes and payment files + # run: | + # expected_cash_notes_files="1" + # expected_payment_files="0" + # pwd + # ls $CLIENT_DATA_PATH/ -l + # ls $CLIENT_DATA_PATH/wallet -l + # ls $CLIENT_DATA_PATH/wallet/cash_notes -l + # cash_note_files=$(ls $CLIENT_DATA_PATH/wallet/cash_notes | wc -l) + # echo "Find $cash_note_files cash_note files" + # if [ $expected_cash_notes_files -lt $cash_note_files ]; then + # echo "Got too many cash_note files leftover: $cash_note_files" + # exit 1 + # fi + # ls $CLIENT_DATA_PATH/wallet/payments -l + # payment_files=$(ls $CLIENT_DATA_PATH/wallet/payments | wc -l) + # if [ $expected_payment_files -lt $payment_files ]; then + # echo "Got too many payment files leftover: $payment_files" + # exit 1 + # fi + # env: + # CLIENT_DATA_PATH: /home/runner/.local/share/safe/client + # timeout-minutes: 10 # - name: Stop the local network and upload logs # if: always() diff --git a/sn_networking/src/bootstrap.rs b/sn_networking/src/bootstrap.rs index ec6c019a88..f8b7cf1e59 100644 --- a/sn_networking/src/bootstrap.rs +++ b/sn_networking/src/bootstrap.rs @@ -7,19 +7,45 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{driver::PendingGetClosestType, SwarmDriver}; +use rand::{rngs::OsRng, Rng}; use tokio::time::Duration; -use crate::target_arch::Instant; +use crate::target_arch::{interval, Instant, Interval}; /// The default interval at which NetworkDiscovery is triggered. The interval is increased as more peers are added to the /// routing table. -pub(crate) const BOOTSTRAP_INTERVAL: Duration = Duration::from_secs(15); +pub(crate) const BOOTSTRAP_INTERVAL: Duration = Duration::from_secs(10); + +/// Every BOOTSTRAP_CONNECTED_PEERS_STEP connected peer, we step up the BOOTSTRAP_INTERVAL to slow down bootstrapping +/// process +const BOOTSTRAP_CONNECTED_PEERS_STEP: u32 = 5; + +/// If the previously added peer has been before LAST_PEER_ADDED_TIME_LIMIT, then we should slowdown the bootstrapping +/// process. This is to make sure we don't flood the network with `FindNode` msgs. +const LAST_PEER_ADDED_TIME_LIMIT: Duration = Duration::from_secs(180); + +/// A minimum interval to prevent bootstrap got triggered too often +const LAST_BOOTSTRAP_TRIGGERED_TIME_LIMIT: Duration = Duration::from_secs(30); + +/// The bootstrap interval to use if we haven't added any new peers in a while. +const NO_PEER_ADDED_SLOWDOWN_INTERVAL_MAX_S: u64 = 600; impl SwarmDriver { /// This functions triggers network discovery based on when the last peer was added to the RT and the number of - /// peers in RT. - pub(crate) fn run_bootstrap_continuously(&mut self) { - self.trigger_network_discovery(); + /// peers in RT. The function also returns a new bootstrap interval that is proportional to the number of + /// peers in RT, so more peers in RT, the longer the interval. + pub(crate) async fn run_bootstrap_continuously( + &mut self, + current_bootstrap_interval: Duration, + ) -> Option { + let (should_bootstrap, new_interval) = self + .bootstrap + .should_we_bootstrap(self.peers_in_rt as u32, current_bootstrap_interval) + .await; + if should_bootstrap { + self.trigger_network_discovery(); + } + new_interval } pub(crate) fn trigger_network_discovery(&mut self) { @@ -35,27 +61,27 @@ impl SwarmDriver { .get_closest_peers(addr.as_bytes()); let _ = self.pending_get_closest_peers.insert( query_id, - ( - addr, - PendingGetClosestType::NetworkDiscovery, - Default::default(), - ), + (PendingGetClosestType::NetworkDiscovery, Default::default()), ); } self.bootstrap.initiated(); - info!("Trigger network discovery took {:?}", now.elapsed()); + debug!("Trigger network discovery took {:?}", now.elapsed()); } } /// Tracks and helps with the continuous kad::bootstrapping process pub(crate) struct ContinuousBootstrap { + initial_bootstrap_done: bool, + last_peer_added_instant: Instant, last_bootstrap_triggered: Option, } impl ContinuousBootstrap { pub(crate) fn new() -> Self { Self { + initial_bootstrap_done: false, + last_peer_added_instant: Instant::now(), last_bootstrap_triggered: None, } } @@ -64,4 +90,76 @@ impl ContinuousBootstrap { pub(crate) fn initiated(&mut self) { self.last_bootstrap_triggered = Some(Instant::now()); } + + /// Notify about a newly added peer to the RT. This will help with slowing down the bootstrap process. + /// Returns `true` if we have to perform the initial bootstrapping. + pub(crate) fn notify_new_peer(&mut self) -> bool { + self.last_peer_added_instant = Instant::now(); + // true to kick off the initial bootstrapping. `run_bootstrap_continuously` might kick of so soon that we might + // not have a single peer in the RT and we'd not perform any bootstrapping for a while. + if !self.initial_bootstrap_done { + self.initial_bootstrap_done = true; + true + } else { + false + } + } + + /// Returns `true` if we should carry out the Kademlia Bootstrap process immediately. + /// Also optionally returns the new interval to re-bootstrap. + pub(crate) async fn should_we_bootstrap( + &self, + peers_in_rt: u32, + current_interval: Duration, + ) -> (bool, Option) { + let is_ongoing = if let Some(last_bootstrap_triggered) = self.last_bootstrap_triggered { + last_bootstrap_triggered.elapsed() < LAST_BOOTSTRAP_TRIGGERED_TIME_LIMIT + } else { + false + }; + let should_bootstrap = !is_ongoing && peers_in_rt >= 1; + + // if it has been a while (LAST_PEER_ADDED_TIME_LIMIT) since we have added a new peer to our RT, then, slowdown + // the bootstrapping process. + // Don't slow down if we haven't even added one peer to our RT. + if self.last_peer_added_instant.elapsed() > LAST_PEER_ADDED_TIME_LIMIT && peers_in_rt != 0 { + // To avoid a heart beat like cpu usage due to the 1K candidates generation, + // randomize the interval within certain range + let no_peer_added_slowdown_interval: u64 = OsRng.gen_range( + NO_PEER_ADDED_SLOWDOWN_INTERVAL_MAX_S / 2..NO_PEER_ADDED_SLOWDOWN_INTERVAL_MAX_S, + ); + let no_peer_added_slowdown_interval_duration = + Duration::from_secs(no_peer_added_slowdown_interval); + info!( + "It has been {LAST_PEER_ADDED_TIME_LIMIT:?} since we last added a peer to RT. Slowing down the continuous bootstrapping process. Old interval: {current_interval:?}, New interval: {no_peer_added_slowdown_interval_duration:?}" + ); + + // `Interval` ticks immediately for Tokio, but not for `wasmtimer`, which is used for wasm32. + #[cfg_attr(target_arch = "wasm32", allow(unused_mut))] + let mut new_interval = interval(no_peer_added_slowdown_interval_duration); + #[cfg(not(target_arch = "wasm32"))] + new_interval.tick().await; + + return (should_bootstrap, Some(new_interval)); + } + + // increment bootstrap_interval in steps of BOOTSTRAP_INTERVAL every BOOTSTRAP_CONNECTED_PEERS_STEP + let step = peers_in_rt / BOOTSTRAP_CONNECTED_PEERS_STEP; + let step = std::cmp::max(1, step); + let new_interval = BOOTSTRAP_INTERVAL * step; + let new_interval = if new_interval > current_interval { + info!("More peers have been added to our RT!. Slowing down the continuous bootstrapping process. Old interval: {current_interval:?}, New interval: {new_interval:?}"); + + // `Interval` ticks immediately for Tokio, but not for `wasmtimer`, which is used for wasm32. + #[cfg_attr(target_arch = "wasm32", allow(unused_mut))] + let mut interval = interval(new_interval); + #[cfg(not(target_arch = "wasm32"))] + interval.tick().await; + + Some(interval) + } else { + None + }; + (should_bootstrap, new_interval) + } } diff --git a/sn_networking/src/cmd.rs b/sn_networking/src/cmd.rs index 48cb8f1307..48372d8d17 100644 --- a/sn_networking/src/cmd.rs +++ b/sn_networking/src/cmd.rs @@ -7,34 +7,33 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{ - close_group_majority, driver::{PendingGetClosestType, SwarmDriver}, error::{NetworkError, Result}, event::TerminateNodeReason, log_markers::Marker, - multiaddr_pop_p2p, sort_peers_by_address_and_limit, GetRecordCfg, GetRecordError, MsgResponder, - NetworkEvent, CLOSE_GROUP_SIZE, + multiaddr_pop_p2p, GetRecordCfg, GetRecordError, MsgResponder, NetworkEvent, CLOSE_GROUP_SIZE, + REPLICATION_PEERS_COUNT, }; use libp2p::{ kad::{ store::{Error as StoreError, RecordStore}, - KBucketDistance, Quorum, Record, RecordKey, + Quorum, Record, RecordKey, }, Multiaddr, PeerId, }; use sn_evm::{AttoTokens, PaymentQuote, QuotingMetrics}; use sn_protocol::{ messages::{Cmd, Request, Response}, - storage::{get_type_from_record, RecordType}, + storage::{RecordHeader, RecordKind, RecordType}, NetworkAddress, PrettyPrintRecordKey, }; use std::{ - cmp::Ordering, collections::{BTreeMap, HashMap}, fmt::Debug, time::Duration, }; use tokio::sync::oneshot; +use xor_name::XorName; use crate::target_arch::Instant; @@ -60,15 +59,6 @@ pub enum NodeIssue { /// Commands to send to the Swarm pub enum LocalSwarmCmd { - // Returns all the peers from all the k-buckets from the local Routing Table. - // This includes our PeerId as well. - GetAllLocalPeersExcludingSelf { - sender: oneshot::Sender>, - }, - /// Return the current GetRange as determined by the SwarmDriver - GetCurrentRequestRange { - sender: oneshot::Sender, - }, /// Get a map where each key is the ilog2 distance of that Kbucket and each value is a vector of peers in that /// bucket. GetKBuckets { @@ -80,8 +70,8 @@ pub enum LocalSwarmCmd { sender: oneshot::Sender>, }, // Get closest peers from the local RoutingTable - GetCloseRangeLocalPeers { - address: NetworkAddress, + GetCloseGroupLocalPeers { + key: NetworkAddress, sender: oneshot::Sender>, }, GetSwarmLocalState(oneshot::Sender), @@ -226,11 +216,15 @@ impl Debug for LocalSwarmCmd { PrettyPrintRecordKey::from(key) ) } + LocalSwarmCmd::GetClosestKLocalPeers { .. } => { write!(f, "LocalSwarmCmd::GetClosestKLocalPeers") } - LocalSwarmCmd::GetCloseRangeLocalPeers { address: key, .. } => { - write!(f, "SwarmCmd::GetCloseGroupLocalPeers {{ key: {key:?} }}") + LocalSwarmCmd::GetCloseGroupLocalPeers { key, .. } => { + write!( + f, + "LocalSwarmCmd::GetCloseGroupLocalPeers {{ key: {key:?} }}" + ) } LocalSwarmCmd::GetLocalStoreCost { .. } => { write!(f, "LocalSwarmCmd::GetLocalStoreCost") @@ -251,12 +245,6 @@ impl Debug for LocalSwarmCmd { LocalSwarmCmd::GetKBuckets { .. } => { write!(f, "LocalSwarmCmd::GetKBuckets") } - LocalSwarmCmd::GetCurrentRequestRange { .. } => { - write!(f, "SwarmCmd::GetCurrentRange") - } - LocalSwarmCmd::GetAllLocalPeersExcludingSelf { .. } => { - write!(f, "SwarmCmd::GetAllLocalPeers") - } LocalSwarmCmd::GetSwarmLocalState { .. } => { write!(f, "LocalSwarmCmd::GetSwarmLocalState") } @@ -487,7 +475,6 @@ impl SwarmDriver { let _ = self.pending_get_closest_peers.insert( query_id, ( - key, PendingGetClosestType::FunctionCall(sender), Default::default(), ), @@ -557,7 +544,6 @@ impl SwarmDriver { Ok(()) } - pub(crate) fn handle_local_cmd(&mut self, cmd: LocalSwarmCmd) -> Result<(), NetworkError> { let start = Instant::now(); let mut cmd_string; @@ -641,7 +627,28 @@ impl SwarmDriver { let key = record.key.clone(); let record_key = PrettyPrintRecordKey::from(&key); - let record_type = get_type_from_record(&record)?; + let record_type = match RecordHeader::from_record(&record) { + Ok(record_header) => { + match record_header.kind { + RecordKind::Chunk => RecordType::Chunk, + RecordKind::Scratchpad => RecordType::Scratchpad, + RecordKind::Spend | RecordKind::Register => { + let content_hash = XorName::from_content(&record.value); + RecordType::NonChunk(content_hash) + } + RecordKind::ChunkWithPayment + | RecordKind::RegisterWithPayment + | RecordKind::ScratchpadWithPayment => { + error!("Record {record_key:?} with payment shall not be stored locally."); + return Err(NetworkError::InCorrectRecordHeader); + } + } + } + Err(err) => { + error!("For record {record_key:?}, failed to parse record_header {err:?}"); + return Err(NetworkError::InCorrectRecordHeader); + } + }; let result = self .swarm @@ -690,8 +697,16 @@ impl SwarmDriver { // The record_store will prune far records and setup a `distance range`, // once reached the `max_records` cap. - self.replication_fetcher - .set_replication_distance_range(self.get_request_range()); + if let Some(distance) = self + .swarm + .behaviour_mut() + .kademlia + .store_mut() + .get_farthest_replication_distance_bucket() + { + self.replication_fetcher + .set_replication_distance_range(distance); + } if let Err(err) = result { error!("Can't store verified record {record_key:?} locally: {err:?}"); @@ -748,10 +763,6 @@ impl SwarmDriver { .record_addresses(); let _ = sender.send(addresses); } - LocalSwarmCmd::GetCurrentRequestRange { sender } => { - cmd_string = "GetCurrentRequestRange"; - let _ = sender.send(self.get_request_range()); - } LocalSwarmCmd::GetKBuckets { sender } => { cmd_string = "GetKBuckets"; let mut ilog2_kbuckets = BTreeMap::new(); @@ -770,13 +781,9 @@ impl SwarmDriver { } let _ = sender.send(ilog2_kbuckets); } - LocalSwarmCmd::GetAllLocalPeersExcludingSelf { sender } => { - cmd_string = "GetAllLocalPeersExcludingSelf"; - let _ = sender.send(self.get_all_local_peers_excluding_self()); - } - LocalSwarmCmd::GetCloseRangeLocalPeers { address, sender } => { - cmd_string = "GetCloseRangeLocalPeers"; - let key = address.as_kbucket_key(); + LocalSwarmCmd::GetCloseGroupLocalPeers { key, sender } => { + cmd_string = "GetCloseGroupLocalPeers"; + let key = key.as_kbucket_key(); // calls `kbuckets.closest_keys(key)` internally, which orders the peers by // increasing distance // Note it will return all peers, heance a chop down is required. @@ -786,6 +793,7 @@ impl SwarmDriver { .kademlia .get_closest_local_peers(&key) .map(|peer| peer.into_preimage()) + .take(CLOSE_GROUP_SIZE) .collect(); let _ = sender.send(closest_peers); @@ -976,70 +984,6 @@ impl SwarmDriver { let _ = self.quotes_history.insert(peer_id, quote); } - /// From all local peers, returns any within (and just exceeding) current get_range for a given key - pub(crate) fn get_filtered_peers_exceeding_range( - &mut self, - target_address: &NetworkAddress, - ) -> Vec { - let acceptable_distance_range = self.get_request_range(); - let target_key = target_address.as_kbucket_key(); - - let sorted_peers: Vec<_> = self - .swarm - .behaviour_mut() - .kademlia - .get_closest_local_peers(&target_key) - .collect(); - - // Binary search to find the index where we exceed the acceptable range - let split_index = sorted_peers - .binary_search_by(|key| { - let distance = target_key.distance(key); - if distance >= acceptable_distance_range { - Ordering::Greater - } else { - Ordering::Less - } - }) - .unwrap_or_else(|x| x); - - // Convert KBucketKey to PeerId for all peers within range - sorted_peers[..split_index] - .iter() - .map(|key| key.into_preimage()) - .collect() - } - - /// From all local peers, returns any within current get_range for a given key - /// Excludes self - pub(crate) fn get_filtered_peers_exceeding_range_or_closest_nodes( - &mut self, - target_address: &NetworkAddress, - ) -> Vec { - let filtered_peers = self.get_filtered_peers_exceeding_range(target_address); - let closest_node_buffer_zone = CLOSE_GROUP_SIZE + close_group_majority(); - if filtered_peers.len() >= closest_node_buffer_zone { - filtered_peers - } else { - warn!("Insufficient peers within replication range of {target_address:?}. Falling back to use {closest_node_buffer_zone:?} closest nodes"); - let all_peers = self.get_all_local_peers_excluding_self(); - match sort_peers_by_address_and_limit( - &all_peers, - target_address, - closest_node_buffer_zone, - ) { - Ok(peers) => peers.iter().map(|p| **p).collect(), - Err(err) => { - error!("sorting peers close to {target_address:?} failed, sort error: {err:?}"); - warn!( - "Using all peers within range even though it's less than CLOSE_GROUP_SIZE." - ); - filtered_peers - } - } - } - } - fn try_interval_replication(&mut self) -> Result<()> { // Add a last_replication field to track the last time replication was performed if let Some(last_replication) = self.last_replication { @@ -1048,14 +992,25 @@ impl SwarmDriver { return Ok(()); } } - // Store the current time as the last replication time self.last_replication = Some(Instant::now()); - let our_address = NetworkAddress::from_peer(self.self_peer_id); - - let mut replicate_targets = - self.get_filtered_peers_exceeding_range_or_closest_nodes(&our_address); + // get closest peers from buckets, sorted by increasing distance to us + let our_peer_id = self.self_peer_id.into(); + let closest_k_peers = self + .swarm + .behaviour_mut() + .kademlia + .get_closest_local_peers(&our_peer_id) + // Map KBucketKey to PeerId. + .map(|key| key.into_preimage()); + + // Only grab the closest nodes within the REPLICATE_RANGE + let mut replicate_targets = closest_k_peers + .into_iter() + // add some leeway to allow for divergent knowledge + .take(REPLICATION_PEERS_COUNT) + .collect::>(); let now = Instant::now(); self.replication_targets diff --git a/sn_networking/src/driver.rs b/sn_networking/src/driver.rs index e70cc6c68d..1e52687741 100644 --- a/sn_networking/src/driver.rs +++ b/sn_networking/src/driver.rs @@ -20,7 +20,6 @@ use crate::{ record_store_api::UnifiedRecordStore, relay_manager::RelayManager, replication_fetcher::ReplicationFetcher, - sort_peers_by_distance_to, target_arch::{interval, spawn, Instant}, GetRecordError, Network, CLOSE_GROUP_SIZE, }; @@ -33,6 +32,7 @@ use futures::future::Either; use futures::StreamExt; #[cfg(feature = "local")] use libp2p::mdns; +use libp2p::Transport as _; use libp2p::{core::muxing::StreamMuxerBox, relay}; use libp2p::{ identity::Keypair, @@ -45,7 +45,6 @@ use libp2p::{ }, Multiaddr, PeerId, }; -use libp2p::{kad::KBucketDistance, Transport as _}; #[cfg(feature = "open-metrics")] use prometheus_client::metrics::info::Info; use sn_evm::PaymentQuote; @@ -60,7 +59,7 @@ use sn_protocol::{ }; use sn_registers::SignedRegister; use std::{ - collections::{btree_map::Entry, BTreeMap, HashMap, HashSet, VecDeque}, + collections::{btree_map::Entry, BTreeMap, HashMap, HashSet}, fmt::Debug, fs, io::{Read, Write}, @@ -80,9 +79,6 @@ pub(crate) const CLOSET_RECORD_CHECK_INTERVAL: Duration = Duration::from_secs(15 /// Interval over which we query relay manager to check if we can make any more reservations. pub(crate) const RELAY_MANAGER_RESERVATION_INTERVAL: Duration = Duration::from_secs(30); -// Number of range distances to keep in the circular buffer -pub const GET_RANGE_STORAGE_LIMIT: usize = 100; - const KAD_STREAM_PROTOCOL_ID: StreamProtocol = StreamProtocol::new("/autonomi/kad/1.0.0"); /// The ways in which the Get Closest queries are used. @@ -93,9 +89,7 @@ pub(crate) enum PendingGetClosestType { /// These are queries made by a function at the upper layers and contains a channel to send the result back. FunctionCall(oneshot::Sender>), } - -/// Maps a query to the address, the type of query and the peers that are being queried. -type PendingGetClosest = HashMap)>; +type PendingGetClosest = HashMap)>; /// Using XorName to differentiate different record content under the same key. type GetRecordResultMap = HashMap)>; @@ -360,6 +354,8 @@ impl NetworkBuilder { .set_publication_interval(None) // 1mb packet size .set_max_packet_size(MAX_PACKET_SIZE) + // How many nodes _should_ store data. + .set_replication_factor(REPLICATION_FACTOR) .set_query_timeout(KAD_QUERY_TIMEOUT_S) // Require iterative queries to use disjoint paths for increased resiliency in the presence of potentially adversarial nodes. .disjoint_query_paths(true) @@ -452,7 +448,9 @@ impl NetworkBuilder { .set_max_packet_size(MAX_PACKET_SIZE) .set_replication_factor(REPLICATION_FACTOR) // Require iterative queries to use disjoint paths for increased resiliency in the presence of potentially adversarial nodes. - .disjoint_query_paths(true); + .disjoint_query_paths(true) + // How many nodes _should_ store data. + .set_replication_factor(REPLICATION_FACTOR); let (network, net_event_recv, driver) = self.build( kad_cfg, @@ -718,8 +716,6 @@ impl NetworkBuilder { bad_nodes: Default::default(), quotes_history: Default::default(), replication_targets: Default::default(), - range_distances: VecDeque::with_capacity(GET_RANGE_STORAGE_LIMIT), - first_contact_made: false, last_replication: None, last_connection_pruning_time: Instant::now(), }; @@ -796,7 +792,7 @@ pub struct SwarmDriver { pub(crate) local_cmd_sender: mpsc::Sender, local_cmd_receiver: mpsc::Receiver, network_cmd_receiver: mpsc::Receiver, - pub(crate) event_sender: mpsc::Sender, // Use `self.send_event()` to send a NetworkEvent. + event_sender: mpsc::Sender, // Use `self.send_event()` to send a NetworkEvent. /// Trackers for underlying behaviour related events pub(crate) pending_get_closest_peers: PendingGetClosest, @@ -819,16 +815,9 @@ pub struct SwarmDriver { pub(crate) bad_nodes: BadNodes, pub(crate) quotes_history: BTreeMap, pub(crate) replication_targets: BTreeMap, - /// when was the last replication event /// This allows us to throttle replication no matter how it is triggered pub(crate) last_replication: Option, - // The recent range_distances calculated by the node - // Each update is generated when there is a routing table change - // We use the largest of these X_STORAGE_LIMIT values as our X distance. - pub(crate) range_distances: VecDeque, - // have we found out initial peer - pub(crate) first_contact_made: bool, /// when was the last outdated connection prunning undertaken. pub(crate) last_connection_pruning_time: Instant, } @@ -881,24 +870,28 @@ impl SwarmDriver { // logging for handling events happens inside handle_swarm_events // otherwise we're rewriting match statements etc around this anwyay if let Err(err) = self.handle_swarm_events(swarm_event) { - warn!("Issue while handling swarm event: {err}"); + warn!("Error while handling swarm event: {err}"); } }, // thereafter we can check our intervals // runs every bootstrap_interval time _ = bootstrap_interval.tick() => { - self.run_bootstrap_continuously(); + if let Some(new_interval) = self.run_bootstrap_continuously(bootstrap_interval.period()).await { + bootstrap_interval = new_interval; + } } _ = set_farthest_record_interval.tick() => { if !self.is_client { - let get_range = self.get_request_range(); - self.swarm.behaviour_mut().kademlia.store_mut().set_distance_range(get_range); - - // the distance range within the replication_fetcher shall be in sync as well - self.replication_fetcher.set_replication_distance_range(get_range); - - + let closest_k_peers = self.get_closest_k_value_local_peers(); + + if let Some(distance) = self.get_responsbile_range_estimate(&closest_k_peers) { + info!("Set responsible range to {distance}"); + // set any new distance to farthest record in the store + self.swarm.behaviour_mut().kademlia.store_mut().set_distance_range(distance); + // the distance range within the replication_fetcher shall be in sync as well + self.replication_fetcher.set_replication_distance_range(distance); + } } } _ = relay_manager_reservation_interval.tick() => self.relay_manager.try_connecting_to_relay(&mut self.swarm, &self.bad_nodes), @@ -910,90 +903,32 @@ impl SwarmDriver { // ---------- Crate helpers ------------------- // -------------------------------------------- - /// Defines a new X distance range to be used for GETs and data replication - /// - /// Enumerates buckets and generates a random distance in the first bucket - /// that has at least `MIN_PEERS_IN_BUCKET` peers. - /// - pub(crate) fn set_request_range( + /// Uses the closest k peers to estimate the farthest address as + /// `K_VALUE / 2`th peer's bucket. + fn get_responsbile_range_estimate( &mut self, - queried_address: NetworkAddress, - network_discovery_peers: &[PeerId], - ) { - info!( - "Adding a GetRange to our stash deriving from {:?} peers", - network_discovery_peers.len() - ); - - let sorted_distances = sort_peers_by_distance_to(network_discovery_peers, queried_address); - - let mapped: Vec<_> = sorted_distances.iter().map(|d| d.ilog2()).collect(); - info!("Sorted distances: {:?}", mapped); - - let farthest_peer_to_check = self - .get_all_local_peers_excluding_self() - .len() - .checked_div(5 * CLOSE_GROUP_SIZE) - .unwrap_or(1); - - info!("Farthest peer we'll check: {:?}", farthest_peer_to_check); - - let yardstick = if sorted_distances.len() >= farthest_peer_to_check { - sorted_distances.get(farthest_peer_to_check.saturating_sub(1)) - } else { - sorted_distances.last() - }; - if let Some(distance) = yardstick { - if self.range_distances.len() >= GET_RANGE_STORAGE_LIMIT { - if let Some(distance) = self.range_distances.pop_front() { - trace!("Removed distance range: {:?}", distance.ilog2()); - } - } - - info!("Adding new distance range: {:?}", distance.ilog2()); - - self.range_distances.push_back(*distance); + // Sorted list of closest k peers to our peer id. + closest_k_peers: &[PeerId], + ) -> Option { + // if we don't have enough peers we don't set the distance range yet. + let mut farthest_distance = None; + + if closest_k_peers.is_empty() { + return farthest_distance; } - info!( - "Distance between peers in set_request_range call: {:?}", - yardstick - ); - } - - /// Returns the KBucketDistance we are currently using as our X value - /// for range based search. - pub(crate) fn get_request_range(&self) -> KBucketDistance { - let mut sorted_distances = self.range_distances.iter().collect::>(); + let our_address = NetworkAddress::from_peer(self.self_peer_id); - sorted_distances.sort_unstable(); + // get `K_VALUE / 2`th peer's address distance + // This is a rough estimate of the farthest address we might be responsible for. + // We want this to be higher than actually necessary, so we retain more data + // and can be sure to pass bad node checks + let target_index = std::cmp::min(K_VALUE.get() / 2, closest_k_peers.len()) - 1; - let median_index = sorted_distances.len() / 8; + let address = NetworkAddress::from_peer(closest_k_peers[target_index]); + farthest_distance = our_address.distance(&address).ilog2(); - let default = KBucketDistance::default(); - let median = sorted_distances.get(median_index).cloned(); - - if let Some(dist) = median { - *dist - } else { - default - } - } - - /// get all the peers from our local RoutingTable. Excluding self - pub(crate) fn get_all_local_peers_excluding_self(&mut self) -> Vec { - let our_peer_id = self.self_peer_id; - let mut all_peers: Vec = vec![]; - for kbucket in self.swarm.behaviour_mut().kademlia.kbuckets() { - for entry in kbucket.iter() { - let id = entry.node.key.into_preimage(); - - if id != our_peer_id { - all_peers.push(id); - } - } - } - all_peers + farthest_distance } /// Pushes NetworkSwarmCmd off thread so as to be non-blocking diff --git a/sn_networking/src/error.rs b/sn_networking/src/error.rs index c767ef8ab1..a3bd64eb05 100644 --- a/sn_networking/src/error.rs +++ b/sn_networking/src/error.rs @@ -30,11 +30,10 @@ pub(super) type Result = std::result::Result; #[derive(Error, Clone)] pub enum GetRecordError { #[error("Get Record completed with non enough copies")] - NotEnoughCopiesInRange { + NotEnoughCopies { record: Record, expected: usize, got: usize, - range: u32, }, #[error("Network query timed out")] QueryTimeout, @@ -57,18 +56,16 @@ pub enum GetRecordError { impl Debug for GetRecordError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::NotEnoughCopiesInRange { + Self::NotEnoughCopies { record, expected, got, - range, } => { let pretty_key = PrettyPrintRecordKey::from(&record.key); - f.debug_struct("NotEnoughCopiesInRange") + f.debug_struct("NotEnoughCopies") .field("record_key", &pretty_key) .field("expected", &expected) .field("got", &got) - .field("range", &range) .finish() } Self::QueryTimeout => write!(f, "QueryTimeout"), @@ -127,6 +124,9 @@ pub enum NetworkError { #[error("The RecordKind obtained from the Record did not match with the expected kind: {0}")] RecordKindMismatch(RecordKind), + #[error("Record header is incorrect")] + InCorrectRecordHeader, + // ---------- Transfer Errors #[error("Failed to get spend: {0}")] FailedToGetSpend(String), @@ -140,7 +140,7 @@ pub enum NetworkError { // ---------- Spend Errors #[error("Spend not found: {0:?}")] NoSpendFoundInsideRecord(SpendAddress), - #[error("Double SpendAttempt was detected. The signed spends are: {0:?}")] + #[error("Double spend(s) attempt was detected. The signed spends are: {0:?}")] DoubleSpendAttempt(Vec), // ---------- Store Error diff --git a/sn_networking/src/event/kad.rs b/sn_networking/src/event/kad.rs index de90a187d6..a2c0a4443c 100644 --- a/sn_networking/src/event/kad.rs +++ b/sn_networking/src/event/kad.rs @@ -7,23 +7,21 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{ - cmd::NetworkSwarmCmd, driver::PendingGetClosestType, get_quorum_value, target_arch::Instant, - GetRecordCfg, GetRecordError, NetworkError, Result, SwarmDriver, CLOSE_GROUP_SIZE, + driver::PendingGetClosestType, get_quorum_value, get_raw_signed_spends_from_record, + target_arch::Instant, GetRecordCfg, GetRecordError, NetworkError, Result, SwarmDriver, + CLOSE_GROUP_SIZE, }; use itertools::Itertools; -use libp2p::{ - kad::{ - self, GetClosestPeersError, InboundRequest, KBucketDistance, PeerRecord, ProgressStep, - QueryId, QueryResult, QueryStats, Quorum, Record, K_VALUE, - }, - PeerId, +use libp2p::kad::{ + self, GetClosestPeersError, InboundRequest, PeerRecord, ProgressStep, QueryId, QueryResult, + QueryStats, Record, K_VALUE, }; use sn_protocol::{ - messages::{Cmd, Request}, - storage::get_type_from_record, + storage::{try_serialize_record, RecordKind}, NetworkAddress, PrettyPrintRecordKey, }; -use std::collections::{hash_map::Entry, HashSet}; +use sn_transfers::SignedSpend; +use std::collections::{hash_map::Entry, BTreeSet, HashSet}; use tokio::sync::oneshot; use xor_name::XorName; @@ -33,9 +31,6 @@ impl SwarmDriver { let event_string; match kad_event { - // We use this query both to bootstrap and populate our routing table, - // but also to define our GetRange as defined by the largest distance between - // peers in any recent GetClosest call. kad::Event::OutboundQueryProgressed { id, result: QueryResult::GetClosestPeers(Ok(ref closest_peers)), @@ -50,7 +45,7 @@ impl SwarmDriver { ); if let Entry::Occupied(mut entry) = self.pending_get_closest_peers.entry(id) { - let (_, _, current_closest) = entry.get_mut(); + let (_, current_closest) = entry.get_mut(); // TODO: consider order the result and terminate when reach any of the // following criteria: @@ -58,19 +53,16 @@ impl SwarmDriver { // 2, `stats.duration()` is longer than a defined period current_closest.extend(closest_peers.peers.iter().map(|i| i.peer_id)); if current_closest.len() >= usize::from(K_VALUE) || step.last { - let (address, get_closest_type, current_closest) = entry.remove(); - self.network_discovery - .handle_get_closest_query(¤t_closest); - - if let PendingGetClosestType::FunctionCall(sender) = get_closest_type { - sender - .send(current_closest) - .map_err(|_| NetworkError::InternalMsgChannelDropped)?; - } else { - // do not set this via function calls, as that could potentially - // skew the results in favour of heavily queried (and manipulated) - // areas of the network - self.set_request_range(address, ¤t_closest); + let (get_closest_type, current_closest) = entry.remove(); + match get_closest_type { + PendingGetClosestType::NetworkDiscovery => self + .network_discovery + .handle_get_closest_query(current_closest), + PendingGetClosestType::FunctionCall(sender) => { + sender + .send(current_closest) + .map_err(|_| NetworkError::InternalMsgChannelDropped)?; + } } } } else { @@ -89,8 +81,9 @@ impl SwarmDriver { ref step, } => { event_string = "kad_event::get_closest_peers_err"; + error!("GetClosest Query task {id:?} errored with {err:?}, {stats:?} - {step:?}"); - let (address, get_closest_type, mut current_closest) = + let (get_closest_type, mut current_closest) = self.pending_get_closest_peers.remove(&id).ok_or_else(|| { debug!( "Can't locate query task {id:?}, it has likely been completed already." @@ -107,23 +100,13 @@ impl SwarmDriver { match err { GetClosestPeersError::Timeout { ref peers, .. } => { current_closest.extend(peers.iter().map(|i| i.peer_id)); - if current_closest.len() < CLOSE_GROUP_SIZE { - error!( - "GetClosest Query task {id:?} errored, not enough found. {err:?}, {stats:?} - {step:?}" - ); - } } } match get_closest_type { - PendingGetClosestType::NetworkDiscovery => { - // do not set this via function calls, as that could potentially - // skew the results in favour of heavily queried (and manipulated) - // areas of the network - self.set_request_range(address, ¤t_closest); - self.network_discovery - .handle_get_closest_query(¤t_closest); - } + PendingGetClosestType::NetworkDiscovery => self + .network_discovery + .handle_get_closest_query(current_closest), PendingGetClosestType::FunctionCall(sender) => { sender .send(current_closest) @@ -144,7 +127,7 @@ impl SwarmDriver { PrettyPrintRecordKey::from(&peer_record.record.key), peer_record.peer ); - self.accumulate_get_record_found(id, peer_record)?; + self.accumulate_get_record_found(id, peer_record, stats, step)?; } kad::Event::OutboundQueryProgressed { id, @@ -265,13 +248,12 @@ impl SwarmDriver { event_string = "kad_event::RoutingUpdated"; if is_new_peer { self.update_on_peer_addition(peer); - } - if !self.first_contact_made { // This should only happen once - self.first_contact_made = true; - info!("Performing the first bootstrap"); - self.trigger_network_discovery(); + if self.bootstrap.notify_new_peer() { + info!("Performing the first bootstrap"); + self.trigger_network_discovery(); + } } info!("kad_event::RoutingUpdated {:?}: {peer:?}, is_new_peer: {is_new_peer:?} old_peer: {old_peer:?}", self.peers_in_rt); @@ -338,7 +320,6 @@ impl SwarmDriver { // `QueryStats::requests` to be 20 (K-Value) // `QueryStats::success` to be over majority of the requests // `err::NotFound::closest_peers` contains a list of CLOSE_GROUP_SIZE peers - // // 2, targeting an existing entry // there will a sequence of (at least CLOSE_GROUP_SIZE) events of // `kad::Event::OutboundQueryProgressed` to be received @@ -352,30 +333,26 @@ impl SwarmDriver { // where: `cache_candidates`: being the peers supposed to hold the record but not // `ProgressStep::count`: to be `number of received copies plus one` // `ProgressStep::last` to be `true` - // - // /// Accumulates the GetRecord query results - /// If we get enough responses (ie exceed GetRange) for a record with the same content hash: + /// If we get enough responses (quorum) for a record with the same content hash: /// - we return the Record after comparing with the target record. This might return RecordDoesNotMatch if the /// check fails. /// - if multiple content hashes are found, we return a SplitRecord Error /// And then we stop the kad query as we are done here. - /// We do not need to wait for GetRange to be exceeded here and should return early. fn accumulate_get_record_found( &mut self, query_id: QueryId, peer_record: PeerRecord, + _stats: QueryStats, + step: ProgressStep, ) -> Result<()> { - let expected_get_range = self.get_request_range(); - let key = peer_record.record.key.clone(); - let peer_id = if let Some(peer_id) = peer_record.peer { peer_id } else { self.self_peer_id }; - let pretty_key = PrettyPrintRecordKey::from(&key).into_owned(); + let pretty_key = PrettyPrintRecordKey::from(&peer_record.record.key).into_owned(); if let Entry::Occupied(mut entry) = self.pending_get_record.entry(query_id) { let (_key, _senders, result_map, cfg) = entry.get_mut(); @@ -392,27 +369,83 @@ impl SwarmDriver { let record_content_hash = XorName::from_content(&peer_record.record.value); debug!("For record {pretty_key:?} task {query_id:?}, received a copy {peer_id:?} with content hash {record_content_hash:?}"); - let peer_list = + let responded_peers = if let Entry::Occupied(mut entry) = result_map.entry(record_content_hash) { let (_, peer_list) = entry.get_mut(); - let _ = peer_list.insert(peer_id); - peer_list.clone() + peer_list.len() } else { let mut peer_list = HashSet::new(); let _ = peer_list.insert(peer_id); - result_map.insert( - record_content_hash, - (peer_record.record.clone(), peer_list.clone()), - ); - - peer_list + result_map.insert(record_content_hash, (peer_record.record.clone(), peer_list)); + 1 }; - let responded_peers = peer_list.len(); + let expected_answers = get_quorum_value(&cfg.get_quorum); + debug!("Expecting {expected_answers:?} answers for record {pretty_key:?} task {query_id:?}, received {responded_peers} so far"); + + if responded_peers >= expected_answers { + if !cfg.expected_holders.is_empty() { + debug!("For record {pretty_key:?} task {query_id:?}, fetch completed with non-responded expected holders {:?}", cfg.expected_holders); + } + let cfg = cfg.clone(); + + // Remove the query task and consume the variables. + let (_key, senders, result_map, _) = entry.remove(); + + if result_map.len() == 1 { + Self::send_record_after_checking_target(senders, peer_record.record, &cfg)?; + } else { + debug!("For record {pretty_key:?} task {query_id:?}, fetch completed with split record"); + let mut accumulated_spends = BTreeSet::new(); + for (record, _) in result_map.values() { + match get_raw_signed_spends_from_record(record) { + Ok(spends) => { + accumulated_spends.extend(spends); + } + Err(_) => { + continue; + } + } + } + if !accumulated_spends.is_empty() { + info!("For record {pretty_key:?} task {query_id:?}, found split record for a spend, accumulated and sending them as a single record"); + let accumulated_spends = + accumulated_spends.into_iter().collect::>(); + + let bytes = try_serialize_record(&accumulated_spends, RecordKind::Spend)?; + + let new_accumulated_record = Record { + key: peer_record.record.key, + value: bytes.to_vec(), + publisher: None, + expires: None, + }; + for sender in senders { + let new_accumulated_record = new_accumulated_record.clone(); + + sender + .send(Ok(new_accumulated_record)) + .map_err(|_| NetworkError::InternalMsgChannelDropped)?; + } + } else { + for sender in senders { + let result_map = result_map.clone(); + sender + .send(Err(GetRecordError::SplitRecord { result_map })) + .map_err(|_| NetworkError::InternalMsgChannelDropped)?; + } + } + } - let expected_answers = cfg.get_quorum; - trace!("Expecting {expected_answers:?} answers to exceed {expected_get_range:?} for record {pretty_key:?} task {query_id:?}, received {responded_peers} so far"); + // Stop the query; possibly stops more nodes from being queried. + if let Some(mut query) = self.swarm.behaviour_mut().kademlia.query_mut(&query_id) { + query.finish(); + } + } else if usize::from(step.count) >= CLOSE_GROUP_SIZE { + debug!("For record {pretty_key:?} task {query_id:?}, got {:?} with {} versions so far.", + step.count, result_map.len()); + } } else { // return error if the entry cannot be found return Err(NetworkError::ReceivedKademliaEventDropped { @@ -423,96 +456,26 @@ impl SwarmDriver { Ok(()) } - /// Checks passed peers from a request and checks they are sufficiently spaced to - /// ensure we have searched enough of the network range as determined by our `get_range` - /// - /// We expect any conflicting records to have been reported prior to this check, - /// so we assume we're returning unique records only. - fn have_we_have_searched_thoroughly_for_quorum( - expected_get_range: KBucketDistance, - searched_peers_list: &HashSet, - data_key_address: &NetworkAddress, - quorum: &Quorum, - ) -> bool { - info!("Assessing search: range: {:?}, address: {data_key_address:?}, quorum required: {quorum:?}, peers_returned_count: {:?}", expected_get_range.ilog2(), searched_peers_list.len()); - let is_sensitive_data = matches!(quorum, Quorum::All); - - let required_quorum = get_quorum_value(quorum); - - let met_quorum = searched_peers_list.len() >= required_quorum; - - // we only enforce range if we have sensitive data...for data spends quorum::all - if met_quorum && !is_sensitive_data { - return true; - } - - // get the farthest distance between peers in the response - let mut max_distance_to_data_from_responded_nodes = KBucketDistance::default(); - - // iterate over peers and see if the distance to the data is greater than the get_range - for peer_id in searched_peers_list.iter() { - let peer_address = NetworkAddress::from_peer(*peer_id); - let distance_to_data = peer_address.distance(data_key_address); - if max_distance_to_data_from_responded_nodes < distance_to_data { - max_distance_to_data_from_responded_nodes = distance_to_data; - } - } - - // use ilog2 as simplified distance check - // It allows us to say "we've searched up to and including this bucket" - // as opposed to the concrete distance itself (which statistically seems like we can fall outwith a range - // quite easily with a small number of peers) - let exceeded_request_range = if max_distance_to_data_from_responded_nodes.ilog2() - < expected_get_range.ilog2() - { - let dist = max_distance_to_data_from_responded_nodes.ilog2(); - let expected_dist = expected_get_range.ilog2(); - - warn!("RANGE: {data_key_address:?} Insufficient GetRange searched. {dist:?} {expected_dist:?} {max_distance_to_data_from_responded_nodes:?} is less than expcted GetRange of {expected_get_range:?}"); - - false - } else { - true - }; - - // We assume a finalised query has searched as far as it can in libp2p - - if exceeded_request_range && met_quorum { - warn!("RANGE: {data_key_address:?} Request satisfied as exceeded request range : {exceeded_request_range:?} and Quorum satisfied with {:?} peers exceeding quorum {required_quorum:?}", searched_peers_list.len()); - return true; - } - - false - } - /// Handles the possible cases when a GetRecord Query completes. - /// The accumulate_get_record_found returns the record if the quorum is satisfied, but, if we have reached this point - /// then we did not get enough records or we got split records (which prevented the quorum to pass). - /// Returns the following errors: - /// RecordNotFound if the result_map is empty. - /// NotEnoughCopies if there is only a single content hash version. - /// SplitRecord if there are multiple content hash versions. + /// The accumulate_get_record_found returns the record if the quorum is satisfied + /// + /// If we have reached this point but did not got enough records, + /// or got split records (which prevented the quorum to pass), + /// returns the following errors: + /// RecordNotFound if the result_map is empty. + /// NotEnoughCopies if there is only a single content hash version. + /// SplitRecord if there are multiple content hash versions. fn handle_get_record_finished(&mut self, query_id: QueryId, step: ProgressStep) -> Result<()> { // return error if the entry cannot be found if let Some((r_key, senders, result_map, cfg)) = self.pending_get_record.remove(&query_id) { let num_of_versions = result_map.len(); let data_key_address = NetworkAddress::from_record_key(&r_key); - let expected_get_range = self.get_request_range(); - let all_seen_peers: HashSet<_> = result_map - .values() - .flat_map(|(_, peers)| peers) - .cloned() - .collect(); - let we_have_searched_thoroughly = Self::have_we_have_searched_thoroughly_for_quorum( - expected_get_range, - &all_seen_peers, - &data_key_address, - &cfg.get_quorum, - ); // we have a split record, return it if num_of_versions > 1 { - warn!("RANGE: Multiple versions ({num_of_versions}) found over range"); + warn!( + "Multiple versions ({num_of_versions}) found for record {data_key_address:?}!" + ); for sender in senders { sender .send(Err(GetRecordError::SplitRecord { @@ -521,16 +484,12 @@ impl SwarmDriver { .map_err(|_| NetworkError::InternalMsgChannelDropped)?; } - for (record, _peers) in result_map.values() { - self.reput_data_to_range(record, &data_key_address, &all_seen_peers)?; - } - return Ok(()); } // we have no results, bail if num_of_versions == 0 { - warn!("RANGE: No versions found!"); + debug!("No versions found for record {data_key_address:?}!"); for sender in senders { sender .send(Err(GetRecordError::RecordNotFound)) @@ -542,17 +501,15 @@ impl SwarmDriver { // if we have searched thoroughly, we can return the record if num_of_versions == 1 { let result = if let Some((record, peers)) = result_map.values().next() { - warn!("RANGE: one version found!"); + trace!("one version found for record {data_key_address:?}!"); - if we_have_searched_thoroughly { + if peers.len() >= get_quorum_value(&cfg.get_quorum) { Ok(record.clone()) } else { - self.reput_data_to_range(record, &data_key_address, &all_seen_peers)?; - Err(GetRecordError::NotEnoughCopiesInRange { + Err(GetRecordError::NotEnoughCopies { record: record.clone(), expected: get_quorum_value(&cfg.get_quorum), got: peers.len(), - range: expected_get_range.ilog2().unwrap_or(0), }) } } else { @@ -564,11 +521,6 @@ impl SwarmDriver { .send(result.clone()) .map_err(|_| NetworkError::InternalMsgChannelDropped)?; } - - #[cfg(feature = "open-metrics")] - if self.metrics_recorder.is_some() { - self.check_for_change_in_our_close_group(); - } } } else { debug!("Can't locate query task {query_id:?} during GetRecord finished. We might have already returned the result to the sender."); @@ -576,67 +528,6 @@ impl SwarmDriver { Ok(()) } - /// Repost data to the network if we didn't get enough responses. - fn reput_data_to_range( - &mut self, - record: &Record, - data_key_address: &NetworkAddress, - // all peers who responded with any version of the record - from_peers: &HashSet, - ) -> Result<()> { - let pretty_key = PrettyPrintRecordKey::from(&record.key); - // This should be a backstop... Quorum::All is the only one that enforces - // a full search of the network range. - info!("RANGE: {pretty_key:?} Query Finished: Not enough of the network has the record, or same state, we need to extend the range and PUT the data."); - - info!("Reputting data to network {pretty_key:?}..."); - - warn!("RANGE: {pretty_key:?} Query Finished: Not enough of the network has responded, we need PUT the data back into nodes in that range."); - - let record_type = get_type_from_record(record)?; - - let replicate_targets: HashSet<_> = self - .get_filtered_peers_exceeding_range_or_closest_nodes(data_key_address) - .iter() - .cloned() - .collect(); - - if from_peers == &replicate_targets { - warn!("RANGE: {pretty_key:?} We asked everyone we know of in that range already!"); - } - - // set holder to someone that has the data - let holder = NetworkAddress::from_peer( - from_peers - .iter() - .next() - .cloned() - .unwrap_or(self.self_peer_id), - ); - - for peer in replicate_targets { - warn!("Reputting data to {peer:?} for {pretty_key:?} if needed..."); - // Do not send to any peer that has already informed us - if from_peers.contains(&peer) { - continue; - } - - debug!("RANGE: (insufficient, so ) Sending data to unresponded peer: {peer:?} for {pretty_key:?}"); - - // nodes will try/fail to trplicate it from us, but grab from the network thereafter - self.queue_network_swarm_cmd(NetworkSwarmCmd::SendRequest { - req: Request::Cmd(Cmd::Replicate { - holder: holder.clone(), - keys: vec![(data_key_address.clone(), record_type.clone())], - }), - peer, - sender: None, - }); - } - - Ok(()) - } - /// Handles the possible cases when a kad GetRecord returns an error. /// If we get NotFound/QuorumFailed, we return a RecordNotFound error. Kad currently does not enforce any quorum. /// If we get a Timeout: diff --git a/sn_networking/src/event/request_response.rs b/sn_networking/src/event/request_response.rs index c46caa756e..5a8999703f 100644 --- a/sn_networking/src/event/request_response.rs +++ b/sn_networking/src/event/request_response.rs @@ -7,21 +7,17 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{ - cmd::NetworkSwarmCmd, log_markers::Marker, sort_peers_by_address_and_limit, MsgResponder, - NetworkError, NetworkEvent, SwarmDriver, CLOSE_GROUP_SIZE, + cmd::NetworkSwarmCmd, log_markers::Marker, sort_peers_by_address, MsgResponder, NetworkError, + NetworkEvent, SwarmDriver, CLOSE_GROUP_SIZE, }; -use libp2p::{ - kad::RecordKey, - request_response::{self, Message}, - PeerId, -}; -use rand::{rngs::OsRng, Rng}; +use itertools::Itertools; +use libp2p::request_response::{self, Message}; +use rand::{rngs::OsRng, thread_rng, Rng}; use sn_protocol::{ messages::{CmdResponse, Request, Response}, storage::RecordType, NetworkAddress, }; -use std::collections::HashMap; impl SwarmDriver { /// Forwards `Request` to the upper layers using `Sender`. Sends `Response` to the peers @@ -194,10 +190,6 @@ impl SwarmDriver { sender: NetworkAddress, incoming_keys: Vec<(NetworkAddress, RecordType)>, ) { - let peers = self.get_all_local_peers_excluding_self(); - let our_peer_id = self.self_peer_id; - let more_than_one_key = incoming_keys.len() > 1; - let holder = if let Some(peer_id) = sender.as_peer_id() { peer_id } else { @@ -210,12 +202,16 @@ impl SwarmDriver { incoming_keys.len() ); - // accept replication requests from all peers known peers within our GetRange - if !peers.contains(&holder) || holder == our_peer_id { - trace!("Holder {holder:?} is self or not in replication range."); + // accept replication requests from the K_VALUE peers away, + // giving us some margin for replication + let closest_k_peers = self.get_closest_k_value_local_peers(); + if !closest_k_peers.contains(&holder) || holder == self.self_peer_id { + debug!("Holder {holder:?} is self or not in replication range."); return; } + let more_than_one_key = incoming_keys.len() > 1; + // On receive a replication_list from a close_group peer, we undertake two tasks: // 1, For those keys that we don't have: // fetch them if close enough to us @@ -228,109 +224,81 @@ impl SwarmDriver { .behaviour_mut() .kademlia .store_mut() - .record_addresses_ref() - .clone(); - - let keys_to_fetch = - self.replication_fetcher - .add_keys(holder, incoming_keys, &all_keys, &peers); - + .record_addresses_ref(); + let keys_to_fetch = self + .replication_fetcher + .add_keys(holder, incoming_keys, all_keys); if keys_to_fetch.is_empty() { debug!("no waiting keys to fetch from the network"); } else { self.send_event(NetworkEvent::KeysToFetchForReplication(keys_to_fetch)); } - let event_sender = self.event_sender.clone(); - if more_than_one_key && OsRng.gen_bool(0.1) { - let _handle = tokio::spawn(async move { - // Only run 10% of the time - let keys_to_verify = - Self::select_verification_data_candidates(&peers, &all_keys, &sender); + // Only trigger chunk_proof check based every X% of the time + let mut rng = thread_rng(); + // 5% probability + if more_than_one_key && rng.gen_bool(0.05) { + self.verify_peer_storage(sender.clone()); - if keys_to_verify.is_empty() { - debug!("No valid candidate to be checked against peer {holder:?}"); - } else { - // choose one random key to verify - let key_to_verify = - keys_to_verify[OsRng.gen_range(0..keys_to_verify.len())].clone(); - if let Err(error) = event_sender - .send(NetworkEvent::ChunkProofVerification { - peer_id: holder, - key_to_verify, - }) - .await - { - error!("SwarmDriver failed to send event: {}", error); - } - } - - // In additon to verify the sender, we also verify a random close node. - // This is to avoid malicious node escaping the check by never send a replication_list. - // With further reduced probability of 1% (5% * 20%) - let close_group_peers = sort_peers_by_address_and_limit( - &peers, - &NetworkAddress::from_peer(our_peer_id), - CLOSE_GROUP_SIZE, - ) - .unwrap_or_default(); - - loop { - let index: usize = OsRng.gen_range(0..close_group_peers.len()); - let candidate_peer_id = *close_group_peers[index]; - let candidate = NetworkAddress::from_peer(*close_group_peers[index]); - if sender != candidate { - let keys_to_verify = Self::select_verification_data_candidates( - &peers, &all_keys, &candidate, - ); - - if keys_to_verify.is_empty() { - debug!("No valid candidate to be checked against peer {candidate:?}"); - } else { - // choose one random key to verify - let key_to_verify = - keys_to_verify[OsRng.gen_range(0..keys_to_verify.len())].clone(); - - if let Err(error) = event_sender - .send(NetworkEvent::ChunkProofVerification { - peer_id: candidate_peer_id, - key_to_verify, - }) - .await - { - error!("SwarmDriver failed to send event: {}", error); - } + // In additon to verify the sender, we also verify a random close node. + // This is to avoid malicious node escaping the check by never send a replication_list. + // With further reduced probability of 1% (5% * 20%) + if rng.gen_bool(0.2) { + let close_group_peers = self + .swarm + .behaviour_mut() + .kademlia + .get_closest_local_peers(&self.self_peer_id.into()) + .map(|peer| peer.into_preimage()) + .take(CLOSE_GROUP_SIZE) + .collect_vec(); + if close_group_peers.len() == CLOSE_GROUP_SIZE { + loop { + let index: usize = OsRng.gen_range(0..close_group_peers.len()); + let candidate = NetworkAddress::from_peer(close_group_peers[index]); + if sender != candidate { + self.verify_peer_storage(candidate); + break; } - - break; } } - }); + } } } /// Check among all chunk type records that we have, select those close to the peer, /// and randomly pick one as the verification candidate. - fn select_verification_data_candidates( - all_peers: &Vec, - all_keys: &HashMap, - peer: &NetworkAddress, - ) -> Vec { + fn verify_peer_storage(&mut self, peer: NetworkAddress) { + let mut closest_peers = self + .swarm + .behaviour_mut() + .kademlia + .get_closest_local_peers(&self.self_peer_id.into()) + .map(|peer| peer.into_preimage()) + .take(20) + .collect_vec(); + closest_peers.push(self.self_peer_id); + let target_peer = if let Some(peer_id) = peer.as_peer_id() { peer_id } else { error!("Target {peer:?} is not a valid PeerId"); - return vec![]; + return; }; + let all_keys = self + .swarm + .behaviour_mut() + .kademlia + .store_mut() + .record_addresses_ref(); + // Targeted chunk type record shall be expected within the close range from our perspective. let mut verify_candidates: Vec = all_keys .values() .filter_map(|(addr, record_type)| { if RecordType::Chunk == *record_type { - // Here we take the actual closest, as this is where we want to be - // strict about who does have the data... - match sort_peers_by_address_and_limit(all_peers, addr, CLOSE_GROUP_SIZE) { + match sort_peers_by_address(&closest_peers, addr, CLOSE_GROUP_SIZE) { Ok(close_group) => { if close_group.contains(&&target_peer) { Some(addr.clone()) @@ -351,6 +319,17 @@ impl SwarmDriver { verify_candidates.sort_by_key(|a| peer.distance(a)); - verify_candidates + // To ensure the candidate must have to be held by the peer, + // we only carry out check when there are already certain amount of chunks uploaded + // AND choose candidate from certain reduced range. + if verify_candidates.len() > 50 { + let index: usize = OsRng.gen_range(0..(verify_candidates.len() / 2)); + self.send_event(NetworkEvent::ChunkProofVerification { + peer_id: target_peer, + key_to_verify: verify_candidates[index].clone(), + }); + } else { + debug!("No valid candidate to be checked against peer {peer:?}"); + } } } diff --git a/sn_networking/src/event/swarm.rs b/sn_networking/src/event/swarm.rs index c4de69665d..f0fd69254e 100644 --- a/sn_networking/src/event/swarm.rs +++ b/sn_networking/src/event/swarm.rs @@ -244,7 +244,7 @@ impl SwarmDriver { } // If we are not local, we care only for peers that we dialed and thus are reachable. - if !self.local && has_dialed { + if self.local || has_dialed { // A bad node cannot establish a connection with us. So we can add it to the RT directly. self.remove_bootstrap_from_full(peer_id); @@ -254,10 +254,7 @@ impl SwarmDriver { multiaddr.iter().any(|p| matches!(p, Protocol::P2pCircuit)) }); } - } - if self.local || has_dialed { - // If we are not local, we care only for peers that we dialed and thus are reachable. debug!(%peer_id, ?addrs, "identify: attempting to add addresses to routing table"); // Attempt to add the addresses to the routing table. @@ -395,7 +392,6 @@ impl SwarmDriver { let _ = self.live_connected_peers.remove(&connection_id); self.record_connection_metrics(); - let mut failed_peer_addresses = vec![]; // we need to decide if this was a critical error and the peer should be removed from the routing table let should_clean_peer = match error { DialError::Transport(errors) => { @@ -405,14 +401,10 @@ impl SwarmDriver { // so we default to it not being a real issue // unless there are _specific_ errors (connection refused eg) error!("Dial errors len : {:?}", errors.len()); - let mut remove_peer_track_peer_issue = false; - for (addr, err) in errors { + let mut there_is_a_serious_issue = false; + for (_addr, err) in errors { error!("OutgoingTransport error : {err:?}"); - if !failed_peer_addresses.contains(&addr) { - failed_peer_addresses.push(addr) - } - match err { TransportError::MultiaddrNotSupported(addr) => { warn!("Multiaddr not supported : {addr:?}"); @@ -422,13 +414,14 @@ impl SwarmDriver { println!("If this was your bootstrap peer, restart your node with a supported multiaddr"); } // if we can't dial a peer on a given address, we should remove it from the routing table - remove_peer_track_peer_issue = false + there_is_a_serious_issue = true } TransportError::Other(err) => { - let problematic_errors = - ["ConnectionRefused", "HostUnreachable"]; - - let intermittent_errors = ["HandshakeTimedOut"]; + let problematic_errors = [ + "ConnectionRefused", + "HostUnreachable", + "HandshakeTimedOut", + ]; let is_bootstrap_peer = self .bootstrap_peers @@ -439,7 +432,7 @@ impl SwarmDriver { && self.peers_in_rt < self.bootstrap_peers.len() { warn!("OutgoingConnectionError: On bootstrap peer {failed_peer_id:?}, while still in bootstrap mode, ignoring"); - remove_peer_track_peer_issue = false; + there_is_a_serious_issue = false; } else { // It is really difficult to match this error, due to being eg: // Custom { kind: Other, error: Left(Left(Os { code: 61, kind: ConnectionRefused, message: "Connection refused" })) } @@ -450,19 +443,13 @@ impl SwarmDriver { .any(|err| error_msg.contains(err)) { warn!("Problematic error encountered: {error_msg}"); - remove_peer_track_peer_issue = true; - } else if intermittent_errors - .iter() - .any(|err| error_msg.contains(err)) - { - warn!("Intermittent error encountered: {error_msg}"); - remove_peer_track_peer_issue = false; + there_is_a_serious_issue = true; } } } } } - remove_peer_track_peer_issue + there_is_a_serious_issue } DialError::NoAddresses => { // We provided no address, and while we can't really blame the peer @@ -503,7 +490,7 @@ impl SwarmDriver { }; if should_clean_peer { - warn!("Serious issue with {failed_peer_id:?}. Clearing it out for now"); + warn!("Tracking issue of {failed_peer_id:?}. Clearing it out for now"); if let Some(dead_peer) = self .swarm diff --git a/sn_networking/src/lib.rs b/sn_networking/src/lib.rs index 01e5d6c9f6..e25c369954 100644 --- a/sn_networking/src/lib.rs +++ b/sn_networking/src/lib.rs @@ -83,6 +83,10 @@ use tokio::time::Duration; /// The type of quote for a selected payee. pub type PayeeQuote = (PeerId, RewardsAddress, PaymentQuote); +/// The count of peers that will be considered as close to a record target, +/// that a replication of the record shall be sent/accepted to/by the peer. +pub const REPLICATION_PEERS_COUNT: usize = CLOSE_GROUP_SIZE + 2; + /// Majority of a given group (i.e. > 1/2). #[inline] pub const fn close_group_majority() -> usize { @@ -98,47 +102,17 @@ const MIN_WAIT_BEFORE_READING_A_PUT: Duration = Duration::from_millis(300); /// Sort the provided peers by their distance to the given `NetworkAddress`. /// Return with the closest expected number of entries if has. -pub fn sort_peers_by_address_and_limit<'a>( +pub fn sort_peers_by_address<'a>( peers: &'a Vec, address: &NetworkAddress, expected_entries: usize, ) -> Result> { - sort_peers_by_key_and_limit(peers, &address.as_kbucket_key(), expected_entries) -} - -/// Sort the provided peers by their distance to the given `NetworkAddress`. -/// Return with the closest expected number of entries if has. -pub fn sort_peers_by_distance_to( - peers: &[PeerId], - queried_address: NetworkAddress, -) -> Vec { - let mut sorted_distances: Vec<_> = peers - .iter() - .map(|peer| { - let addr = NetworkAddress::from_peer(*peer); - queried_address.distance(&addr) - }) - .collect(); - - sorted_distances.sort(); - - sorted_distances -} - -/// Sort the provided peers by their distance to the given `NetworkAddress`. -/// Return with the closest expected number of entries if has. -#[allow(clippy::result_large_err)] -pub fn sort_peers_by_address_and_limit_by_distance<'a>( - peers: &'a Vec, - address: &NetworkAddress, - distance: KBucketDistance, -) -> Result> { - limit_peers_by_distance(peers, &address.as_kbucket_key(), distance) + sort_peers_by_key(peers, &address.as_kbucket_key(), expected_entries) } /// Sort the provided peers by their distance to the given `KBucketKey`. /// Return with the closest expected number of entries if has. -pub fn sort_peers_by_key_and_limit<'a, T>( +pub fn sort_peers_by_key<'a, T>( peers: &'a Vec, key: &KBucketKey, expected_entries: usize, @@ -175,40 +149,6 @@ pub fn sort_peers_by_key_and_limit<'a, T>( Ok(sorted_peers) } -/// Only return peers closer to key than the provided distance -/// Their distance is measured by closeness to the given `KBucketKey`. -/// Return with the closest expected number of entries if has. -#[allow(clippy::result_large_err)] -pub fn limit_peers_by_distance<'a, T>( - peers: &'a Vec, - key: &KBucketKey, - distance: KBucketDistance, -) -> Result> { - // Check if there are enough peers to satisfy the request. - // bail early if that's not the case - if CLOSE_GROUP_SIZE > peers.len() { - warn!("Not enough peers in the k-bucket to satisfy the request"); - return Err(NetworkError::NotEnoughPeers { - found: peers.len(), - required: CLOSE_GROUP_SIZE, - }); - } - - // Create a vector of tuples where each tuple is a reference to a peer and its distance to the key. - // This avoids multiple computations of the same distance in the sorting process. - let mut peers_within_distance: Vec<&PeerId> = Vec::with_capacity(peers.len()); - - for peer_id in peers { - let addr = NetworkAddress::from_peer(*peer_id); - let peer_distance = key.distance(&addr.as_kbucket_key()); - - if peer_distance < distance { - peers_within_distance.push(peer_id); - } - } - - Ok(peers_within_distance) -} #[derive(Clone, Debug)] /// API to interact with the underlying Swarm @@ -262,13 +202,6 @@ impl Network { &self.inner.local_swarm_cmd_sender } - /// Return the GetRange as determined by the internal SwarmDriver - pub async fn get_range(&self) -> Result { - let (sender, receiver) = oneshot::channel(); - self.send_local_swarm_cmd(LocalSwarmCmd::GetCurrentRequestRange { sender }); - receiver.await.map_err(NetworkError::from) - } - /// Signs the given data with the node's keypair. pub fn sign(&self, msg: &[u8]) -> Result> { self.keypair().sign(msg).map_err(NetworkError::from) @@ -292,115 +225,6 @@ impl Network { receiver.await? } - /// Replicate a fresh record to its close group peers. - /// This should not be triggered by a record we receive via replicaiton fetch - pub async fn replicate_valid_fresh_record(&self, paid_key: RecordKey, record_type: RecordType) { - let network = self; - - let start = std::time::Instant::now(); - let pretty_key = PrettyPrintRecordKey::from(&paid_key); - - // first we wait until our own network store can return the record - // otherwise it may not be fully written yet - let mut retry_count = 0; - trace!("Checking we have successfully stored the fresh record {pretty_key:?} in the store before replicating"); - loop { - let record = match network.get_local_record(&paid_key).await { - Ok(record) => record, - Err(err) => { - error!( - "Replicating fresh record {pretty_key:?} get_record_from_store errored: {err:?}" - ); - None - } - }; - - if record.is_some() { - break; - } - - if retry_count > 10 { - error!( - "Could not get record from store for replication: {pretty_key:?} after 10 retries" - ); - return; - } - - retry_count += 1; - tokio::time::sleep(std::time::Duration::from_millis(100)).await; - } - - trace!("Start replication of fresh record {pretty_key:?} from store"); - - let all_peers = match network.get_all_local_peers_excluding_self().await { - Ok(peers) => peers, - Err(err) => { - error!( - "Replicating fresh record {pretty_key:?} get_all_local_peers errored: {err:?}" - ); - return; - } - }; - - let data_addr = NetworkAddress::from_record_key(&paid_key); - let mut peers_to_replicate_to = match network.get_range().await { - Err(error) => { - error!("Replicating fresh record {pretty_key:?} get_range errored: {error:?}"); - - return; - } - - Ok(our_get_range) => { - match sort_peers_by_address_and_limit_by_distance( - &all_peers, - &data_addr, - our_get_range, - ) { - Ok(result) => result, - Err(err) => { - error!("When replicating fresh record {pretty_key:?}, sort error: {err:?}"); - return; - } - } - } - }; - - if peers_to_replicate_to.len() < CLOSE_GROUP_SIZE { - warn!( - "Replicating fresh record {pretty_key:?} current GetRange insufficient for secure replication. Falling back to CLOSE_GROUP_SIZE" - ); - - peers_to_replicate_to = - match sort_peers_by_address_and_limit(&all_peers, &data_addr, CLOSE_GROUP_SIZE) { - Ok(result) => result, - Err(err) => { - error!("When replicating fresh record {pretty_key:?}, sort error: {err:?}"); - return; - } - }; - } - - let our_peer_id = network.peer_id(); - let our_address = NetworkAddress::from_peer(our_peer_id); - #[allow(clippy::mutable_key_type)] // for Bytes in NetworkAddress - let keys = vec![(data_addr.clone(), record_type.clone())]; - - for peer_id in &peers_to_replicate_to { - trace!("Replicating fresh record {pretty_key:?} to {peer_id:?}"); - let request = Request::Cmd(Cmd::Replicate { - holder: our_address.clone(), - keys: keys.clone(), - }); - - network.send_req_ignore_reply(request, **peer_id); - } - trace!( - "Completed replicate fresh record {pretty_key:?} to {:?} peers on store, in {:?}", - peers_to_replicate_to.len(), - start.elapsed() - ); - } - /// 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( @@ -411,6 +235,14 @@ impl Network { .await } + /// Returns the closest peers to the given `NetworkAddress`, sorted by their distance to the key. + /// + /// Includes our node's `PeerId` while calculating the closest peers. + pub async fn node_get_closest_peers(&self, key: &NetworkAddress) -> Result> { + self.get_all_close_peers_in_range_or_close_group(key, false) + .await + } + /// Returns a map where each key is the ilog2 distance of that Kbucket and each value is a vector of peers in that /// bucket. /// Does not include self @@ -423,10 +255,10 @@ impl Network { } /// Returns all the PeerId from all the KBuckets from our local Routing Table - /// Excludes our own PeerId. - pub async fn get_all_local_peers_excluding_self(&self) -> Result> { + /// Also contains our own PeerId. + pub async fn get_closest_k_value_local_peers(&self) -> Result> { let (sender, receiver) = oneshot::channel(); - self.send_local_swarm_cmd(LocalSwarmCmd::GetAllLocalPeersExcludingSelf { sender }); + self.send_local_swarm_cmd(LocalSwarmCmd::GetClosestKLocalPeers { sender }); receiver .await @@ -715,7 +547,7 @@ impl Network { Err(GetRecordError::RecordDoesNotMatch(_)) => { warn!("The returned record does not match target {pretty_key:?}."); } - Err(GetRecordError::NotEnoughCopiesInRange { expected, got, .. }) => { + Err(GetRecordError::NotEnoughCopies { expected, got, .. }) => { warn!("Not enough copies ({got}/{expected}) found yet for {pretty_key:?}."); } // libp2p RecordNotFound does mean no holders answered. @@ -731,8 +563,8 @@ impl Network { Err(GetRecordError::SplitRecord { result_map }) => { error!("Encountered a split record for {pretty_key:?}."); if let Some(record) = Self::handle_split_record_error(result_map, &key)? { - info!("Merged the split record (register) for {pretty_key:?}, into a single record"); - return Ok(record); + info!("Merged the split record (register) for {pretty_key:?}, into a single record"); + return Ok(record); } } Err(GetRecordError::QueryTimeout) => { @@ -1205,15 +1037,14 @@ impl Network { debug!("Network knowledge of close peers to {key:?} are: {close_peers_pretty_print:?}"); } - let closest_peers = sort_peers_by_address_and_limit(&closest_peers, key, CLOSE_GROUP_SIZE)?; + let closest_peers = sort_peers_by_address(&closest_peers, key, CLOSE_GROUP_SIZE)?; Ok(closest_peers.into_iter().cloned().collect()) } /// Returns the closest peers to the given `XorName`, sorted by their distance to the xor_name. /// If `client` is false, then include `self` among the `closest_peers` - /// Returns all peers found inside the range /// - /// If less than CLOSE_GROUP_SIZE peers are found, it will return all the peers found up to the CLOSE_GROUP_SIZE + /// If less than CLOSE_GROUP_SIZE peers are found, it will return all the peers. pub async fn get_all_close_peers_in_range_or_close_group( &self, key: &NetworkAddress, @@ -1233,8 +1064,6 @@ impl Network { let result_len = found_peers.len(); let mut closest_peers = found_peers; - let expected_range = self.get_range().await?; - // ensure we're not including self here if client { // remove our peer id from the calculations here: @@ -1260,22 +1089,8 @@ impl Network { ); } - let mut restricted_closest_peers = - sort_peers_by_address_and_limit_by_distance(&closest_peers, key, expected_range)?; - - if restricted_closest_peers.len() < CLOSE_GROUP_SIZE { - warn!( - "Getting close peers to {pretty_key:?} current GetRange of {:?} too strict giving insufficient peers... Falling back to all peers found" - , expected_range.ilog2()); - - restricted_closest_peers = - sort_peers_by_address_and_limit(&closest_peers, key, CLOSE_GROUP_SIZE)?; - } - - debug!( - "Network knowledge of closest peers in range of {:?} to target {pretty_key:?} are: {:?}", expected_range.ilog2(), restricted_closest_peers.len() - ); - Ok(restricted_closest_peers.into_iter().cloned().collect()) + let closest_peers = sort_peers_by_address(&closest_peers, key, CLOSE_GROUP_SIZE)?; + Ok(closest_peers.into_iter().cloned().collect()) } /// Send a `Request` to the provided set of peers and wait for their responses concurrently. diff --git a/sn_networking/src/network_discovery.rs b/sn_networking/src/network_discovery.rs index 3d82c944fb..f3f4986134 100644 --- a/sn_networking/src/network_discovery.rs +++ b/sn_networking/src/network_discovery.rs @@ -8,6 +8,7 @@ use crate::target_arch::Instant; use libp2p::{kad::KBucketKey, PeerId}; +use rand::{thread_rng, Rng}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use sn_protocol::NetworkAddress; use std::collections::{btree_map::Entry, BTreeMap}; @@ -51,13 +52,13 @@ impl NetworkDiscovery { } /// The result from the kad::GetClosestPeers are again used to update our kbucket. - pub(crate) fn handle_get_closest_query(&mut self, closest_peers: &[PeerId]) { + pub(crate) fn handle_get_closest_query(&mut self, closest_peers: Vec) { let now = Instant::now(); let candidates_map: BTreeMap> = closest_peers - .iter() + .into_iter() .filter_map(|peer| { - let peer = NetworkAddress::from_peer(*peer); + let peer = NetworkAddress::from_peer(peer); let peer_key = peer.as_kbucket_key(); peer_key .distance(&self.self_key) @@ -82,28 +83,18 @@ impl NetworkDiscovery { /// Returns one random candidate per bucket. Also tries to refresh the candidate list. /// Todo: Limit the candidates to return. Favor the closest buckets. - pub(crate) fn candidates(&mut self) -> Vec { - let mut op = Vec::with_capacity(self.candidates.len()); - - let mut generate_fresh_candidates = false; - for addresses in self.candidates.values_mut() { - // get a random candidate from each bucket each time - if addresses.is_empty() { - generate_fresh_candidates = true; - continue; - } + pub(crate) fn candidates(&mut self) -> Vec<&NetworkAddress> { + self.try_refresh_candidates(); - // remove the first each time - let address = addresses.remove(0); - op.push(address); - } - - if generate_fresh_candidates { - // we only refresh when we are running low on candidates - self.try_refresh_candidates(); - } + let mut rng = thread_rng(); + let mut op = Vec::with_capacity(self.candidates.len()); - debug!("Candidates returned: {}", op.len()); + let candidates = self.candidates.values().filter_map(|candidates| { + // get a random index each time + let random_index = rng.gen::() % candidates.len(); + candidates.get(random_index) + }); + op.extend(candidates); op } diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index 254ec6380a..a976ed26b4 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -90,7 +90,7 @@ pub struct NodeRecordStore { /// ilog2 distance range of responsible records /// AKA: how many buckets of data do we consider "close" /// None means accept all records. - responsible_distance_range: Option, + responsible_distance_range: Option, #[cfg(feature = "open-metrics")] /// Used to report the number of records held by the store to the metrics server. record_count_metric: Option, @@ -315,6 +315,11 @@ impl NodeRecordStore { self } + /// Returns the current distance ilog2 (aka bucket) range of CLOSE_GROUP nodes. + pub fn get_responsible_distance_range(&self) -> Option { + self.responsible_distance_range + } + // Converts a Key into a Hex string. fn generate_filename(key: &Key) -> String { hex::encode(key.as_ref()) @@ -460,14 +465,16 @@ impl NodeRecordStore { return; } - let responsible_range = if let Some(range) = self.responsible_distance_range { + let max_bucket = if let Some(range) = self.responsible_distance_range { + // avoid the distance_range is a default value + if range == 0 { + return; + } range } else { return; }; - let max_bucket = responsible_range.ilog2().unwrap_or_default(); - // Collect keys to remove from buckets beyond our range let keys_to_remove: Vec = self .records_by_bucket @@ -698,10 +705,8 @@ impl NodeRecordStore { pub fn get_records_within_distance_range( &self, _records: HashSet<&Key>, - max_distance: Distance, + max_bucket: u32, ) -> usize { - let max_bucket = max_distance.ilog2().unwrap_or_default(); - let within_range = self .records_by_bucket .iter() @@ -715,8 +720,8 @@ impl NodeRecordStore { } /// Setup the distance range. - pub(crate) fn set_responsible_distance_range(&mut self, farthest_distance: Distance) { - self.responsible_distance_range = Some(farthest_distance); + pub(crate) fn set_responsible_distance_range(&mut self, farthest_responsible_bucket: u32) { + self.responsible_distance_range = Some(farthest_responsible_bucket); } } @@ -1511,7 +1516,10 @@ mod tests { .wrap_err("Could not parse record store key")?, ); // get the distance to this record from our local key - let distance = self_address.distance(&halfway_record_address); + let distance = self_address + .distance(&halfway_record_address) + .ilog2() + .unwrap_or(0); // must be plus one bucket from the halfway record store.set_responsible_distance_range(distance); diff --git a/sn_networking/src/record_store_api.rs b/sn_networking/src/record_store_api.rs index 53cea6701e..31eb650294 100644 --- a/sn_networking/src/record_store_api.rs +++ b/sn_networking/src/record_store_api.rs @@ -10,7 +10,7 @@ use crate::record_store::{ClientRecordStore, NodeRecordStore}; use libp2p::kad::{ store::{RecordStore, Result}, - KBucketDistance, ProviderRecord, Record, RecordKey, + ProviderRecord, Record, RecordKey, }; use sn_evm::{AttoTokens, QuotingMetrics}; use sn_protocol::{storage::RecordType, NetworkAddress}; @@ -130,7 +130,17 @@ impl UnifiedRecordStore { } } - pub(crate) fn set_distance_range(&mut self, distance: KBucketDistance) { + pub(crate) fn get_farthest_replication_distance_bucket(&self) -> Option { + match self { + Self::Client(_store) => { + warn!("Calling get_distance_range at Client. This should not happen"); + None + } + Self::Node(store) => store.get_responsible_distance_range(), + } + } + + pub(crate) fn set_distance_range(&mut self, distance: u32) { match self { Self::Client(_store) => { warn!("Calling set_distance_range at Client. This should not happen"); diff --git a/sn_networking/src/replication_fetcher.rs b/sn_networking/src/replication_fetcher.rs index 1858d65350..edff49f9f9 100644 --- a/sn_networking/src/replication_fetcher.rs +++ b/sn_networking/src/replication_fetcher.rs @@ -8,9 +8,7 @@ #![allow(clippy::mutable_key_type)] use crate::target_arch::spawn; -use crate::CLOSE_GROUP_SIZE; use crate::{event::NetworkEvent, target_arch::Instant}; -use itertools::Itertools; use libp2p::{ kad::{KBucketDistance as Distance, RecordKey, K_VALUE}, PeerId, @@ -43,8 +41,8 @@ pub(crate) struct ReplicationFetcher { // Avoid fetching same chunk from different nodes AND carry out too many parallel tasks. on_going_fetches: HashMap<(RecordKey, RecordType), (PeerId, ReplicationTimeout)>, event_sender: mpsc::Sender, - /// KBucketDistance range that the incoming key shall be fetched - distance_range: Option, + /// ilog2 bucket distance range that the incoming key shall be fetched + distance_range: Option, /// Restrict fetch range to closer than this value /// used when the node is full, but we still have "close" data coming in /// that is _not_ closer than our farthest max record @@ -65,7 +63,7 @@ impl ReplicationFetcher { } /// Set the distance range. - pub(crate) fn set_replication_distance_range(&mut self, distance_range: Distance) { + pub(crate) fn set_replication_distance_range(&mut self, distance_range: u32) { self.distance_range = Some(distance_range); } @@ -78,7 +76,6 @@ impl ReplicationFetcher { holder: PeerId, incoming_keys: Vec<(NetworkAddress, RecordType)>, locally_stored_keys: &HashMap, - all_local_peers: &[PeerId], ) -> Vec<(PeerId, RecordKey)> { // Pre-calculate self_address since it's used multiple times let self_address = NetworkAddress::from_peer(self.self_peer_id); @@ -135,29 +132,13 @@ impl ReplicationFetcher { self.to_be_fetched .retain(|_, time_out| *time_out > Instant::now()); + let mut out_of_range_keys = vec![]; // Filter out those out_of_range ones among the incoming_keys. if let Some(ref distance_range) = self.distance_range { new_incoming_keys.retain(|(addr, _record_type)| { - // find all closer peers to the data - let closer_peers_len = all_local_peers - .iter() - .filter(|peer_id| { - let peer_address = NetworkAddress::from_peer(**peer_id); - addr.distance(&peer_address) <= *distance_range - }) - .collect_vec() - .len(); - - // we consider ourselves in range if - // A) We don't know enough closer peers than ourselves - // or B) The distance to the data is within our GetRange - let is_in_range = closer_peers_len <= CLOSE_GROUP_SIZE - || self_address.distance(addr).ilog2() <= distance_range.ilog2(); + let is_in_range = + self_address.distance(addr).ilog2().unwrap_or(0) <= *distance_range; if !is_in_range { - warn!( - "Rejecting incoming key: {addr:?} as out of range. {:?} is larger than {:?} ", - self_address.distance(addr).ilog2(), - distance_range.ilog2()); out_of_range_keys.push(addr.clone()); } is_in_range @@ -449,12 +430,8 @@ mod tests { incoming_keys.push((key, RecordType::Chunk)); }); - let keys_to_fetch = replication_fetcher.add_keys( - PeerId::random(), - incoming_keys, - &locally_stored_keys, - &[], - ); + let keys_to_fetch = + replication_fetcher.add_keys(PeerId::random(), incoming_keys, &locally_stored_keys); assert_eq!(keys_to_fetch.len(), MAX_PARALLEL_FETCH); // we should not fetch anymore keys @@ -466,7 +443,6 @@ mod tests { PeerId::random(), vec![(key_1, RecordType::Chunk), (key_2, RecordType::Chunk)], &locally_stored_keys, - &[], ); assert!(keys_to_fetch.is_empty()); @@ -477,7 +453,6 @@ mod tests { PeerId::random(), vec![(key, RecordType::Chunk)], &locally_stored_keys, - &[], ); assert!(!keys_to_fetch.is_empty()); @@ -503,41 +478,34 @@ mod tests { let mut replication_fetcher = ReplicationFetcher::new(peer_id, event_sender); // Set distance range - // way to update this test let distance_target = NetworkAddress::from_peer(PeerId::random()); - let distance_range = self_address.distance(&distance_target); + let distance_range = self_address.distance(&distance_target).ilog2().unwrap_or(1); replication_fetcher.set_replication_distance_range(distance_range); - // generate a list of close peers - let close_peers = (0..100).map(|_| PeerId::random()).collect::>(); - let mut incoming_keys = Vec::new(); let mut in_range_keys = 0; (0..100).for_each(|_| { let random_data: Vec = (0..50).map(|_| rand::random::()).collect(); let key = NetworkAddress::from_record_key(&RecordKey::from(random_data)); - if key.distance(&self_address).ilog2() <= distance_range.ilog2() { + if key.distance(&self_address).ilog2().unwrap_or(0) <= distance_range { in_range_keys += 1; } incoming_keys.push((key, RecordType::Chunk)); }); - let keys_to_fetch = replication_fetcher.add_keys( - PeerId::random(), - incoming_keys, - &Default::default(), - &close_peers, - ); + let keys_to_fetch = + replication_fetcher.add_keys(PeerId::random(), incoming_keys, &Default::default()); assert_eq!( keys_to_fetch.len(), replication_fetcher.on_going_fetches.len(), "keys to fetch and ongoing fetches should match" ); - assert!( - keys_to_fetch.len() + replication_fetcher.to_be_fetched.len() >= in_range_keys, - "at least all keys in range should be in the fetcher" + assert_eq!( + in_range_keys, + keys_to_fetch.len() + replication_fetcher.to_be_fetched.len(), + "all keys should be in range and in the fetcher" ); } } diff --git a/sn_networking/src/transfers.rs b/sn_networking/src/transfers.rs index 40c6182f94..76b6349ce1 100644 --- a/sn_networking/src/transfers.rs +++ b/sn_networking/src/transfers.rs @@ -6,7 +6,9 @@ // 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 crate::{driver::GetRecordCfg, Network, NetworkError, Result}; +use crate::{ + close_group_majority, driver::GetRecordCfg, GetRecordError, Network, NetworkError, Result, +}; use libp2p::kad::{Quorum, Record}; use sn_protocol::{ storage::{try_deserialize_record, RecordHeader, RecordKind, RetryStrategy, SpendAddress}, @@ -37,7 +39,7 @@ impl Network { }; let record = self.get_record_from_network(key.clone(), &get_cfg).await?; debug!( - "Got raw spends from the network, {:?}", + "Got record from the network, {:?}", PrettyPrintRecordKey::from(&record.key) ); get_raw_signed_spends_from_record(&record) @@ -49,14 +51,38 @@ impl Network { /// If we get a quorum error, we increase the RetryStrategy pub async fn get_spend(&self, address: SpendAddress) -> Result { let key = NetworkAddress::from_spend_address(address).to_record_key(); - let get_cfg = GetRecordCfg { + let mut get_cfg = GetRecordCfg { get_quorum: Quorum::All, retry_strategy: Some(RetryStrategy::Quick), target_record: None, expected_holders: Default::default(), is_register: false, }; - let record = self.get_record_from_network(key.clone(), &get_cfg).await?; + let record = match self.get_record_from_network(key.clone(), &get_cfg).await { + Ok(record) => record, + Err(NetworkError::GetRecordError(GetRecordError::NotEnoughCopies { + record, + expected, + got, + })) => { + // if majority holds the spend, it might be worth to be trusted. + if got >= close_group_majority() { + debug!("At least a majority nodes hold the spend {address:?}, going to trust it if can fetch with majority again."); + get_cfg.get_quorum = Quorum::Majority; + get_cfg.retry_strategy = Some(RetryStrategy::Balanced); + self.get_record_from_network(key, &get_cfg).await? + } else { + return Err(NetworkError::GetRecordError( + GetRecordError::NotEnoughCopies { + record, + expected, + got, + }, + )); + } + } + Err(err) => return Err(err), + }; debug!( "Got record from the network, {:?}", PrettyPrintRecordKey::from(&record.key) diff --git a/sn_node/src/put_validation.rs b/sn_node/src/put_validation.rs index 224fc3bcb9..d08e1e7d28 100644 --- a/sn_node/src/put_validation.rs +++ b/sn_node/src/put_validation.rs @@ -564,7 +564,7 @@ impl Node { }; debug!( - "Found {} spends with key: {unique_pubkey:?} at {pretty_key:?}", + "Got {} validated spends with key: {unique_pubkey:?} at {pretty_key:?}", validated_spends.len() ); @@ -576,12 +576,14 @@ impl Node { expires: None, }; self.network().put_local_record(record); - debug!("Successfully stored spends with key: {unique_pubkey:?} at {pretty_key:?}"); + debug!( + "Successfully stored validated spends with key: {unique_pubkey:?} at {pretty_key:?}" + ); // Just log the double spend attempt. DoubleSpend error during PUT is not used and would just lead to // RecordRejected marker (which is incorrect, since we store double spends). if validated_spends.len() > 1 { - warn!("Got Burnt SpendAttempts of len {} for the Spend PUT with unique_pubkey {unique_pubkey} at {pretty_key:?}", validated_spends.len()); + warn!("Got double spend(s) of len {} for the Spend PUT with unique_pubkey {unique_pubkey}", validated_spends.len()); } self.record_metrics(Marker::ValidSpendRecordPutFromNetwork(&pretty_key)); @@ -772,14 +774,13 @@ impl Node { } spends } - Err(NetworkError::GetRecordError(GetRecordError::NotEnoughCopiesInRange { + Err(NetworkError::GetRecordError(GetRecordError::NotEnoughCopies { record, got, - range, .. })) => { info!( - "Retrieved {got} copies of the record for {unique_pubkey:?} from the network in range {range}" + "Retrieved {got} copies of the record for {unique_pubkey:?} from the network" ); match get_raw_signed_spends_from_record(&record) { Ok(spends) => spends, diff --git a/sn_node/src/replication.rs b/sn_node/src/replication.rs index bc3496b750..d6e123c524 100644 --- a/sn_node/src/replication.rs +++ b/sn_node/src/replication.rs @@ -6,18 +6,15 @@ // 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 crate::{ - error::{Error, Result}, - node::Node, -}; +use crate::{error::Result, node::Node}; use libp2p::{ kad::{Quorum, Record, RecordKey}, PeerId, }; -use sn_networking::{GetRecordCfg, Network}; +use sn_networking::{sort_peers_by_address, GetRecordCfg, Network, REPLICATION_PEERS_COUNT}; use sn_protocol::{ - messages::{Query, QueryResponse, Request, Response}, - storage::{try_serialize_record, RecordKind, RecordType}, + messages::{Cmd, Query, QueryResponse, Request, Response}, + storage::RecordType, NetworkAddress, PrettyPrintRecordKey, }; use tokio::task::spawn; @@ -82,27 +79,12 @@ impl Node { // Hence value of the flag actually doesn't matter. is_register: false, }; - match node - .network() - .get_record_from_network(key.clone(), &get_cfg) - .await - { + match node.network().get_record_from_network(key, &get_cfg).await { Ok(record) => record, - Err(error) => match error { - sn_networking::NetworkError::DoubleSpendAttempt(spends) => { - debug!("Failed to fetch record {pretty_key:?} from the network, double spend attempt {spends:?}"); - - let bytes = try_serialize_record(&spends, RecordKind::Spend)?; - - Record { - key, - value: bytes.to_vec(), - publisher: None, - expires: None, - } - } - other_error => return Err(other_error.into()), - }, + Err(err) => { + error!("During replication fetch of {pretty_key:?}, failed in re-attempt of get from network {err:?}"); + return; + } } }; @@ -114,7 +96,6 @@ impl Node { } else { debug!("Completed storing Replication Record {pretty_key:?} from network."); } - Ok::<(), Error>(()) }); } Ok(()) @@ -130,9 +111,86 @@ impl Node { let network = self.network().clone(); let _handle = spawn(async move { - network - .replicate_valid_fresh_record(paid_key, record_type) - .await; + let start = std::time::Instant::now(); + let pretty_key = PrettyPrintRecordKey::from(&paid_key); + + // first we wait until our own network store can return the record + // otherwise it may not be fully written yet + let mut retry_count = 0; + debug!("Checking we have successfully stored the fresh record {pretty_key:?} in the store before replicating"); + loop { + let record = match network.get_local_record(&paid_key).await { + Ok(record) => record, + Err(err) => { + error!( + "Replicating fresh record {pretty_key:?} get_record_from_store errored: {err:?}" + ); + None + } + }; + + if record.is_some() { + break; + } + + if retry_count > 10 { + error!( + "Could not get record from store for replication: {pretty_key:?} after 10 retries" + ); + return; + } + + retry_count += 1; + tokio::time::sleep(std::time::Duration::from_millis(100)).await; + } + + debug!("Start replication of fresh record {pretty_key:?} from store"); + + // Already contains self_peer_id + let mut closest_k_peers = match network.get_closest_k_value_local_peers().await { + Ok(peers) => peers, + Err(err) => { + error!("Replicating fresh record {pretty_key:?} get_closest_local_peers errored: {err:?}"); + return; + } + }; + + // remove ourself from these calculations + closest_k_peers.retain(|peer_id| peer_id != &network.peer_id()); + + let data_addr = NetworkAddress::from_record_key(&paid_key); + + let sorted_based_on_addr = match sort_peers_by_address( + &closest_k_peers, + &data_addr, + REPLICATION_PEERS_COUNT, + ) { + Ok(result) => result, + Err(err) => { + error!( + "When replicating fresh record {pretty_key:?}, having error when sort {err:?}" + ); + return; + } + }; + + let our_peer_id = network.peer_id(); + let our_address = NetworkAddress::from_peer(our_peer_id); + let keys = vec![(data_addr.clone(), record_type.clone())]; + + for peer_id in sorted_based_on_addr { + debug!("Replicating fresh record {pretty_key:?} to {peer_id:?}"); + let request = Request::Cmd(Cmd::Replicate { + holder: our_address.clone(), + keys: keys.clone(), + }); + + network.send_req_ignore_reply(request, *peer_id); + } + debug!( + "Completed replicate fresh record {pretty_key:?} on store, in {:?}", + start.elapsed() + ); }); } } diff --git a/sn_node/tests/double_spend.rs b/sn_node/tests/double_spend.rs index 21ba72d619..8d06a87187 100644 --- a/sn_node/tests/double_spend.rs +++ b/sn_node/tests/double_spend.rs @@ -13,19 +13,18 @@ // use common::client::{get_client_and_funded_wallet, get_wallet}; // use eyre::{bail, Result}; // use itertools::Itertools; -// use sn_logging::LogBuilder; -// use sn_networking::NetworkError; // use sn_transfers::{ -// get_genesis_sk, rng, DerivationIndex, HotWallet, NanoTokens, SignedTransaction, SpendReason, -// WalletError, GENESIS_CASHNOTE, +// get_genesis_sk, rng, NanoTokens, DerivationIndex, HotWallet, SignedTransaction, +// SpendReason, WalletError, GENESIS_CASHNOTE, // }; +// use sn_logging::LogBuilder; +// use sn_networking::NetworkError; // use std::time::Duration; // use tracing::*; // #[tokio::test] // async fn cash_note_transfer_double_spend_fail() -> Result<()> { -// let _log_guards = -// LogBuilder::init_single_threaded_tokio_test("cash_note_transfer_double_spend_fail", true); +// let _log_guards = LogBuilder::init_single_threaded_tokio_test("double_spend", true); // // create 1 wallet add money from faucet // let first_wallet_dir = TempDir::new()?; @@ -41,7 +40,7 @@ // assert_eq!(third_wallet.balance(), NanoTokens::zero()); // // manually forge two transfers of the same source -// let amount = NanoTokens::from(first_wallet_balance / 3); +// let amount = first_wallet_balance / 3; // let to1 = first_wallet.address(); // let to2 = second_wallet.address(); // let to3 = third_wallet.address(); @@ -71,50 +70,31 @@ // )?; // // send both transfers to the network - +// // upload won't error out, only error out during verification. // info!("Sending both transfers to the network..."); -// // These may error (but may not depending on network speed) -// // so we're not going to rely on it here. -// let _ = client.send_spends(transfer_to_2.spends.iter(), true).await; +// let res = client.send_spends(transfer_to_2.spends.iter(), false).await; +// assert!(res.is_ok()); +// let res = client.send_spends(transfer_to_3.spends.iter(), false).await; +// assert!(res.is_ok()); -// let _ = client.send_spends(transfer_to_3.spends.iter(), true).await; - -// // check the CashNotes, it should fail -// info!("Verifying the transfers from first wallet..."); +// // we wait 5s to ensure that the double spend attempt is detected and accumulated +// info!("Verifying the transfers from first wallet... Sleeping for 10 seconds."); +// tokio::time::sleep(Duration::from_secs(10)).await; // let cash_notes_for_2: Vec<_> = transfer_to_2.output_cashnotes.clone(); // let cash_notes_for_3: Vec<_> = transfer_to_3.output_cashnotes.clone(); -// let mut should_err1 = client.verify_cashnote(&cash_notes_for_2[0]).await; -// let mut should_err2 = client.verify_cashnote(&cash_notes_for_3[0]).await; - -// for i in 0..5 { -// if should_err1.is_err() && should_err2.is_err() { -// break; -// } - -// tokio::time::sleep(Duration::from_secs(1)).await; -// info!("Retrying verification.{i}... for should_err1+2"); -// println!("Retrying verification{i} ... for should_err1+2"); -// should_err1 = client.verify_cashnote(&cash_notes_for_2[0]).await; -// should_err2 = client.verify_cashnote(&cash_notes_for_3[0]).await; -// } - -// info!("Both should fail during GET record accumulation + Double SpendAttempt should be flagged: {should_err1:?} {should_err2:?}"); -// println!("Both should fail during GET record accumulation + Double SpendAttempt should be flagged: {should_err1:?} {should_err2:?}"); +// // check the CashNotes, it should fail +// let should_err1 = client.verify_cashnote(&cash_notes_for_2[0]).await; +// let should_err2 = client.verify_cashnote(&cash_notes_for_3[0]).await; +// info!("Both should fail during GET record accumulation : {should_err1:?} {should_err2:?}"); // assert!(should_err1.is_err() && should_err2.is_err()); - -// assert_eq!( -// format!("{should_err1:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpend error, was: {should_err1:?}" -// ); - -// assert_eq!( -// format!("{should_err2:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpend error, was: {should_err2:?}" -// ); +// assert_matches!(should_err1, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); +// assert_matches!(should_err2, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); // Ok(()) // } @@ -188,7 +168,7 @@ // )?; // // send the transfer to the network which should reject it -// let res = client.send_spends(transfer2.spends.iter(), true).await; +// let res = client.send_spends(transfer2.spends.iter(), false).await; // std::mem::drop(exclusive_access); // assert_matches!(res, Err(WalletError::CouldNotSendMoney(_))); @@ -204,8 +184,8 @@ // let wallet_dir_1 = TempDir::new()?; // let (client, mut wallet_1) = get_client_and_funded_wallet(wallet_dir_1.path()).await?; -// let balance_1 = wallet_1.balance().as_nano(); -// let amount = NanoTokens::from(balance_1 / 2); +// let balance_1 = wallet_1.balance(); +// let amount = balance_1 / 2; // let to1 = wallet_1.address(); // // Send from 1 -> 2 @@ -282,18 +262,14 @@ // reason.clone(), // wallet_1.key(), // )?; // reuse the old cash notes -// // ignore response in case it errors out early, we verify below -// let _res = client.send_spends(transfer_to_3.spends.iter(), true).await; +// client +// .send_spends(transfer_to_3.spends.iter(), false) +// .await?; // info!("Verifying the transfers from 1 -> 3 wallet... It should error out."); // let cash_notes_for_3: Vec<_> = transfer_to_3.output_cashnotes.clone(); - -// let res = client.verify_cashnote(&cash_notes_for_3[0]).await; -// assert!(res.is_err(), "should be error, was {res:?}"); // the old spend has been poisoned - +// assert!(client.verify_cashnote(&cash_notes_for_3[0]).await.is_err()); // the old spend has been poisoned // info!("Verifying the original transfers from 1 -> 2 wallet... It should error out."); - -// let res = client.verify_cashnote(&cash_notes_for_2[0]).await; -// assert!(res.is_err(), "should be error, was {res:?}"); // the old spend has been poisoned +// assert!(client.verify_cashnote(&cash_notes_for_2[0]).await.is_err()); // the old spend has been poisoned // // The old spend has been poisoned, but spends from 22 -> 222 should still work // let wallet_dir_222 = TempDir::new()?; @@ -324,16 +300,16 @@ // client.verify_cashnote(&cash_notes_for_222[0]).await?; // // finally assert that we have a double spend attempt error here -// // we wait to ensure that the double spend attempt is detected and accumulated +// // we wait 1s to ensure that the double spend attempt is detected and accumulated // tokio::time::sleep(Duration::from_secs(5)).await; // match client.verify_cashnote(&cash_notes_for_2[0]).await { // Ok(_) => bail!("Cashnote verification should have failed"), // Err(e) => { -// assert_eq!( -// e.to_string(), -// format!("{}", WalletError::BurntSpend), -// "error should reflect double spend attempt was: {e:?}", +// assert!( +// e.to_string() +// .contains("Network Error Double spend(s) attempt was detected"), +// "error should reflect double spend attempt", // ); // } // } @@ -341,10 +317,10 @@ // match client.verify_cashnote(&cash_notes_for_3[0]).await { // Ok(_) => bail!("Cashnote verification should have failed"), // Err(e) => { -// assert_eq!( -// e.to_string(), -// format!("{}", WalletError::BurntSpend), -// "error should reflect double spend attempt was: {e:?}", +// assert!( +// e.to_string() +// .contains("Network Error Double spend(s) attempt was detected"), +// "error should reflect double spend attempt", // ); // } // } @@ -363,7 +339,7 @@ // let (client, mut wallet_a) = get_client_and_funded_wallet(wallet_dir_a.path()).await?; // let balance_a = wallet_a.balance().as_nano(); -// let amount = NanoTokens::from(balance_a / 2); +// let amount = balance_a / 2; // // Send from A -> B // let wallet_dir_b = TempDir::new()?; @@ -452,10 +428,12 @@ // let result = client.verify_cashnote(&cash_notes_for_x[0]).await; // info!("Got result while verifying double spend from A -> X: {result:?}"); -// assert!( -// format!("{result:?}").starts_with("Err(UnexpectedParentSpends"), -// "Should have been UnexpectedParentSpends error, was: {result:?}" -// ); +// // sleep for a bit to allow the network to process and accumulate the double spend +// tokio::time::sleep(Duration::from_secs(10)).await; + +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); // poisoned // // Try to double spend from B -> Y // let wallet_dir_y = TempDir::new()?; @@ -492,48 +470,32 @@ // let result = client.verify_cashnote(&cash_notes_for_y[0]).await; // info!("Got result while verifying double spend from B -> Y: {result:?}"); -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpent error, was: {result:?}" -// ); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); // info!("Verifying the original cashnote of A -> B"); - -// // arbitrary time sleep to allow for network accumulation of double spend. -// tokio::time::sleep(Duration::from_secs(1)).await; - // let result = client.verify_cashnote(&cash_notes_for_b[0]).await; // info!("Got result while verifying the original spend from A -> B: {result:?}"); -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpent error, was: {result:?}" -// ); - -// println!("Verifying the original cashnote of B -> C"); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); +// info!("Verifying the original cashnote of B -> C"); // let result = client.verify_cashnote(&cash_notes_for_c[0]).await; // info!("Got result while verifying the original spend from B -> C: {result:?}"); -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpent error, was: {result:?}" -// ); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }, "result should be verify error, it was {result:?}"); // let result = client.verify_cashnote(&cash_notes_for_y[0]).await; -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpent error, was: {result:?}" -// ); - +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }, "result should be verify error, it was {result:?}"); // let result = client.verify_cashnote(&cash_notes_for_b[0]).await; -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend), -// "Should have been BurntSpent error, was: {result:?}" -// ); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }, "result should be verify error, it was {result:?}"); // Ok(()) // } @@ -549,8 +511,8 @@ // let wallet_dir_a = TempDir::new()?; // let (client, mut wallet_a) = get_client_and_funded_wallet(wallet_dir_a.path()).await?; -// let balance_a = wallet_a.balance().as_nano(); -// let amount = NanoTokens::from(balance_a / 2); +// let balance_a = wallet_a.balance(); +// let amount = balance_a / 2; // // Send from A -> B // let wallet_dir_b = TempDir::new()?; @@ -612,7 +574,7 @@ // )?; // client -// .send_spends(transfer_to_c.spends.iter(), true) +// .send_spends(transfer_to_c.spends.iter(), false) // .await?; // info!("Verifying the transfers from B -> C wallet..."); @@ -649,10 +611,9 @@ // let result = client.verify_cashnote(&cash_notes_for_x[0]).await; // info!("Got result while verifying double spend from A -> X: {result:?}"); -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend) -// ); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); // // the original A should still be present as one of the double spends // let res = client @@ -688,23 +649,20 @@ // reason.clone(), // wallet_a.key(), // )?; // reuse the old cash notes - -// // we actually don't care about the result here, we just want to spam the network with double spends -// let _ = client.send_spends(transfer_to_y.spends.iter(), false).await; - -// // and then we verify the double spend attempt +// client +// .send_spends(transfer_to_y.spends.iter(), false) +// .await?; // info!("Verifying the transfers from A -> Y wallet... It should error out."); // let cash_notes_for_y: Vec<_> = transfer_to_y.output_cashnotes.clone(); // // sleep for a bit to allow the network to process and accumulate the double spend -// tokio::time::sleep(Duration::from_millis(1500)).await; +// tokio::time::sleep(Duration::from_millis(500)).await; // let result = client.verify_cashnote(&cash_notes_for_y[0]).await; // info!("Got result while verifying double spend from A -> Y: {result:?}"); -// assert_eq!( -// format!("{result:?}"), -// format!("Err({:?})", WalletError::BurntSpend) -// ); +// assert_matches!(result, Err(WalletError::CouldNotVerifyTransfer(str)) => { +// assert!(str.starts_with("Network Error Double spend(s) attempt was detected"), "Expected double spend, but got {str}"); +// }); // // the original A should still be present as one of the double spends // let res = client diff --git a/sn_node/tests/storage_payments.rs b/sn_node/tests/storage_payments.rs index d36f680ca2..23fe9c53b0 100644 --- a/sn_node/tests/storage_payments.rs +++ b/sn_node/tests/storage_payments.rs @@ -14,6 +14,7 @@ // use libp2p::PeerId; // use rand::Rng; // use sn_client::{Error as ClientError, FilesDownload, Uploader, WalletClient}; +// use sn_evm::{Amount, AttoTokens, PaymentQuote}; // use sn_logging::LogBuilder; // use sn_networking::{GetRecordError, NetworkError}; // use sn_protocol::{ @@ -22,7 +23,6 @@ // NetworkAddress, // }; // use sn_registers::Permissions; -// use sn_transfers::{MainPubkey, NanoTokens, PaymentQuote}; // use std::collections::BTreeMap; // use tokio::time::{sleep, Duration}; // use tracing::info; @@ -80,7 +80,7 @@ // let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); // let subset_len = chunks.len() / 3; -// let res = wallet_client +// let _storage_cost = wallet_client // .pay_for_storage( // chunks // .clone() @@ -88,15 +88,7 @@ // .take(subset_len) // .map(|(name, _)| NetworkAddress::ChunkAddress(ChunkAddress::new(name))), // ) -// .await; - -// // if the payment failed, we can log that -// if let Err(error) = res { -// tracing::warn!( -// "Payment failed, (though that doesn't really break this test): {:?}", -// error -// ); -// } +// .await?; // // now let's request to upload all addresses, even that we've already paid for a subset of them // let verify_store = false; @@ -119,7 +111,7 @@ // let paying_wallet_dir: TempDir = TempDir::new()?; // let (client, paying_wallet) = get_client_and_funded_wallet(paying_wallet_dir.path()).await?; -// let wallet_original_balance = paying_wallet.balance().as_nano(); +// let wallet_original_balance = paying_wallet.balance().as_atto(); // let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); // // generate a random number (between 50 and 100) of random addresses @@ -143,10 +135,10 @@ // .ok_or(eyre!("Total storage cost exceed possible token amount"))?; // // check we've paid only for the subset of addresses, 1 nano per addr -// let new_balance = NanoTokens::from(wallet_original_balance - total_cost.as_nano()); +// let new_balance = AttoTokens::from_atto(wallet_original_balance - total_cost.as_atto()); // info!("Verifying new balance on paying wallet is {new_balance} ..."); // let paying_wallet = wallet_client.into_wallet(); -// assert_eq!(paying_wallet.balance(), new_balance); +// // assert_eq!(paying_wallet.balance(), new_balance);// TODO adapt to evm // // let's verify payment proofs for the subset have been cached in the wallet // assert!(random_content_addrs @@ -168,12 +160,13 @@ // .ok_or(eyre!("Total storage cost exceed possible token amount"))?; // // check we've paid only for addresses we haven't previously paid for, 1 nano per addr -// let new_balance = NanoTokens::from( -// wallet_original_balance - (random_content_addrs.len() as u64 * total_cost.as_nano()), +// let new_balance = AttoTokens::from_atto( +// wallet_original_balance - (Amount::from(random_content_addrs.len()) * total_cost.as_atto()), // ); // println!("Verifying new balance on paying wallet is now {new_balance} ..."); // let paying_wallet = wallet_client.into_wallet(); -// assert_eq!(paying_wallet.balance(), new_balance); +// // TODO adapt to evm +// // assert_eq!(paying_wallet.balance(), new_balance); // // let's verify payment proofs now for all addresses have been cached in the wallet // // assert!(random_content_addrs @@ -236,16 +229,18 @@ // no_data_payments.insert( // *chunk_name, // ( -// MainPubkey::new(bls::SecretKey::random().public_key()), -// PaymentQuote::test_dummy(*chunk_name, NanoTokens::from(0)), +// sn_evm::utils::dummy_address(), +// PaymentQuote::test_dummy(*chunk_name, AttoTokens::from_u64(0)), // PeerId::random().to_bytes(), // ), // ); // } -// let _ = wallet_client -// .mut_wallet() -// .local_send_storage_payment(&no_data_payments)?; +// // TODO adapt to evm +// // let _ = wallet_client +// // .mut_wallet() +// // .send_storage_payment(&no_data_payments) +// // .await?; // sleep(Duration::from_secs(5)).await; @@ -253,131 +248,131 @@ // .upload_test_bytes(content_bytes.clone(), false) // .await?; -// // info!("Reading {content_addr:?} expected to fail"); -// // let mut files_download = FilesDownload::new(files_api); -// // assert!( -// // matches!( -// // files_download.download_file(content_addr, None).await, -// // Err(ClientError::Network(NetworkError::GetRecordError( -// // GetRecordError::RecordNotFound -// // ))) -// // ), -// // "read bytes should fail as we didn't store them" -// // ); +// info!("Reading {content_addr:?} expected to fail"); +// let mut files_download = FilesDownload::new(files_api); +// assert!( +// matches!( +// files_download.download_file(content_addr, None).await, +// Err(ClientError::Network(NetworkError::GetRecordError( +// GetRecordError::RecordNotFound +// ))) +// ), +// "read bytes should fail as we didn't store them" +// ); -// // Ok(()) -// // } +// Ok(()) +// } -// // #[tokio::test] -// // async fn storage_payment_register_creation_succeeds() -> Result<()> { -// // let _log_guards = LogBuilder::init_single_threaded_tokio_test("storage_payments", true); +// #[tokio::test] +// async fn storage_payment_register_creation_succeeds() -> Result<()> { +// let _log_guards = LogBuilder::init_single_threaded_tokio_test("storage_payments", true); -// // let paying_wallet_dir = TempDir::new()?; +// let paying_wallet_dir = TempDir::new()?; -// // let (client, paying_wallet) = get_client_and_funded_wallet(paying_wallet_dir.path()).await?; -// // let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); +// let (client, paying_wallet) = get_client_and_funded_wallet(paying_wallet_dir.path()).await?; +// let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); -// // let mut rng = rand::thread_rng(); -// // let xor_name = XorName::random(&mut rng); -// // let address = RegisterAddress::new(xor_name, client.signer_pk()); -// // let net_addr = NetworkAddress::from_register_address(address); -// // info!("Paying for random Register address {net_addr:?} ..."); +// let mut rng = rand::thread_rng(); +// let xor_name = XorName::random(&mut rng); +// let address = RegisterAddress::new(xor_name, client.signer_pk()); +// let net_addr = NetworkAddress::from_register_address(address); +// info!("Paying for random Register address {net_addr:?} ..."); -// // let _cost = wallet_client -// // .pay_for_storage(std::iter::once(net_addr)) -// // .await?; +// let _cost = wallet_client +// .pay_for_storage(std::iter::once(net_addr)) +// .await?; -// // let (mut register, _cost, _royalties_fees) = client -// // .create_and_pay_for_register(xor_name, &mut wallet_client, true, Permissions::default()) -// // .await?; +// let (mut register, _cost, _royalties_fees) = client +// .create_and_pay_for_register(xor_name, &mut wallet_client, true, Permissions::default()) +// .await?; -// // println!("Newly created register has {} ops", register.read().len()); +// println!("Newly created register has {} ops", register.read().len()); -// // let retrieved_reg = client.get_register(address).await?; +// let retrieved_reg = client.get_register(address).await?; -// // assert_eq!(register.read(), retrieved_reg.read()); +// assert_eq!(register.read(), retrieved_reg.read()); -// // let random_entry = rng.gen::<[u8; 32]>().to_vec(); +// let random_entry = rng.gen::<[u8; 32]>().to_vec(); -// // register.write(&random_entry)?; +// register.write(&random_entry)?; -// // println!( -// // "Register has {} ops after first write", -// // register.read().len() -// // ); +// println!( +// "Register has {} ops after first write", +// register.read().len() +// ); -// // register.sync(&mut wallet_client, true, None).await?; +// register.sync(&mut wallet_client, true, None).await?; -// // let retrieved_reg = client.get_register(address).await?; +// let retrieved_reg = client.get_register(address).await?; -// // assert_eq!(retrieved_reg.read().iter().next().unwrap().1, random_entry); +// assert_eq!(retrieved_reg.read().iter().next().unwrap().1, random_entry); -// // assert_eq!(retrieved_reg.read().len(), 1); +// assert_eq!(retrieved_reg.read().len(), 1); -// // for index in 1..10 { -// // println!("current index is {index}"); -// // let random_entry = rng.gen::<[u8; 32]>().to_vec(); +// for index in 1..10 { +// println!("current index is {index}"); +// let random_entry = rng.gen::<[u8; 32]>().to_vec(); -// // register.write(&random_entry)?; -// // register.sync(&mut wallet_client, true, None).await?; +// register.write(&random_entry)?; +// register.sync(&mut wallet_client, true, None).await?; -// // let retrieved_reg = client.get_register(address).await?; +// let retrieved_reg = client.get_register(address).await?; -// // println!( -// // "current retrieved register entry length is {}", -// // retrieved_reg.read().len() -// // ); -// // println!("current expected entry length is {}", register.read().len()); +// println!( +// "current retrieved register entry length is {}", +// retrieved_reg.read().len() +// ); +// println!("current expected entry length is {}", register.read().len()); -// // println!( -// // "current retrieved register ops length is {}", -// // retrieved_reg.ops.len() -// // ); -// // println!("current local cached ops length is {}", register.ops.len()); +// println!( +// "current retrieved register ops length is {}", +// retrieved_reg.ops.len() +// ); +// println!("current local cached ops length is {}", register.ops.len()); -// // assert_eq!(retrieved_reg.read().len(), register.read().len()); +// assert_eq!(retrieved_reg.read().len(), register.read().len()); -// // assert_eq!(retrieved_reg.read().iter().next().unwrap().1, random_entry); +// assert_eq!(retrieved_reg.read().iter().next().unwrap().1, random_entry); -// // println!("Current fetched register is {:?}", retrieved_reg.register); -// // println!( -// // "Fetched register has update history of {}", -// // retrieved_reg.register.log_update_history() -// // ); +// println!("Current fetched register is {:?}", retrieved_reg.register); +// println!( +// "Fetched register has update history of {}", +// retrieved_reg.register.log_update_history() +// ); -// // std::thread::sleep(std::time::Duration::from_millis(1000)); -// // } +// std::thread::sleep(std::time::Duration::from_millis(1000)); +// } -// // Ok(()) -// // } +// Ok(()) +// } -// // #[tokio::test] -// // #[ignore = "Test currently invalid as we always try to pay and upload registers if none found... need to check if this test is valid"] -// // async fn storage_payment_register_creation_and_mutation_fails() -> Result<()> { -// // let _log_guards = LogBuilder::init_single_threaded_tokio_test("storage_payments", true); +// #[tokio::test] +// #[ignore = "Test currently invalid as we always try to pay and upload registers if none found... need to check if this test is valid"] +// async fn storage_payment_register_creation_and_mutation_fails() -> Result<()> { +// let _log_guards = LogBuilder::init_single_threaded_tokio_test("storage_payments", true); -// // let paying_wallet_dir = TempDir::new()?; +// let paying_wallet_dir = TempDir::new()?; -// // let (client, paying_wallet) = get_client_and_funded_wallet(paying_wallet_dir.path()).await?; -// // let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); +// let (client, paying_wallet) = get_client_and_funded_wallet(paying_wallet_dir.path()).await?; +// let mut wallet_client = WalletClient::new(client.clone(), paying_wallet); -// // let mut rng = rand::thread_rng(); -// // let xor_name = XorName::random(&mut rng); -// // let address = RegisterAddress::new(xor_name, client.signer_pk()); -// // let net_address = -// // NetworkAddress::RegisterAddress(RegisterAddress::new(xor_name, client.signer_pk())); +// let mut rng = rand::thread_rng(); +// let xor_name = XorName::random(&mut rng); +// let address = RegisterAddress::new(xor_name, client.signer_pk()); +// let net_address = +// NetworkAddress::RegisterAddress(RegisterAddress::new(xor_name, client.signer_pk())); -// // let mut no_data_payments = BTreeMap::default(); -// // no_data_payments.insert( -// // net_address -// // .as_xorname() -// // .expect("RegisterAddress should convert to XorName"), -// // ( -// // sn_evm::utils::dummy_address(), -// // PaymentQuote::test_dummy(xor_name, AttoTokens::from_u64(0)), -// // vec![], -// // ), -// // ); +// let mut no_data_payments = BTreeMap::default(); +// no_data_payments.insert( +// net_address +// .as_xorname() +// .expect("RegisterAddress should convert to XorName"), +// ( +// sn_evm::utils::dummy_address(), +// PaymentQuote::test_dummy(xor_name, AttoTokens::from_u64(0)), +// vec![], +// ), +// ); // println!( // "current retrieved register entry length is {}", @@ -400,16 +395,16 @@ // // .send_storage_payment(&no_data_payments) // // .await?; -// // // this should fail to store as the amount paid is not enough -// // let (mut register, _cost, _royalties_fees) = client -// // .create_and_pay_for_register(xor_name, &mut wallet_client, false, Permissions::default()) -// // .await?; +// // this should fail to store as the amount paid is not enough +// let (mut register, _cost, _royalties_fees) = client +// .create_and_pay_for_register(xor_name, &mut wallet_client, false, Permissions::default()) +// .await?; -// // sleep(Duration::from_secs(5)).await; -// // assert!(matches!( -// // client.get_register(address).await, -// // Err(ClientError::Protocol(ProtocolError::RegisterNotFound(addr))) if *addr == address -// // )); +// sleep(Duration::from_secs(5)).await; +// assert!(matches!( +// client.get_register(address).await, +// Err(ClientError::Protocol(ProtocolError::RegisterNotFound(addr))) if *addr == address +// )); // println!("Current fetched register is {:?}", retrieved_reg.address()); // println!( @@ -420,11 +415,11 @@ // let random_entry = rng.gen::<[u8; 32]>().to_vec(); // register.write(&random_entry)?; -// // sleep(Duration::from_secs(5)).await; -// // assert!(matches!( -// // register.sync(&mut wallet_client, false, None).await, -// // Err(ClientError::Protocol(ProtocolError::RegisterNotFound(addr))) if *addr == address -// // )); +// sleep(Duration::from_secs(5)).await; +// assert!(matches!( +// register.sync(&mut wallet_client, false, None).await, +// Err(ClientError::Protocol(ProtocolError::RegisterNotFound(addr))) if *addr == address +// )); -// // Ok(()) -// // } +// Ok(()) +// } diff --git a/sn_node/tests/verify_data_location.rs b/sn_node/tests/verify_data_location.rs index 8649d07909..641756fa2c 100644 --- a/sn_node/tests/verify_data_location.rs +++ b/sn_node/tests/verify_data_location.rs @@ -16,10 +16,13 @@ use common::{ get_all_peer_ids, get_safenode_rpc_client, NodeRestart, }; use eyre::{eyre, Result}; -use libp2p::{kad::RecordKey, PeerId}; +use libp2p::{ + kad::{KBucketKey, RecordKey}, + PeerId, +}; use rand::{rngs::OsRng, Rng}; use sn_logging::LogBuilder; -use sn_networking::{sleep, sort_peers_by_address_and_limit, sort_peers_by_key_and_limit}; +use sn_networking::{sleep, sort_peers_by_key}; use sn_protocol::{ safenode_proto::{NodeInfoRequest, RecordAddressesRequest}, NetworkAddress, PrettyPrintRecordKey, CLOSE_GROUP_SIZE, @@ -157,8 +160,8 @@ fn print_node_close_groups(all_peers: &[PeerId]) { for (node_index, peer) in all_peers.iter().enumerate() { let key = NetworkAddress::from_peer(*peer).as_kbucket_key(); - let closest_peers = sort_peers_by_key_and_limit(&all_peers, &key, CLOSE_GROUP_SIZE) - .expect("failed to sort peer"); + let closest_peers = + sort_peers_by_key(&all_peers, &key, CLOSE_GROUP_SIZE).expect("failed to sort peer"); let closest_peers_idx = closest_peers .iter() .map(|&&peer| { @@ -209,12 +212,11 @@ async fn verify_location(all_peers: &Vec, node_rpc_addresses: &[SocketAd for (key, actual_holders_idx) in record_holders.iter() { println!("Verifying {:?}", PrettyPrintRecordKey::from(key)); info!("Verifying {:?}", PrettyPrintRecordKey::from(key)); - let record_address = NetworkAddress::from_record_key(key); - let expected_holders = - sort_peers_by_address_and_limit(all_peers, &record_address, CLOSE_GROUP_SIZE)? - .into_iter() - .cloned() - .collect::>(); + let record_key = KBucketKey::from(key.to_vec()); + let expected_holders = sort_peers_by_key(all_peers, &record_key, CLOSE_GROUP_SIZE)? + .into_iter() + .cloned() + .collect::>(); let actual_holders = actual_holders_idx .iter() diff --git a/sn_node/tests/verify_routing_table.rs b/sn_node/tests/verify_routing_table.rs index 85dc2e3a09..da19270b69 100644 --- a/sn_node/tests/verify_routing_table.rs +++ b/sn_node/tests/verify_routing_table.rs @@ -26,7 +26,7 @@ use tracing::{error, info, trace}; /// Sleep for sometime for the nodes for discover each other before verification /// Also can be set through the env variable of the same name. -const SLEEP_BEFORE_VERIFICATION: Duration = Duration::from_secs(60); +const SLEEP_BEFORE_VERIFICATION: Duration = Duration::from_secs(5); #[tokio::test(flavor = "multi_thread")] async fn verify_routing_table() -> Result<()> { diff --git a/sn_protocol/src/error.rs b/sn_protocol/src/error.rs index 2d24feb0d9..7db10f9612 100644 --- a/sn_protocol/src/error.rs +++ b/sn_protocol/src/error.rs @@ -81,7 +81,4 @@ pub enum Error { // The record already exists at this node #[error("The record already exists, so do not charge for it: {0:?}")] RecordExists(PrettyPrintRecordKey<'static>), - - #[error("Record header is incorrect")] - IncorrectRecordHeader, } diff --git a/sn_protocol/src/storage.rs b/sn_protocol/src/storage.rs index 3a6b4ba6a8..2935e43fce 100644 --- a/sn_protocol/src/storage.rs +++ b/sn_protocol/src/storage.rs @@ -18,10 +18,7 @@ use std::{str::FromStr, time::Duration}; pub use self::{ address::{ChunkAddress, RegisterAddress, ScratchpadAddress, SpendAddress}, chunks::Chunk, - header::{ - get_type_from_record, try_deserialize_record, try_serialize_record, RecordHeader, - RecordKind, RecordType, - }, + header::{try_deserialize_record, try_serialize_record, RecordHeader, RecordKind, RecordType}, scratchpad::Scratchpad, }; diff --git a/sn_protocol/src/storage/header.rs b/sn_protocol/src/storage/header.rs index af43c21256..96a4515526 100644 --- a/sn_protocol/src/storage/header.rs +++ b/sn_protocol/src/storage/header.rs @@ -84,33 +84,6 @@ impl Display for RecordKind { } } -/// Return the RecordType -pub fn get_type_from_record(record: &Record) -> Result { - let key = record.key.clone(); - let record_key = PrettyPrintRecordKey::from(&key); - - match RecordHeader::from_record(record) { - Ok(record_header) => match record_header.kind { - RecordKind::Chunk => Ok(RecordType::Chunk), - RecordKind::Scratchpad => Ok(RecordType::Scratchpad), - RecordKind::Spend | RecordKind::Register => { - let content_hash = XorName::from_content(&record.value); - Ok(RecordType::NonChunk(content_hash)) - } - RecordKind::ChunkWithPayment - | RecordKind::RegisterWithPayment - | RecordKind::ScratchpadWithPayment => { - error!("Record {record_key:?} with payment shall not be stored locally."); - Err(Error::IncorrectRecordHeader) - } - }, - Err(err) => { - error!("For record {record_key:?}, failed to parse record_header {err:?}"); - Err(Error::IncorrectRecordHeader) - } - } -} - impl RecordHeader { pub const SIZE: usize = 2; diff --git a/sn_transfers/src/wallet/error.rs b/sn_transfers/src/wallet/error.rs index f60b718f42..5a57b7434a 100644 --- a/sn_transfers/src/wallet/error.rs +++ b/sn_transfers/src/wallet/error.rs @@ -40,19 +40,9 @@ pub enum Error { /// A general error when receiving a transfer fails #[error("Failed to receive transfer due to {0}")] CouldNotReceiveMoney(String), - /// A spend has been burnt (ie there was a DoubleSpendAttempt) - #[error("Failed to verify transfer validity in the network, a burnt SpendAttempt was found")] - BurntSpend, - /// Parents of a spend were not as expected in a provided cash note - #[error("Failed to verify transfer's parents in the network, transfer could be invalid or a parent double spent")] - UnexpectedParentSpends(crate::SpendAddress), - ///No valid unspent cashnotes found - #[error("All the redeemed CashNotes are already spent")] - AllRedeemedCashnotesSpent, /// A general error when verifying a transfer validity in the network #[error("Failed to verify transfer validity in the network {0}")] CouldNotVerifyTransfer(String), - /// Failed to fetch spend from network #[error("Failed to fetch spend from network: {0}")] FailedToGetSpend(String), From 4af2ed57ae51d8666f67f0a38b0817fed7ffc567 Mon Sep 17 00:00:00 2001 From: qima Date: Wed, 30 Oct 2024 06:25:34 +0800 Subject: [PATCH 02/24] fix(node): ignore timestamp elapsed call failure --- sn_evm/src/data_payments.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sn_evm/src/data_payments.rs b/sn_evm/src/data_payments.rs index 688d11b621..4ae3fb93b9 100644 --- a/sn_evm/src/data_payments.rs +++ b/sn_evm/src/data_payments.rs @@ -244,17 +244,29 @@ impl PaymentQuote { return false; } + // TODO: Double check if this applies, as this will prevent a node restart with same ID + if new_quote.quoting_metrics.received_payment_count + < old_quote.quoting_metrics.received_payment_count + { + info!("claimed received_payment_count out of sequence"); + return false; + } + let old_elapsed = if let Ok(elapsed) = old_quote.timestamp.elapsed() { elapsed } else { - info!("timestamp failure"); - return false; + // The elapsed call could fail due to system clock change + // hence consider the verification succeeded. + info!("old_quote timestamp elapsed call failure"); + return true; }; let new_elapsed = if let Ok(elapsed) = new_quote.timestamp.elapsed() { elapsed } else { - info!("timestamp failure"); - return false; + // The elapsed call could fail due to system clock change + // hence consider the verification succeeded. + info!("new_quote timestamp elapsed call failure"); + return true; }; let time_diff = old_elapsed.as_secs().saturating_sub(new_elapsed.as_secs()); @@ -275,14 +287,6 @@ impl PaymentQuote { old_quote.quoting_metrics.close_records_stored ); - // TODO: Double check if this applies, as this will prevent a node restart with same ID - if new_quote.quoting_metrics.received_payment_count - < old_quote.quoting_metrics.received_payment_count - { - info!("claimed received_payment_count out of sequence"); - return false; - } - true } } From ef9b81ce0ab934547f3ee823454b9d288869ed6d Mon Sep 17 00:00:00 2001 From: qima Date: Tue, 29 Oct 2024 18:31:27 +0800 Subject: [PATCH 03/24] fix(node): fairly pick verification candidates --- sn_node/src/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sn_node/src/node.rs b/sn_node/src/node.rs index 204067879a..d73fa9985c 100644 --- a/sn_node/src/node.rs +++ b/sn_node/src/node.rs @@ -718,10 +718,10 @@ impl Node { // The `rolling_index` is rotating among 0-511, // meanwhile the returned `kbuckets` only holding non-empty buckets. // Hence using the `remainder` calculate to achieve a rolling check. - // A further `divide by 2` is used to allow `upper or lower part` index within - // a bucket, to further reduce the concurrent queries. + // A further `remainder of 2` is used to allow `upper or lower part` + // index within a bucket, to further reduce the concurrent queries. let mut bucket_index = (rolling_index / 2) % kbuckets.len(); - let part_index = rolling_index / 2; + let part_index = rolling_index % 2; for (distance, peers) in kbuckets.iter() { if bucket_index == 0 { From 5146831883754dd8403ac596ceb4d9c88093d0f2 Mon Sep 17 00:00:00 2001 From: qima Date: Thu, 31 Oct 2024 08:14:59 +0800 Subject: [PATCH 04/24] chore(node): create a RecordCache struct --- sn_networking/src/record_store.rs | 109 ++++++++++++++++++------------ 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index a976ed26b4..0a3a5fa537 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -35,7 +35,6 @@ use sn_protocol::{ storage::{RecordHeader, RecordKind, RecordType}, NetworkAddress, PrettyPrintRecordKey, }; -use std::collections::VecDeque; use std::{ borrow::Cow, collections::{HashMap, HashSet}, @@ -68,6 +67,54 @@ const MAX_STORE_COST: u64 = 1_000_000; // Min store cost for a chunk. const MIN_STORE_COST: u64 = 1; +/// FIFO simple cache of records to reduce read times +struct RecordCache { + records_cache: HashMap, + cache_size: usize, +} + +impl RecordCache { + fn new(cache_size: usize) -> Self { + RecordCache { + records_cache: HashMap::new(), + cache_size, + } + } + + fn remove(&mut self, key: &Key) -> Option<(Record, SystemTime)> { + self.records_cache.remove(key) + } + + fn get(&self, key: &Key) -> Option<&(Record, SystemTime)> { + self.records_cache.get(key) + } + + fn push_back(&mut self, key: Key, record: Record) { + self.free_up_space(); + + let _ = self.records_cache.insert(key, (record, SystemTime::now())); + } + + fn free_up_space(&mut self) { + while self.records_cache.len() >= self.cache_size { + self.remove_oldest_entry() + } + } + + fn remove_oldest_entry(&mut self) { + let mut oldest_timestamp = SystemTime::now(); + + for (_record, timestamp) in self.records_cache.values() { + if *timestamp < oldest_timestamp { + oldest_timestamp = *timestamp; + } + } + + self.records_cache + .retain(|_key, (_record, timestamp)| *timestamp != oldest_timestamp); + } +} + /// A `RecordStore` that stores records on disk. pub struct NodeRecordStore { /// The address of the peer owning the store @@ -79,10 +126,7 @@ pub struct NodeRecordStore { /// Additional index organizing records by distance bucket records_by_bucket: HashMap>, /// FIFO simple cache of records to reduce read times - records_cache: VecDeque, - /// A map from record keys to their indices in the cache - /// allowing for more efficient cache management - records_cache_map: HashMap, + records_cache: RecordCache, /// Send network events to the node layer. network_event_sender: mpsc::Sender, /// Send cmds to the network layer. Used to interact with self in an async fashion. @@ -288,8 +332,7 @@ impl NodeRecordStore { config, records, records_by_bucket: HashMap::new(), - records_cache: VecDeque::with_capacity(cache_size), - records_cache_map: HashMap::with_capacity(cache_size), + records_cache: RecordCache::new(cache_size), network_event_sender, local_swarm_cmd_sender: swarm_cmd_sender, responsible_distance_range: None, @@ -578,35 +621,22 @@ impl NodeRecordStore { let record_key = PrettyPrintRecordKey::from(&r.key).into_owned(); debug!("PUTting a verified Record: {record_key:?}"); - // if the cache already has this record in it (eg, a conflicting spend) - // remove it from the cache - // self.records_cache.retain(|record| record.key != r.key); - // Remove from cache if it already exists - if let Some(&index) = self.records_cache_map.get(key) { - if let Some(existing_record) = self.records_cache.remove(index) { - if existing_record.value == r.value { - // we actually just want to keep what we have, and can assume it's been stored properly. - - // so we put it back in the cache - self.records_cache.insert(index, existing_record); - // and exit early. - return Ok(()); - } - } - self.update_cache_indices(index); - } + // if cache already has the record : + // * if with same content, do nothing and return early + // * if with different content, remove the existing one + if let Some((existing_record, _timestamp)) = self.records_cache.remove(key) { + if existing_record.value == r.value { + // we actually just want to keep what we have, and can assume it's been stored properly. - // Store in the FIFO records cache, removing the oldest if needed - if self.records_cache.len() >= self.config.records_cache_size { - if let Some(old_record) = self.records_cache.pop_front() { - self.records_cache_map.remove(&old_record.key); + // so we put it back in the cache + self.records_cache.push_back(key.clone(), existing_record); + // and exit early. + return Ok(()); } } - // Push the new record to the back of the cache - self.records_cache.push_back(r.clone()); - self.records_cache_map - .insert(key.clone(), self.records_cache.len() - 1); + // Store the new record to the cache + self.records_cache.push_back(key.clone(), r.clone()); self.prune_records_if_needed(key)?; @@ -647,15 +677,6 @@ impl NodeRecordStore { Ok(()) } - /// Update the cache indices after removing an element - fn update_cache_indices(&mut self, start_index: usize) { - for index in start_index..self.records_cache.len() { - if let Some(record) = self.records_cache.get(index) { - self.records_cache_map.insert(record.key.clone(), index); - } - } - } - /// Calculate the cost to store data for our current store state pub(crate) fn store_cost(&self, key: &Key) -> (AttoTokens, QuotingMetrics) { let records_stored = self.records.len(); @@ -735,9 +756,9 @@ impl RecordStore for NodeRecordStore { // ignored if we don't have the record locally. let key = PrettyPrintRecordKey::from(k); - let cached_record = self.records_cache.iter().find(|r| r.key == *k); + let cached_record = self.records_cache.get(k); // first return from FIFO cache if existing there - if let Some(record) = cached_record { + if let Some((record, _timestamp)) = cached_record { return Some(Cow::Borrowed(record)); } @@ -831,7 +852,7 @@ impl RecordStore for NodeRecordStore { } } - self.records_cache.retain(|r| r.key != *k); + self.records_cache.remove(k); #[cfg(feature = "open-metrics")] if let Some(metric) = &self.record_count_metric { From a8d1f36d2894dec9d283294a3e8f8007fc8c939b Mon Sep 17 00:00:00 2001 From: Warm Beer Date: Fri, 1 Nov 2024 14:30:04 +0100 Subject: [PATCH 05/24] feat: check wallet balance before paying quotes --- evmlib/src/wallet.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/evmlib/src/wallet.rs b/evmlib/src/wallet.rs index 22350b1ff4..3cd0a0e4de 100644 --- a/evmlib/src/wallet.rs +++ b/evmlib/src/wallet.rs @@ -6,7 +6,7 @@ // 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 crate::common::{Address, QuoteHash, QuotePayment, TxHash, U256}; +use crate::common::{Address, Amount, QuoteHash, QuotePayment, TxHash, U256}; use crate::contract::data_payments::{DataPaymentsHandler, MAX_TRANSFERS_PER_TRANSACTION}; use crate::contract::network_token::NetworkToken; use crate::contract::{data_payments, network_token}; @@ -27,6 +27,8 @@ use std::sync::Arc; #[derive(thiserror::Error, Debug)] pub enum Error { + #[error("Insufficient tokens to pay for quotes. Have: {0} atto, need: {1} atto")] + InsufficientTokensForQuotes(Amount, Amount), #[error("Private key is invalid")] PrivateKeyInvalid, #[error(transparent)] @@ -291,21 +293,32 @@ pub async fn pay_for_quotes>( let payments: Vec<_> = payments.into_iter().collect(); info!("Paying for quotes of len: {}", payments.len()); - let total_amount = payments.iter().map(|(_, _, amount)| amount).sum(); + let total_amount_to_be_paid = payments.iter().map(|(_, _, amount)| amount).sum(); - let mut tx_hashes_by_quote = BTreeMap::new(); + // Get current wallet token balance + let wallet_balance = balance_of_tokens(wallet_address(&wallet), network) + .await + .map_err(|err| PayForQuotesError(Error::from(err), Default::default()))?; + + // Check if wallet contains enough payment tokens to pay for all quotes + if wallet_balance < total_amount_to_be_paid { + return Err(PayForQuotesError( + Error::InsufficientTokensForQuotes(wallet_balance, total_amount_to_be_paid), + Default::default(), + )); + } - // Check allowance + // Get current allowance let allowance = token_allowance( network, wallet_address(&wallet), *network.data_payments_address(), ) .await - .map_err(|err| PayForQuotesError(Error::from(err), tx_hashes_by_quote.clone()))?; + .map_err(|err| PayForQuotesError(Error::from(err), Default::default()))?; // TODO: Get rid of approvals altogether, by using permits or whatever.. - if allowance < total_amount { + if allowance < total_amount_to_be_paid { // Approve the contract to spend all the client's tokens. approve_to_spend_tokens( wallet.clone(), @@ -314,7 +327,7 @@ pub async fn pay_for_quotes>( U256::MAX, ) .await - .map_err(|err| PayForQuotesError(Error::from(err), tx_hashes_by_quote.clone()))?; + .map_err(|err| PayForQuotesError(Error::from(err), Default::default()))?; } let provider = http_provider_with_wallet(network.rpc_url().clone(), wallet); @@ -323,6 +336,8 @@ pub async fn pay_for_quotes>( // Divide transfers over multiple transactions if they exceed the max per transaction. let chunks = payments.chunks(MAX_TRANSFERS_PER_TRANSACTION); + let mut tx_hashes_by_quote = BTreeMap::new(); + for batch in chunks { let batch: Vec = batch.to_vec(); debug!( From ca5d90720546961e67d45f3141429a1f08ab1d3a Mon Sep 17 00:00:00 2001 From: qima Date: Fri, 1 Nov 2024 21:39:35 +0800 Subject: [PATCH 06/24] feat(node): remove outdated un-decryptable record copies --- sn_networking/src/record_store.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index 254ec6380a..977f80d2bf 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -183,7 +183,22 @@ impl NodeRecordStore { let record = match fs::read(path) { Ok(bytes) => { // and the stored record - Self::get_record_from_bytes(bytes, &key, encryption_details)? + if let Some(record) = + Self::get_record_from_bytes(bytes, &key, encryption_details) + { + record + } else { + // This will be due to node restart, result in different encrypt_detail. + // Hence need to clean up the old copy. + info!("Failed to decrypt record from file {filename:?}, clean it up."); + if let Err(e) = fs::remove_file(path) { + warn!( + "Failed to remove outdated record file {filename:?} from storage dir: {:?}", + e + ); + } + return None; + } } Err(err) => { error!("Error while reading file. filename: {filename}, error: {err:?}"); @@ -198,7 +213,18 @@ impl NodeRecordStore { RecordType::NonChunk(xorname_hash) } Err(error) => { - warn!("Failed to parse record type from record: {:?}", error); + warn!( + "Failed to parse record type of record {filename:?}: {:?}", + error + ); + // In correct decryption using different key could result in this. + // In that case, a cleanup shall be carried out. + if let Err(e) = fs::remove_file(path) { + warn!( + "Failed to remove invalid record file {filename:?} from storage dir: {:?}", + e + ); + } return None; } }; From b4bb6181726847324597bf076f2d67c880daae3d Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Wed, 30 Oct 2024 20:27:46 +0530 Subject: [PATCH 07/24] fix: restart node only on restart rpc command --- sn_node/src/bin/safenode/main.rs | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/sn_node/src/bin/safenode/main.rs b/sn_node/src/bin/safenode/main.rs index 1b18429e89..29fcd0b501 100644 --- a/sn_node/src/bin/safenode/main.rs +++ b/sn_node/src/bin/safenode/main.rs @@ -326,24 +326,28 @@ fn main() -> Result<()> { // actively shut down the runtime rt.shutdown_timeout(Duration::from_secs(2)); - // we got this far without error, which means (so far) the only thing we should be doing - // is restarting the node - start_new_node_process(restart_options); + // Restart only if we received a restart command. + if let Some((retain_peer_id, root_dir, port)) = restart_options { + start_new_node_process(retain_peer_id, root_dir, port); + println!("A new node process has been started successfully."); + } else { + println!("The node process has been stopped."); + } - // Command was successful, so we shut down the process - println!("A new node process has been started successfully."); Ok(()) } /// Start a node with the given configuration. -/// This function will only return if it receives a Restart NodeCtrl cmd. It optionally contains the node's root dir -/// and it's listening port if we want to retain_peer_id on restart. +/// Returns: +/// - `Ok(Some(_))` if we receive a restart request. +/// - `Ok(None)` if we want to shutdown the node. +/// - `Err(_)` if we want to shutdown the node with an error. async fn run_node( node_builder: NodeBuilder, rpc: Option, log_output_dest: &str, log_reload_handle: ReloadHandle, -) -> Result> { +) -> Result> { let started_instant = std::time::Instant::now(); info!("Starting node ..."); @@ -463,19 +467,15 @@ You can check your reward balance by running: delay, retain_peer_id, }) => { - let res = if retain_peer_id { - let root_dir = running_node.root_dir_path(); - let node_port = running_node.get_node_listening_port().await?; - Some((root_dir, node_port)) - } else { - None - }; + let root_dir = running_node.root_dir_path(); + let node_port = running_node.get_node_listening_port().await?; + let msg = format!("Node is restarting in {delay:?}..."); info!("{msg}"); println!("{msg} Node path: {log_output_dest}"); sleep(delay).await; - break Ok(res); + return Ok(Some((retain_peer_id, root_dir, node_port))); } Some(NodeCtrl::Stop { delay, result }) => { let msg = format!("Node is stopping in {delay:?}..."); @@ -689,7 +689,7 @@ fn get_root_dir_and_keypair(root_dir: &Option) -> Result<(PathBuf, Keyp /// Starts a new process running the binary with the same args as /// the current process /// Optionally provide the node's root dir and listen port to retain it's PeerId -fn start_new_node_process(retain_peer_id: Option<(PathBuf, u16)>) { +fn start_new_node_process(retain_peer_id: bool, root_dir: PathBuf, port: u16) { // Retrieve the current executable's path let current_exe = env::current_exe().expect("could not get current executable path"); @@ -722,7 +722,7 @@ fn start_new_node_process(retain_peer_id: Option<(PathBuf, u16)>) { // Set the arguments for the new Command cmd.args(&args[1..]); // Exclude the first argument (binary path) - if let Some((root_dir, port)) = retain_peer_id { + if retain_peer_id { cmd.arg("--root-dir"); cmd.arg(format!("{root_dir:?}")); cmd.arg("--port"); From 99d67c905bcb0e1cde424eef537cce3c1e9266be Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Sat, 2 Nov 2024 14:43:34 +0000 Subject: [PATCH 08/24] chore(release): release candidate 2024.10.4.3 ================== Crate Versions ================== autonomi: 0.2.3-rc.1 autonomi-cli: 0.1.4-rc.1 evmlib: 0.1.3-rc.1 evm_testnet: 0.1.3-rc.1 sn_build_info: 0.1.18-rc.1 sn_evm: 0.1.3-rc.1 sn_logging: 0.2.39-rc.1 sn_metrics: 0.1.19-rc.1 nat-detection: 0.2.10-rc.1 sn_networking: 0.19.2-rc.1 sn_node: 0.112.3-rc.1 node-launchpad: 0.4.3-rc.1 sn_node_manager: 0.11.2-rc.1 sn_node_rpc_client: 0.6.34-rc.1 sn_peers_acquisition: 0.5.6-rc.1 sn_protocol: 0.17.14-rc.1 sn_registers: 0.4.2-rc.1 sn_service_management: 0.4.2-rc.1 sn_transfers: 0.20.2-rc.1 test_utils: 0.4.10-rc.1 token_supplies: 0.1.57-rc.1 =================== Binary Versions =================== nat-detection: 0.2.10-rc.1 node-launchpad: 0.4.3-rc.1 autonomi: 0.1.4-rc.1 safenode: 0.112.3-rc.1 safenode-manager: 0.11.2-rc.1 safenode_rpc_client: 0.6.34-rc.1 safenodemand: 0.11.2-rc.1 --- Cargo.lock | 42 +++++++++++++++---------------- autonomi-cli/Cargo.toml | 12 ++++----- autonomi/Cargo.toml | 18 ++++++------- evm_testnet/Cargo.toml | 6 ++--- evmlib/Cargo.toml | 2 +- nat-detection/Cargo.toml | 8 +++--- node-launchpad/Cargo.toml | 14 +++++------ release-cycle-info | 2 +- sn_build_info/Cargo.toml | 2 +- sn_build_info/src/release_info.rs | 2 +- sn_evm/Cargo.toml | 4 +-- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 12 ++++----- sn_node/Cargo.toml | 28 ++++++++++----------- sn_node_manager/Cargo.toml | 16 ++++++------ sn_node_rpc_client/Cargo.toml | 16 ++++++------ sn_peers_acquisition/Cargo.toml | 4 +-- sn_protocol/Cargo.toml | 10 ++++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++--- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 6 ++--- token_supplies/Cargo.toml | 2 +- 24 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dfcaa5e8c7..4e0032e1b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,7 +1076,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autonomi" -version = "0.2.2" +version = "0.2.3-rc.1" dependencies = [ "alloy", "bip39", @@ -1123,7 +1123,7 @@ dependencies = [ [[package]] name = "autonomi-cli" -version = "0.1.3" +version = "0.1.4-rc.1" dependencies = [ "autonomi", "clap", @@ -2809,7 +2809,7 @@ dependencies = [ [[package]] name = "evm_testnet" -version = "0.1.2" +version = "0.1.3-rc.1" dependencies = [ "clap", "dirs-next", @@ -2820,7 +2820,7 @@ dependencies = [ [[package]] name = "evmlib" -version = "0.1.2" +version = "0.1.3-rc.1" dependencies = [ "alloy", "dirs-next", @@ -5630,7 +5630,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.9" +version = "0.2.10-rc.1" dependencies = [ "clap", "clap-verbosity-flag", @@ -5747,7 +5747,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.4.2" +version = "0.4.3-rc.1" dependencies = [ "atty", "better-panic", @@ -8147,7 +8147,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.11.1" +version = "0.11.2-rc.1" dependencies = [ "assert_cmd", "assert_fs", @@ -8223,7 +8223,7 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.17" +version = "0.1.18-rc.1" dependencies = [ "chrono", "tracing", @@ -8265,7 +8265,7 @@ dependencies = [ [[package]] name = "sn_evm" -version = "0.1.2" +version = "0.1.3-rc.1" dependencies = [ "custom_debug", "evmlib", @@ -8288,7 +8288,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.38" +version = "0.2.39-rc.1" dependencies = [ "chrono", "color-eyre", @@ -8313,7 +8313,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.18" +version = "0.1.19-rc.1" dependencies = [ "clap", "color-eyre", @@ -8327,7 +8327,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.19.1" +version = "0.19.2-rc.1" dependencies = [ "aes-gcm-siv", "async-trait", @@ -8372,7 +8372,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.112.2" +version = "0.112.3-rc.1" dependencies = [ "assert_fs", "async-trait", @@ -8429,7 +8429,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.33" +version = "0.6.34-rc.1" dependencies = [ "assert_fs", "async-trait", @@ -8456,7 +8456,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.5" +version = "0.5.6-rc.1" dependencies = [ "clap", "lazy_static", @@ -8472,7 +8472,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.13" +version = "0.17.14-rc.1" dependencies = [ "blsttc", "bytes", @@ -8502,7 +8502,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.4.1" +version = "0.4.2-rc.1" dependencies = [ "blsttc", "crdts", @@ -8519,7 +8519,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.4.1" +version = "0.4.2-rc.1" dependencies = [ "async-trait", "dirs-next", @@ -8545,7 +8545,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.20.1" +version = "0.20.2-rc.1" dependencies = [ "assert_fs", "blsttc", @@ -8889,7 +8889,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.9" +version = "0.4.10-rc.1" dependencies = [ "bytes", "color-eyre", @@ -9033,7 +9033,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.56" +version = "0.1.57-rc.1" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/autonomi-cli/Cargo.toml b/autonomi-cli/Cargo.toml index fb49e41f33..94e5592062 100644 --- a/autonomi-cli/Cargo.toml +++ b/autonomi-cli/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] name = "autonomi-cli" description = "Autonomi CLI" license = "GPL-3.0" -version = "0.1.3" +version = "0.1.4-rc.1" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -24,7 +24,7 @@ name = "files" harness = false [dependencies] -autonomi = { path = "../autonomi", version = "0.2.2", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = [ "data", "fs", "vault", @@ -50,9 +50,9 @@ tokio = { version = "1.32.0", features = [ "fs", ] } tracing = { version = "~0.1.26" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_logging = { path = "../sn_logging", version = "0.2.38" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } walkdir = "2.5.0" serde_json = "1.0.132" serde = "1.0.210" @@ -60,7 +60,7 @@ hex = "0.4.3" ring = "0.17.8" [dev-dependencies] -autonomi = { path = "../autonomi", version = "0.2.2", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = [ "data", "fs", ] } diff --git a/autonomi/Cargo.toml b/autonomi/Cargo.toml index 6f5491a4f3..6311ce31b6 100644 --- a/autonomi/Cargo.toml +++ b/autonomi/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] description = "Autonomi client API" name = "autonomi" license = "GPL-3.0" -version = "0.2.2" +version = "0.2.3-rc.1" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -38,11 +38,11 @@ rand = "0.8.5" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.19.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } -sn_protocol = { version = "0.17.13", path = "../sn_protocol" } -sn_registers = { path = "../sn_registers", version = "0.4.1" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_protocol = { version = "0.17.14-rc.1", path = "../sn_protocol" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } thiserror = "1.0.23" tokio = { version = "1.35.0", features = ["sync"] } tracing = { version = "~0.1.26" } @@ -60,8 +60,8 @@ blstrs = "0.7.1" alloy = { version = "0.5.3", default-features = false, features = ["std", "reqwest-rustls-tls", "provider-anvil-node", "sol-types", "json", "signers", "contract", "signer-local", "network"] } eyre = "0.6.5" sha2 = "0.10.6" -sn_logging = { path = "../sn_logging", version = "0.2.38" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } # Do not specify the version field. Release process expects even the local dev deps to be published. # Removing the version field is a workaround. test_utils = { path = "../test_utils" } @@ -71,7 +71,7 @@ wasm-bindgen-test = "0.3.43" [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.7" -evmlib = { path = "../evmlib", version = "0.1.2", features = ["wasm-bindgen"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.1", features = ["wasm-bindgen"] } # See https://github.com/sebcrozet/instant/blob/7bd13f51f5c930239fddc0476a837870fb239ed7/README.md#using-instant-for-a-wasm-platform-where-performancenow-is-not-available instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] } js-sys = "0.3.70" diff --git a/evm_testnet/Cargo.toml b/evm_testnet/Cargo.toml index 5182f2eca7..aeda4d085e 100644 --- a/evm_testnet/Cargo.toml +++ b/evm_testnet/Cargo.toml @@ -6,13 +6,13 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evm_testnet" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.2" +version = "0.1.3-rc.1" [dependencies] clap = { version = "4.5", features = ["derive"] } dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.2" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } tokio = { version = "1.40", features = ["rt-multi-thread", "signal"] } [lints] diff --git a/evmlib/Cargo.toml b/evmlib/Cargo.toml index 23c6a35e45..3561e67dfd 100644 --- a/evmlib/Cargo.toml +++ b/evmlib/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evmlib" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.2" +version = "0.1.3-rc.1" [features] wasm-bindgen = ["alloy/wasm-bindgen"] diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 5da84e4066..e367d6bb07 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.9" +version = "0.2.10-rc.1" [[bin]] name = "nat-detection" @@ -31,9 +31,9 @@ libp2p = { version = "0.54.1", features = [ "macros", "upnp", ] } -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_networking = { path = "../sn_networking", version = "0.19.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index b9ee73af76..611eef9433 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.4.2" +version = "0.4.3-rc.1" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -51,13 +51,13 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } -sn-node-manager = { version = "0.11.1", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.5", path = "../sn_peers_acquisition" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn-node-manager = { version = "0.11.2-rc.1", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.6-rc.1", path = "../sn_peers_acquisition" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.4.1", path = "../sn_service_management" } +sn_service_management = { version = "0.4.2-rc.1", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index 9b8978040f..112a1fee5d 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -15,4 +15,4 @@ release-year: 2024 release-month: 10 release-cycle: 4 -release-cycle-counter: 2 +release-cycle-counter: 3 diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index d20a5f947b..02bea308ad 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.17" +version = "0.1.18-rc.1" build = "build.rs" include = ["Cargo.toml", "src/**/*", "build.rs"] diff --git a/sn_build_info/src/release_info.rs b/sn_build_info/src/release_info.rs index e9c752684e..24d314f99c 100644 --- a/sn_build_info/src/release_info.rs +++ b/sn_build_info/src/release_info.rs @@ -1,4 +1,4 @@ pub const RELEASE_YEAR: &str = "2024"; pub const RELEASE_MONTH: &str = "10"; pub const RELEASE_CYCLE: &str = "4"; -pub const RELEASE_CYCLE_COUNTER: &str = "2"; +pub const RELEASE_CYCLE_COUNTER: &str = "3"; diff --git a/sn_evm/Cargo.toml b/sn_evm/Cargo.toml index 37c9d84cb8..cd6a0145b3 100644 --- a/sn_evm/Cargo.toml +++ b/sn_evm/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_evm" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.2" +version = "0.1.3-rc.1" [features] test-utils = [] @@ -17,7 +17,7 @@ external-signer = ["evmlib/external-signer"] [dependencies] custom_debug = "~0.6.1" -evmlib = { path = "../evmlib", version = "0.1.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } hex = "~0.4.3" lazy_static = "~1.4.0" libp2p = { version = "0.53", features = ["identify", "kad"] } diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 8b6d7d8802..74ccbcf6d6 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.38" +version = "0.2.39-rc.1" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index 103d1d628e..07d814a1aa 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.18" +version = "0.1.19-rc.1" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index 1a6bdc5b67..bf3b5961a6 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.1" +version = "0.19.2-rc.1" [features] default = [] @@ -54,11 +54,11 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13" } -sn_transfers = { path = "../sn_transfers", version = "0.20.1" } -sn_registers = { path = "../sn_registers", version = "0.4.1" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index 5903b68729..0b0c848f2d 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.112.2" +version = "0.112.3-rc.1" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -52,15 +52,15 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } -sn_logging = { path = "../sn_logging", version = "0.2.38" } -sn_networking = { path = "../sn_networking", version = "0.19.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13" } -sn_registers = { path = "../sn_registers", version = "0.4.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.1" } -sn_service_management = { path = "../sn_service_management", version = "0.4.1" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } sysinfo = { version = "0.30.8", default-features = false } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ @@ -83,16 +83,16 @@ strum = { version = "0.26.2", features = ["derive"] } color-eyre = "0.6.2" [dev-dependencies] -evmlib = { path = "../evmlib", version = "0.1.2" } -autonomi = { path = "../autonomi", version = "0.2.2", features = ["registers"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } +autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = ["registers"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_protocol = { path = "../sn_protocol", version = "0.17.13", features = [ +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.20.1", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index b3e651927e..3adc4f589a 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.11.1" +version = "0.11.2-rc.1" [[bin]] name = "safenode-manager" @@ -46,14 +46,14 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_logging = { path = "../sn_logging", version = "0.2.38" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13" } -sn_service_management = { path = "../sn_service_management", version = "0.4.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } sn-releases = "0.2.6" -sn_evm = { path = "../sn_evm", version = "0.1.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index cdeb4a2dc1..2e221af39a 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.33" +version = "0.6.34-rc.1" [[bin]] name = "safenode_rpc_client" @@ -26,13 +26,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version = "0.54.1", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_logging = { path = "../sn_logging", version = "0.2.38" } -sn_node = { path = "../sn_node", version = "0.112.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.4.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_node = { path = "../sn_node", version = "0.112.3-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 2d40d10161..b587f8d680 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.5" +version = "0.5.6-rc.1" [features] local = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version = "0.54.1", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.13", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false } tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index 832a832206..454a85a5ec 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.13" +version = "0.17.14-rc.1" [features] default = [] @@ -28,10 +28,10 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.17" } -sn_transfers = { path = "../sn_transfers", version = "0.20.1" } -sn_registers = { path = "../sn_registers", version = "0.4.1" } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index 596ce700ed..c5ad0d1a6d 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.1" +version = "0.4.2-rc.1" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index 5cdfd7cd8f..d1840ce652 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.1" +version = "0.4.2-rc.1" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.38" } -sn_protocol = { path = "../sn_protocol", version = "0.17.13", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features = [ "rpc", ] } -sn_evm = { path = "../sn_evm", version = "0.1.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index f156f93de9..d8093df405 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.20.1" +version = "0.20.2-rc.1" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 5acb11e414..f87ff7aa2b 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.9" +version = "0.4.10-rc.1" [features] local = ["sn_peers_acquisition/local"] @@ -16,9 +16,9 @@ local = ["sn_peers_acquisition/local"] bytes = { version = "1.0.1", features = ["serde"] } color-eyre = "~0.6.2" dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } libp2p = { version = "0.54.1", features = ["identify", "kad"] } rand = "0.8.5" serde = { version = "1.0.133", features = ["derive"] } serde_json = "1.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.5" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index cf18a18ec8..aff1c1f7ad 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.56" +version = "0.1.57-rc.1" [dependencies] From 1d1328ea3279ac0aa5fdda8a8ddff6ebf37d4464 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Sat, 2 Nov 2024 16:24:35 +0000 Subject: [PATCH 09/24] chore: enable debug symbols for release build This could help us analyse problems in the production environment. It can be switched off in the future. --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 779485a2c8..40750e1775 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,8 +43,7 @@ unwrap_used = "warn" clone_on_ref_ptr = "warn" [profile.release] -debug = 0 -strip = "debuginfo" +debug = true [profile.dev] debug = 0 From 5d332c583c417f0b0c578d51fd9cae0c7211bec0 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Sat, 2 Nov 2024 20:45:02 +0000 Subject: [PATCH 10/24] fix: retain rewards address arg on upgrade This is one of the new EVM arguments that were missing from being retained on an upgrade. --- sn_node_manager/src/lib.rs | 204 ++++++++++++++++++++++++++++++ sn_service_management/src/node.rs | 5 + 2 files changed, 209 insertions(+) diff --git a/sn_node_manager/src/lib.rs b/sn_node_manager/src/lib.rs index a71e7b6b4e..b73ed48612 100644 --- a/sn_node_manager/src/lib.rs +++ b/sn_node_manager/src/lib.rs @@ -2709,6 +2709,8 @@ mod tests { OsString::from("--log-output-dest"), OsString::from("/var/log/safenode/safenode1"), OsString::from("--upnp"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -2870,6 +2872,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--log-format"), OsString::from("json"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3034,6 +3038,8 @@ mod tests { OsString::from("--log-output-dest"), OsString::from("/var/log/safenode/safenode1"), OsString::from("--home-network"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3195,6 +3201,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--ip"), OsString::from("192.168.1.1"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3359,6 +3367,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--port"), OsString::from("12000"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3520,6 +3530,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--max-archived-log-files"), OsString::from("20"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3684,6 +3696,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--max-log-files"), OsString::from("20"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -3845,6 +3859,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--metrics-server-port"), OsString::from("12000"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -4009,6 +4025,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--metrics-server-port"), OsString::from("12000"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -4173,6 +4191,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--owner"), OsString::from("discord_username"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, @@ -4337,6 +4357,8 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--owner"), OsString::from("discord_username"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: true, @@ -4498,6 +4520,186 @@ mod tests { OsString::from("/var/log/safenode/safenode1"), OsString::from("--owner"), OsString::from("discord_username"), + 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: true, + contents: None, + environment: None, + label: "safenode1".parse()?, + program: current_node_bin.to_path_buf(), + username: Some("safe".to_string()), + working_directory: None, + }), + eq(false), + ) + .times(1) + .returning(|_, _| Ok(())); + + // after service restart + mock_service_control + .expect_start() + .with(eq("safenode1"), 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/safenode-manager/services/safenode1"), + log_path: PathBuf::from("/var/log/safenode/safenode1"), + 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: true, + connected_peers: None, + data_dir_path: PathBuf::from("/var/safenode-manager/services/safenode1"), + 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, + listen_addr: None, + local: false, + log_dir_path: PathBuf::from("/var/log/safenode/safenode1"), + log_format: None, + max_archived_log_files: None, + max_log_files: None, + metrics_port: None, + node_ip: None, + node_port: None, + number: 1, + owner: Some("discord_username".to_string()), + peer_id: Some(PeerId::from_str( + "12D3KooWS2tpXGGTmg2AHFiDh57yPQnat49YHnyqoggzXZWpqkCR", + )?), + 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), + safenode_path: current_node_bin.to_path_buf(), + service_name: "safenode1".to_string(), + status: ServiceStatus::Running, + upnp: false, + user: Some("safe".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: true, + bootstrap_peers: Vec::new(), + 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.auto_restart,); + + Ok(()) + } + + #[tokio::test] + async fn upgrade_should_retain_the_rewards_address() -> 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("safenode_install"); + current_install_dir.create_dir_all()?; + + let current_node_bin = current_install_dir.child("safenode"); + current_node_bin.write_binary(b"fake safenode binary")?; + let target_node_bin = tmp_data_dir.child("safenode"); + target_node_bin.write_binary(b"fake safenode 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("safenode1"), eq(false)) + .times(1) + .returning(|_, _| Ok(())); + + // after binary upgrade + mock_service_control + .expect_uninstall() + .with(eq("safenode1"), 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/safenode-manager/services/safenode1"), + OsString::from("--log-output-dest"), + OsString::from("/var/log/safenode/safenode1"), + OsString::from("--owner"), + OsString::from("discord_username"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-custom"), OsString::from("--rpc-url"), OsString::from("http://localhost:8545/"), @@ -4673,6 +4875,8 @@ mod tests { OsString::from("--log-output-dest"), OsString::from("/var/log/safenode/safenode1"), OsString::from("--upnp"), + OsString::from("--rewards-address"), + OsString::from("0x03B770D9cD32077cC0bF330c13C114a87643B124"), OsString::from("evm-arbitrum-one"), ], autostart: false, diff --git a/sn_service_management/src/node.rs b/sn_service_management/src/node.rs index c9d853a009..d896aeb48d 100644 --- a/sn_service_management/src/node.rs +++ b/sn_service_management/src/node.rs @@ -126,6 +126,11 @@ impl<'a> ServiceStateActions for NodeService<'a> { args.push(OsString::from(peers_str)); } + args.push(OsString::from("--rewards-address")); + args.push(OsString::from( + self.service_data.rewards_address.to_string(), + )); + args.push(OsString::from(self.service_data.evm_network.to_string())); if let EvmNetwork::Custom(custom_network) = &self.service_data.evm_network { args.push(OsString::from("--rpc-url")); From 15bf53f8b08445849eeca873c5664f17b61a3d47 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Sat, 2 Nov 2024 23:27:01 +0000 Subject: [PATCH 11/24] chore(release): release candidate 2024.10.4.4 ================== Crate Versions ================== autonomi: 0.2.3-rc.2 autonomi-cli: 0.1.4-rc.2 evmlib: 0.1.3-rc.2 evm_testnet: 0.1.3-rc.2 sn_build_info: 0.1.18-rc.2 sn_evm: 0.1.3-rc.2 sn_logging: 0.2.39-rc.2 sn_metrics: 0.1.19-rc.2 nat-detection: 0.2.10-rc.2 sn_networking: 0.19.2-rc.2 sn_node: 0.112.3-rc.2 node-launchpad: 0.4.3-rc.2 sn_node_manager: 0.11.2-rc.2 sn_node_rpc_client: 0.6.34-rc.2 sn_peers_acquisition: 0.5.6-rc.2 sn_protocol: 0.17.14-rc.2 sn_registers: 0.4.2-rc.2 sn_service_management: 0.4.2-rc.2 sn_transfers: 0.20.2-rc.2 test_utils: 0.4.10-rc.2 token_supplies: 0.1.57-rc.2 =================== Binary Versions =================== nat-detection: 0.2.10-rc.2 node-launchpad: 0.4.3-rc.2 autonomi: 0.1.4-rc.2 safenode: 0.112.3-rc.2 safenode-manager: 0.11.2-rc.2 safenode_rpc_client: 0.6.34-rc.2 safenodemand: 0.11.2-rc.2 --- Cargo.lock | 42 +++++++++++++++---------------- autonomi-cli/Cargo.toml | 12 ++++----- autonomi/Cargo.toml | 18 ++++++------- evm_testnet/Cargo.toml | 6 ++--- evmlib/Cargo.toml | 2 +- nat-detection/Cargo.toml | 8 +++--- node-launchpad/Cargo.toml | 14 +++++------ release-cycle-info | 2 +- sn_build_info/Cargo.toml | 2 +- sn_build_info/src/release_info.rs | 2 +- sn_evm/Cargo.toml | 4 +-- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 12 ++++----- sn_node/Cargo.toml | 28 ++++++++++----------- sn_node_manager/Cargo.toml | 16 ++++++------ sn_node_rpc_client/Cargo.toml | 16 ++++++------ sn_peers_acquisition/Cargo.toml | 4 +-- sn_protocol/Cargo.toml | 10 ++++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++--- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 6 ++--- token_supplies/Cargo.toml | 2 +- 24 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e0032e1b0..3417d842b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,7 +1076,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autonomi" -version = "0.2.3-rc.1" +version = "0.2.3-rc.2" dependencies = [ "alloy", "bip39", @@ -1123,7 +1123,7 @@ dependencies = [ [[package]] name = "autonomi-cli" -version = "0.1.4-rc.1" +version = "0.1.4-rc.2" dependencies = [ "autonomi", "clap", @@ -2809,7 +2809,7 @@ dependencies = [ [[package]] name = "evm_testnet" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" dependencies = [ "clap", "dirs-next", @@ -2820,7 +2820,7 @@ dependencies = [ [[package]] name = "evmlib" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" dependencies = [ "alloy", "dirs-next", @@ -5630,7 +5630,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.10-rc.1" +version = "0.2.10-rc.2" dependencies = [ "clap", "clap-verbosity-flag", @@ -5747,7 +5747,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.4.3-rc.1" +version = "0.4.3-rc.2" dependencies = [ "atty", "better-panic", @@ -8147,7 +8147,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.11.2-rc.1" +version = "0.11.2-rc.2" dependencies = [ "assert_cmd", "assert_fs", @@ -8223,7 +8223,7 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.18-rc.1" +version = "0.1.18-rc.2" dependencies = [ "chrono", "tracing", @@ -8265,7 +8265,7 @@ dependencies = [ [[package]] name = "sn_evm" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" dependencies = [ "custom_debug", "evmlib", @@ -8288,7 +8288,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.39-rc.1" +version = "0.2.39-rc.2" dependencies = [ "chrono", "color-eyre", @@ -8313,7 +8313,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.19-rc.1" +version = "0.1.19-rc.2" dependencies = [ "clap", "color-eyre", @@ -8327,7 +8327,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.19.2-rc.1" +version = "0.19.2-rc.2" dependencies = [ "aes-gcm-siv", "async-trait", @@ -8372,7 +8372,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.112.3-rc.1" +version = "0.112.3-rc.2" dependencies = [ "assert_fs", "async-trait", @@ -8429,7 +8429,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.34-rc.1" +version = "0.6.34-rc.2" dependencies = [ "assert_fs", "async-trait", @@ -8456,7 +8456,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.6-rc.1" +version = "0.5.6-rc.2" dependencies = [ "clap", "lazy_static", @@ -8472,7 +8472,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.14-rc.1" +version = "0.17.14-rc.2" dependencies = [ "blsttc", "bytes", @@ -8502,7 +8502,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.4.2-rc.1" +version = "0.4.2-rc.2" dependencies = [ "blsttc", "crdts", @@ -8519,7 +8519,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.4.2-rc.1" +version = "0.4.2-rc.2" dependencies = [ "async-trait", "dirs-next", @@ -8545,7 +8545,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.20.2-rc.1" +version = "0.20.2-rc.2" dependencies = [ "assert_fs", "blsttc", @@ -8889,7 +8889,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.10-rc.1" +version = "0.4.10-rc.2" dependencies = [ "bytes", "color-eyre", @@ -9033,7 +9033,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.57-rc.1" +version = "0.1.57-rc.2" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/autonomi-cli/Cargo.toml b/autonomi-cli/Cargo.toml index 94e5592062..d9214fa74e 100644 --- a/autonomi-cli/Cargo.toml +++ b/autonomi-cli/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] name = "autonomi-cli" description = "Autonomi CLI" license = "GPL-3.0" -version = "0.1.4-rc.1" +version = "0.1.4-rc.2" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -24,7 +24,7 @@ name = "files" harness = false [dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = [ "data", "fs", "vault", @@ -50,9 +50,9 @@ tokio = { version = "1.32.0", features = [ "fs", ] } tracing = { version = "~0.1.26" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } walkdir = "2.5.0" serde_json = "1.0.132" serde = "1.0.210" @@ -60,7 +60,7 @@ hex = "0.4.3" ring = "0.17.8" [dev-dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = [ "data", "fs", ] } diff --git a/autonomi/Cargo.toml b/autonomi/Cargo.toml index 6311ce31b6..ef1be61970 100644 --- a/autonomi/Cargo.toml +++ b/autonomi/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] description = "Autonomi client API" name = "autonomi" license = "GPL-3.0" -version = "0.2.3-rc.1" +version = "0.2.3-rc.2" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -38,11 +38,11 @@ rand = "0.8.5" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } -sn_protocol = { version = "0.17.14-rc.1", path = "../sn_protocol" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_protocol = { version = "0.17.14-rc.2", path = "../sn_protocol" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } thiserror = "1.0.23" tokio = { version = "1.35.0", features = ["sync"] } tracing = { version = "~0.1.26" } @@ -60,8 +60,8 @@ blstrs = "0.7.1" alloy = { version = "0.5.3", default-features = false, features = ["std", "reqwest-rustls-tls", "provider-anvil-node", "sol-types", "json", "signers", "contract", "signer-local", "network"] } eyre = "0.6.5" sha2 = "0.10.6" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } # Do not specify the version field. Release process expects even the local dev deps to be published. # Removing the version field is a workaround. test_utils = { path = "../test_utils" } @@ -71,7 +71,7 @@ wasm-bindgen-test = "0.3.43" [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.7" -evmlib = { path = "../evmlib", version = "0.1.3-rc.1", features = ["wasm-bindgen"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.2", features = ["wasm-bindgen"] } # See https://github.com/sebcrozet/instant/blob/7bd13f51f5c930239fddc0476a837870fb239ed7/README.md#using-instant-for-a-wasm-platform-where-performancenow-is-not-available instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] } js-sys = "0.3.70" diff --git a/evm_testnet/Cargo.toml b/evm_testnet/Cargo.toml index aeda4d085e..e69aaf3128 100644 --- a/evm_testnet/Cargo.toml +++ b/evm_testnet/Cargo.toml @@ -6,13 +6,13 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evm_testnet" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" [dependencies] clap = { version = "4.5", features = ["derive"] } dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } tokio = { version = "1.40", features = ["rt-multi-thread", "signal"] } [lints] diff --git a/evmlib/Cargo.toml b/evmlib/Cargo.toml index 3561e67dfd..0526db809e 100644 --- a/evmlib/Cargo.toml +++ b/evmlib/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evmlib" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" [features] wasm-bindgen = ["alloy/wasm-bindgen"] diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index e367d6bb07..2c4aa402b8 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.10-rc.1" +version = "0.2.10-rc.2" [[bin]] name = "nat-detection" @@ -31,9 +31,9 @@ libp2p = { version = "0.54.1", features = [ "macros", "upnp", ] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 611eef9433..925bb282bf 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.4.3-rc.1" +version = "0.4.3-rc.2" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -51,13 +51,13 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } -sn-node-manager = { version = "0.11.2-rc.1", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.6-rc.1", path = "../sn_peers_acquisition" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn-node-manager = { version = "0.11.2-rc.2", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.6-rc.2", path = "../sn_peers_acquisition" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.4.2-rc.1", path = "../sn_service_management" } +sn_service_management = { version = "0.4.2-rc.2", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index 112a1fee5d..0db6470d15 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -15,4 +15,4 @@ release-year: 2024 release-month: 10 release-cycle: 4 -release-cycle-counter: 3 +release-cycle-counter: 4 diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 02bea308ad..8819df1452 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.18-rc.1" +version = "0.1.18-rc.2" build = "build.rs" include = ["Cargo.toml", "src/**/*", "build.rs"] diff --git a/sn_build_info/src/release_info.rs b/sn_build_info/src/release_info.rs index 24d314f99c..15237cd119 100644 --- a/sn_build_info/src/release_info.rs +++ b/sn_build_info/src/release_info.rs @@ -1,4 +1,4 @@ pub const RELEASE_YEAR: &str = "2024"; pub const RELEASE_MONTH: &str = "10"; pub const RELEASE_CYCLE: &str = "4"; -pub const RELEASE_CYCLE_COUNTER: &str = "3"; +pub const RELEASE_CYCLE_COUNTER: &str = "4"; diff --git a/sn_evm/Cargo.toml b/sn_evm/Cargo.toml index cd6a0145b3..81d9dd01fa 100644 --- a/sn_evm/Cargo.toml +++ b/sn_evm/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_evm" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.1" +version = "0.1.3-rc.2" [features] test-utils = [] @@ -17,7 +17,7 @@ external-signer = ["evmlib/external-signer"] [dependencies] custom_debug = "~0.6.1" -evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } hex = "~0.4.3" lazy_static = "~1.4.0" libp2p = { version = "0.53", features = ["identify", "kad"] } diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 74ccbcf6d6..1277a6d0bc 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.39-rc.1" +version = "0.2.39-rc.2" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index 07d814a1aa..d0f83aa760 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.19-rc.1" +version = "0.1.19-rc.2" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index bf3b5961a6..2c4fa90806 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.2-rc.1" +version = "0.19.2-rc.2" [features] default = [] @@ -54,11 +54,11 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index 0b0c848f2d..a9db79409c 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.112.3-rc.1" +version = "0.112.3-rc.2" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -52,15 +52,15 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } sysinfo = { version = "0.30.8", default-features = false } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ @@ -83,16 +83,16 @@ strum = { version = "0.26.2", features = ["derive"] } color-eyre = "0.6.2" [dev-dependencies] -evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } -autonomi = { path = "../autonomi", version = "0.2.3-rc.1", features = ["registers"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } +autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = ["registers"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features = [ +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 3adc4f589a..d07b98d781 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.11.2-rc.1" +version = "0.11.2-rc.2" [[bin]] name = "safenode-manager" @@ -46,14 +46,14 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } sn-releases = "0.2.6" -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index 2e221af39a..ceec7270a7 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.34-rc.1" +version = "0.6.34-rc.2" [[bin]] name = "safenode_rpc_client" @@ -26,13 +26,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version = "0.54.1", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } -sn_node = { path = "../sn_node", version = "0.112.3-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_node = { path = "../sn_node", version = "0.112.3-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index b587f8d680..88bdb8d53b 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.6-rc.1" +version = "0.5.6-rc.2" [features] local = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version = "0.54.1", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false } tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index 454a85a5ec..ddf615ae1c 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.14-rc.1" +version = "0.17.14-rc.2" [features] default = [] @@ -28,10 +28,10 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.1" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index c5ad0d1a6d..219dc83686 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.1" +version = "0.4.2-rc.2" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index d1840ce652..79510fa25b 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.1" +version = "0.4.2-rc.2" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.1", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features = [ "rpc", ] } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.1" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index d8093df405..57f6de55c1 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.20.2-rc.1" +version = "0.20.2-rc.2" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index f87ff7aa2b..b309b5a514 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.10-rc.1" +version = "0.4.10-rc.2" [features] local = ["sn_peers_acquisition/local"] @@ -16,9 +16,9 @@ local = ["sn_peers_acquisition/local"] bytes = { version = "1.0.1", features = ["serde"] } color-eyre = "~0.6.2" dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.1" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } libp2p = { version = "0.54.1", features = ["identify", "kad"] } rand = "0.8.5" serde = { version = "1.0.133", features = ["derive"] } serde_json = "1.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index aff1c1f7ad..7a9e940da2 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.57-rc.1" +version = "0.1.57-rc.2" [dependencies] From 91a0c0cc14dc00fdb1b3ac8c0c5c40606b7eb1ab Mon Sep 17 00:00:00 2001 From: qima Date: Mon, 4 Nov 2024 21:11:19 +0800 Subject: [PATCH 12/24] chore(node): trigger pruning earlier --- sn_networking/src/record_store.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index 149b11030a..e45b59b7a5 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -524,13 +524,15 @@ impl NodeRecordStore { Ok(()) } - // When the accumulated record copies exceeds the `expotional pricing point` (max_records * 0.6) + // When the accumulated record copies exceeds the `expotional pricing point` (max_records * 0.1) // those `out of range` records shall be cleaned up. - // This is to avoid `over-quoting` during restart, when RT is not fully populated, - // result in mis-calculation of relevant records. + // This is to avoid : + // * holding too many irrelevant record, which occupies disk space + // * `over-quoting` during restart, when RT is not fully populated, + // result in mis-calculation of relevant records. pub fn cleanup_irrelevant_records(&mut self) { let accumulated_records = self.records.len(); - if accumulated_records < MAX_RECORDS_COUNT * 6 / 10 { + if accumulated_records < MAX_RECORDS_COUNT / 10 { return; } From ea489b353015a1c68cf88b8036845b3c72255b5a Mon Sep 17 00:00:00 2001 From: qima Date: Mon, 4 Nov 2024 23:56:36 +0800 Subject: [PATCH 13/24] feat(node): derive encrypt_details from self keypair --- .github/workflows/merge.yml | 6 +- .github/workflows/nightly.yml | 2 +- Cargo.lock | 3 + sn_networking/Cargo.toml | 3 + sn_networking/src/driver.rs | 9 ++ sn_networking/src/record_store.rs | 137 +++++++++++++++++++++++++++--- 6 files changed, 148 insertions(+), 12 deletions(-) diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 9142383db4..db5563ca3d 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -118,7 +118,11 @@ jobs: timeout-minutes: 25 run: cargo test --release --package sn_node --lib - - name: Run network tests + - name: Run network tests (with encrypt-records) + timeout-minutes: 25 + run: cargo test --release --package sn_networking --features="open-metrics, encrypt-records" + + name: Run network tests (without encrypt-records) timeout-minutes: 25 run: cargo test --release --package sn_networking --features="open-metrics" diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 843507abff..a1e0ef2046 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -250,7 +250,7 @@ jobs: - name: Run network tests timeout-minutes: 25 - run: cargo test --release --package sn_networking --features="open-metrics" + run: cargo test --release --package sn_networking --features="open-metrics, encrypt-records" - name: Run protocol tests timeout-minutes: 25 diff --git a/Cargo.lock b/Cargo.lock index 3417d842b1..dcbc426bd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8330,6 +8330,7 @@ name = "sn_networking" version = "0.19.2-rc.2" dependencies = [ "aes-gcm-siv", + "assert_fs", "async-trait", "backoff", "blsttc", @@ -8339,6 +8340,7 @@ dependencies = [ "futures", "getrandom 0.2.15", "hex 0.4.3", + "hkdf", "hyper 0.14.30", "itertools 0.12.1", "lazy_static", @@ -8351,6 +8353,7 @@ dependencies = [ "rmp-serde", "self_encryption", "serde", + "sha2 0.10.8", "sn_build_info", "sn_evm", "sn_protocol", diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index 2c4fa90806..df71cf51a3 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -73,11 +73,14 @@ tracing = { version = "~0.1.26" } xor_name = "5.0.0" backoff = { version = "0.4.0", features = ["tokio"] } aes-gcm-siv = "0.11.1" +hkdf = "0.12" +sha2 = "0.10" walkdir = "~2.5.0" strum = { version = "0.26.2", features = ["derive"] } void = "1.0.2" [dev-dependencies] +assert_fs = "1.0.0" bls = { package = "blsttc", version = "8.0.1" } # add rand to libp2p libp2p-identity = { version = "0.2.7", features = ["rand"] } diff --git a/sn_networking/src/driver.rs b/sn_networking/src/driver.rs index 1e52687741..2fdc2129ec 100644 --- a/sn_networking/src/driver.rs +++ b/sn_networking/src/driver.rs @@ -60,6 +60,7 @@ use sn_protocol::{ use sn_registers::SignedRegister; use std::{ collections::{btree_map::Entry, BTreeMap, HashMap, HashSet}, + convert::TryInto, fmt::Debug, fs, io::{Read, Write}, @@ -389,10 +390,18 @@ impl NetworkBuilder { source: error, }); } + let peer_id = PeerId::from(self.keypair.public()); + let encryption_seed: [u8; 16] = peer_id + .to_bytes() + .get(..16) + .expect("Cann't get encryption_seed from keypair") + .try_into() + .expect("Cann't get 16 bytes from serialised key_pair"); NodeRecordStoreConfig { max_value_bytes: MAX_PACKET_SIZE, // TODO, does this need to be _less_ than MAX_PACKET_SIZE storage_dir: storage_dir_path, historic_quote_dir: root_dir.clone(), + encryption_seed, ..Default::default() } }; diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index 149b11030a..b7cb493b58 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -13,10 +13,10 @@ use crate::send_local_swarm_cmd; use crate::target_arch::{spawn, Instant}; use crate::{event::NetworkEvent, log_markers::Marker}; use aes_gcm_siv::{ - aead::{Aead, KeyInit, OsRng}, - Aes256GcmSiv, Nonce, + aead::{Aead, KeyInit}, + Aes256GcmSiv, Key as AesKey, Nonce, }; - +use hkdf::Hkdf; use itertools::Itertools; use libp2p::{ identity::PeerId, @@ -27,9 +27,9 @@ use libp2p::{ }; #[cfg(feature = "open-metrics")] use prometheus_client::metrics::gauge::Gauge; -use rand::RngCore; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; +use sha2::Sha256; use sn_evm::{AttoTokens, QuotingMetrics}; use sn_protocol::{ storage::{RecordHeader, RecordKind, RecordType}, @@ -67,6 +67,27 @@ const MAX_STORE_COST: u64 = 1_000_000; // Min store cost for a chunk. const MIN_STORE_COST: u64 = 1; +fn derive_aes256gcm_siv_from_seed(seed: &[u8; 16]) -> (Aes256GcmSiv, [u8; 4]) { + // shall be unique for purpose. + let salt = b"autonomi_record_store"; + + let hk = Hkdf::::new(Some(salt), seed); + + let mut okm = [0u8; 32]; + hk.expand(b"", &mut okm) + .expect("32 bytes is a valid length for HKDF output"); + + let seeded_key = AesKey::::from_slice(&okm); + + let mut nonce_starter = [0u8; 4]; + let bytes_to_copy = seed.len().min(nonce_starter.len()); + nonce_starter[..bytes_to_copy].copy_from_slice(&seed[..bytes_to_copy]); + + trace!("seeded_key is {seeded_key:?} nonce_starter is {nonce_starter:?}"); + + (Aes256GcmSiv::new(seeded_key), nonce_starter) +} + /// FIFO simple cache of records to reduce read times struct RecordCache { records_cache: HashMap, @@ -163,6 +184,8 @@ pub struct NodeRecordStoreConfig { pub max_value_bytes: usize, /// The maximum number of records to cache in memory. pub records_cache_size: usize, + /// The seed to generate record_store encryption_details + pub encryption_seed: [u8; 16], } impl Default for NodeRecordStoreConfig { @@ -174,6 +197,7 @@ impl Default for NodeRecordStoreConfig { max_records: MAX_RECORDS_COUNT, max_value_bytes: MAX_PACKET_SIZE, records_cache_size: MAX_RECORDS_CACHE_SIZE, + encryption_seed: [0u8; 16], } } } @@ -330,12 +354,8 @@ impl NodeRecordStore { network_event_sender: mpsc::Sender, swarm_cmd_sender: mpsc::Sender, ) -> Self { - let key = Aes256GcmSiv::generate_key(&mut OsRng); - let cipher = Aes256GcmSiv::new(&key); - let mut nonce_starter = [0u8; 4]; - OsRng.fill_bytes(&mut nonce_starter); - - let encryption_details = (cipher, nonce_starter); + info!("Using encryption_seed of {:?}", config.encryption_seed); + let encryption_details = derive_aes256gcm_siv_from_seed(&config.encryption_seed); // Recover the quoting_metrics first, as the historical file will be cleaned by // the later on update_records_from_an_existing_store function @@ -1021,6 +1041,7 @@ mod tests { use bls::SecretKey; use xor_name::XorName; + use assert_fs::TempDir; use bytes::Bytes; use eyre::{bail, ContextCompat}; use libp2p::kad::K_VALUE; @@ -1221,6 +1242,102 @@ mod tests { assert!(store.get(&r.key).is_none()); } + #[tokio::test] + async fn can_store_after_restart() -> eyre::Result<()> { + let temp_dir = TempDir::new().expect("Should be able to create a temp dir."); + let store_config = NodeRecordStoreConfig { + storage_dir: temp_dir.to_path_buf(), + encryption_seed: [1u8; 16], + ..Default::default() + }; + let self_id = PeerId::random(); + let (network_event_sender, _) = mpsc::channel(1); + let (swarm_cmd_sender, _) = mpsc::channel(1); + + let mut store = NodeRecordStore::with_config( + self_id, + store_config.clone(), + network_event_sender.clone(), + swarm_cmd_sender.clone(), + ); + + // Create a chunk + let chunk_data = Bytes::from_static(b"Test chunk data"); + let chunk = Chunk::new(chunk_data); + let chunk_address = *chunk.address(); + + // Create a record from the chunk + let record = Record { + key: NetworkAddress::ChunkAddress(chunk_address).to_record_key(), + value: try_serialize_record(&chunk, RecordKind::Chunk)?.to_vec(), + expires: None, + publisher: None, + }; + + // Store the chunk using put_verified + assert!(store + .put_verified(record.clone(), RecordType::Chunk) + .is_ok()); + + // Mark as stored (simulating the CompletedWrite event) + store.mark_as_stored(record.key.clone(), RecordType::Chunk); + + // Verify the chunk is stored + let stored_record = store.get(&record.key); + assert!(stored_record.is_some(), "Chunk should be stored"); + + // Sleep a while to let OS completes the flush to disk + sleep(Duration::from_secs(1)).await; + + // Restart the store with same encrypt_seed + drop(store); + let store = NodeRecordStore::with_config( + self_id, + store_config, + network_event_sender.clone(), + swarm_cmd_sender.clone(), + ); + + // Sleep a lit bit to let OS completes restoring + sleep(Duration::from_secs(1)).await; + + // Verify the record still exists + let stored_record = store.get(&record.key); + assert!(stored_record.is_some(), "Chunk should be stored"); + + // Restart the store with different encrypt_seed + let self_id_diff = PeerId::random(); + let store_config_diff = NodeRecordStoreConfig { + storage_dir: temp_dir.to_path_buf(), + encryption_seed: [2u8; 16], + ..Default::default() + }; + let store_diff = NodeRecordStore::with_config( + self_id_diff, + store_config_diff, + network_event_sender, + swarm_cmd_sender, + ); + + // Sleep a lit bit to let OS completes restoring (if has) + sleep(Duration::from_secs(1)).await; + + // Verify the record existence, shall get removed when encryption enabled + if cfg!(feature = "encrypt-records") { + assert!( + store_diff.get(&record.key).is_none(), + "Chunk should be gone" + ); + } else { + assert!( + store_diff.get(&record.key).is_some(), + "Chunk shall persists without encryption" + ); + } + + Ok(()) + } + #[tokio::test] async fn can_store_and_retrieve_chunk() { let temp_dir = std::env::temp_dir(); From e7f7e03000d4b0455eb0e6ebc4e0677cf739eee7 Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Tue, 5 Nov 2024 17:09:02 +0530 Subject: [PATCH 14/24] feat(manager): introduce sleep interval when stopping node services --- node-launchpad/src/node_mgmt.rs | 2 +- sn_node_manager/src/bin/cli/main.rs | 8 +++++++- sn_node_manager/src/cmd/node.rs | 12 ++++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 2c3b6205a9..5b7c2ae769 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -20,7 +20,7 @@ const NODE_ADD_MAX_RETRIES: u32 = 5; pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) { tokio::task::spawn_local(async move { if let Err(err) = - sn_node_manager::cmd::node::stop(vec![], services, VerbosityLevel::Minimal).await + sn_node_manager::cmd::node::stop(None, vec![], services, VerbosityLevel::Minimal).await { error!("Error while stopping services {err:?}"); if let Err(err) = diff --git a/sn_node_manager/src/bin/cli/main.rs b/sn_node_manager/src/bin/cli/main.rs index 9269f76889..db4936d686 100644 --- a/sn_node_manager/src/bin/cli/main.rs +++ b/sn_node_manager/src/bin/cli/main.rs @@ -376,6 +376,11 @@ pub enum SubCmd { /// sudo if you defined system-wide services; otherwise, do not run the command elevated. #[clap(name = "stop")] Stop { + /// An interval applied between stopping each service. + /// + /// Units are milliseconds. + #[clap(long, conflicts_with = "connection-timeout")] + interval: Option, /// The peer ID of the service to stop. /// /// The argument can be used multiple times to stop many services. @@ -1367,9 +1372,10 @@ async fn main() -> Result<()> { json, }) => cmd::node::status(details, fail, json).await, Some(SubCmd::Stop { + interval, peer_id: peer_ids, service_name: service_names, - }) => cmd::node::stop(peer_ids, service_names, verbosity).await, + }) => cmd::node::stop(interval, peer_ids, service_names, verbosity).await, Some(SubCmd::Upgrade { connection_timeout, do_not_start, diff --git a/sn_node_manager/src/cmd/node.rs b/sn_node_manager/src/cmd/node.rs index 7d6a10871a..454295e514 100644 --- a/sn_node_manager/src/cmd/node.rs +++ b/sn_node_manager/src/cmd/node.rs @@ -293,7 +293,7 @@ pub async fn reset(force: bool, verbosity: VerbosityLevel) -> Result<()> { } } - stop(vec![], vec![], verbosity).await?; + stop(None, vec![], vec![], verbosity).await?; remove(false, vec![], vec![], verbosity).await?; // Due the possibility of repeated runs of the `reset` command, we need to check for the @@ -406,6 +406,7 @@ pub async fn status(details: bool, fail: bool, json: bool) -> Result<()> { } pub async fn stop( + interval: Option, peer_ids: Vec, service_names: Vec, verbosity: VerbosityLevel, @@ -442,6 +443,13 @@ pub async fn stop( let service = NodeService::new(node, Box::new(rpc_client)); let mut service_manager = ServiceManager::new(service, Box::new(ServiceController {}), verbosity); + + if service_manager.service.status() == ServiceStatus::Running { + if let Some(interval) = interval { + debug!("Sleeping for {} milliseconds", interval); + std::thread::sleep(std::time::Duration::from_millis(interval)); + } + } match service_manager.stop().await { Ok(()) => { debug!("Stopped service {}", node.service_name); @@ -662,7 +670,7 @@ pub async fn maintain_n_running_nodes( "Stopping {} excess nodes: {:?}", to_stop_count, services_to_stop ); - stop(vec![], services_to_stop, verbosity).await?; + stop(None, vec![], services_to_stop, verbosity).await?; } Ordering::Less => { let to_start_count = target_count - running_count; From 45336addd1f51b109b2fbe6b19fbd4f50df973b4 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Tue, 5 Nov 2024 17:32:38 +0100 Subject: [PATCH 15/24] feat(launchpad): upgrade nodes version --- node-launchpad/.config/config.json5 | 2 + node-launchpad/src/action.rs | 4 + node-launchpad/src/app.rs | 4 +- node-launchpad/src/components/options.rs | 73 ++++--- node-launchpad/src/components/popup.rs | 1 + .../src/components/popup/rewards_address.rs | 1 - .../src/components/popup/upgrade_nodes.rs | 182 ++++++++++++++++++ node-launchpad/src/components/status.rs | 124 ++++++++++-- node-launchpad/src/mode.rs | 1 + node-launchpad/src/node_mgmt.rs | 54 ++++++ sn_node_manager/src/cmd/mod.rs | 8 +- sn_node_manager/src/cmd/node.rs | 4 +- 12 files changed, 414 insertions(+), 44 deletions(-) create mode 100644 node-launchpad/src/components/popup/upgrade_nodes.rs diff --git a/node-launchpad/.config/config.json5 b/node-launchpad/.config/config.json5 index c630bfdc7f..ac376945d3 100644 --- a/node-launchpad/.config/config.json5 +++ b/node-launchpad/.config/config.json5 @@ -54,6 +54,8 @@ "": {"OptionsActions":"TriggerAccessLogs"}, "": {"OptionsActions":"TriggerAccessLogs"}, "": {"OptionsActions":"TriggerAccessLogs"}, + "": {"OptionsActions":"TriggerUpdateNodes"}, + "": {"OptionsActions":"TriggerUpdateNodes"}, "": {"OptionsActions":"TriggerResetNodes"}, "": {"OptionsActions":"TriggerResetNodes"}, "": {"OptionsActions":"TriggerResetNodes"}, diff --git a/node-launchpad/src/action.rs b/node-launchpad/src/action.rs index 60c6cd618d..2cc81ca675 100644 --- a/node-launchpad/src/action.rs +++ b/node-launchpad/src/action.rs @@ -48,6 +48,7 @@ pub enum StatusActions { StartNodesCompleted, StopNodesCompleted, ResetNodesCompleted { trigger_start_node: bool }, + UpdateNodesCompleted, SuccessfullyDetectedNatStatus, ErrorWhileRunningNatDetection, ErrorLoadingNodeRegistry { raw_error: String }, @@ -55,6 +56,7 @@ pub enum StatusActions { ErrorScalingUpNodes { raw_error: String }, ErrorStoppingNodes { raw_error: String }, ErrorResettingNodes { raw_error: String }, + ErrorUpdatingNodes { raw_error: String }, NodesStatsObtained(NodeStats), TriggerManageNodes, @@ -67,11 +69,13 @@ pub enum StatusActions { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Display, Deserialize)] pub enum OptionsActions { ResetNodes, + UpdateNodes, TriggerChangeDrive, TriggerChangeConnectionMode, TriggerChangePortRange, TriggerRewardsAddress, + TriggerUpdateNodes, TriggerResetNodes, TriggerAccessLogs, UpdateConnectionMode(ConnectionMode), diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 7c191b1abe..f4247b114b 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -16,7 +16,7 @@ use crate::{ popup::{ change_drive::ChangeDrivePopup, connection_mode::ChangeConnectionModePopUp, manage_nodes::ManageNodes, port_range::PortRangePopUp, reset_nodes::ResetNodesPopup, - rewards_address::RewardsAddress, + rewards_address::RewardsAddress, upgrade_nodes::UpgradeNodesPopUp, }, status::{Status, StatusConfig}, Component, @@ -120,6 +120,7 @@ impl App { let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; let port_range = PortRangePopUp::new(connection_mode, port_from, port_to); let rewards_address = RewardsAddress::new(app_data.discord_username.clone()); + let upgrade_nodes = UpgradeNodesPopUp::default(); Ok(Self { config, @@ -146,6 +147,7 @@ impl App { Box::new(rewards_address), Box::new(reset_nodes), Box::new(manage_nodes), + Box::new(upgrade_nodes), ], should_quit: false, should_suspend: false, diff --git a/node-launchpad/src/components/options.rs b/node-launchpad/src/components/options.rs index a631d41b5e..4f59a89f3c 100644 --- a/node-launchpad/src/components/options.rs +++ b/node-launchpad/src/components/options.rs @@ -1,6 +1,6 @@ -use std::path::PathBuf; +use std::{cmp::max, path::PathBuf}; -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::{eyre, Ok, Result}; use ratatui::{ layout::{Alignment, Constraint, Direction, Layout, Rect}, style::{Style, Stylize}, @@ -74,7 +74,7 @@ impl Component for Options { Constraint::Length(7), Constraint::Length(3), Constraint::Length(3), - Constraint::Length(3), + Constraint::Length(4), Constraint::Length(3), ] .as_ref(), @@ -271,35 +271,58 @@ impl Component for Options { .block(block3) .style(Style::default().fg(GHOST_WHITE)); - // Reset All Nodes + // Update Nodes let reset_legend = " Begin Reset "; let reset_key = " [Ctrl+R] "; + let upgrade_legend = " Begin Upgrade "; + let upgrade_key = " [Ctrl+U] "; let block4 = Block::default() - .title(" Reset All Nodes ") + .title(" Update Nodes ") .title_style(Style::default().bold().fg(GHOST_WHITE)) .style(Style::default().fg(GHOST_WHITE)) .borders(Borders::ALL) .border_style(Style::default().fg(EUCALYPTUS)); let reset_nodes = Table::new( - vec![Row::new(vec![ - Cell::from( - Line::from(vec![Span::styled( - " Remove and Reset all Nodes on this device ", - Style::default().fg(LIGHT_PERIWINKLE), - )]) - .alignment(Alignment::Left), - ), - Cell::from( - Line::from(vec![ - Span::styled(reset_legend, Style::default().fg(EUCALYPTUS)), - Span::styled(reset_key, Style::default().fg(GHOST_WHITE)), - ]) - .alignment(Alignment::Right), - ), - ])], + vec![ + Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Upgrade all Nodes ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![ + Span::styled(upgrade_legend, Style::default().fg(EUCALYPTUS)), + Span::styled(upgrade_key, Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right), + ), + ]), + Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Reset all Nodes on this device ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![ + Span::styled(reset_legend, Style::default().fg(EUCALYPTUS)), + Span::styled(reset_key, Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right), + ), + ]), + ], &[ Constraint::Fill(1), - Constraint::Length((reset_legend.len() + reset_key.len()) as u16), + Constraint::Length( + (max(reset_legend.len(), upgrade_legend.len()) + + max(reset_key.len(), upgrade_key.len())) as u16, + ), ], ) .block(block4) @@ -355,7 +378,8 @@ impl Component for Options { | Scene::ChangeConnectionModePopUp | Scene::ChangePortsPopUp { .. } | Scene::OptionsRewardsAddressPopUp - | Scene::ResetNodesPopUp => { + | Scene::ResetNodesPopUp + | Scene::UpgradeNodesPopUp => { self.active = true; // make sure we're in navigation mode return Ok(Some(Action::SwitchInputMode(InputMode::Navigation))); @@ -402,6 +426,9 @@ impl Component for Options { error!("Failed to open folder: {}", e); } } + OptionsActions::TriggerUpdateNodes => { + return Ok(Some(Action::SwitchScene(Scene::UpgradeNodesPopUp))); + } OptionsActions::TriggerResetNodes => { return Ok(Some(Action::SwitchScene(Scene::ResetNodesPopUp))) } diff --git a/node-launchpad/src/components/popup.rs b/node-launchpad/src/components/popup.rs index 4c0c37a1c7..964dbe8a8d 100644 --- a/node-launchpad/src/components/popup.rs +++ b/node-launchpad/src/components/popup.rs @@ -12,3 +12,4 @@ pub mod manage_nodes; pub mod port_range; pub mod reset_nodes; pub mod rewards_address; +pub mod upgrade_nodes; diff --git a/node-launchpad/src/components/popup/rewards_address.rs b/node-launchpad/src/components/popup/rewards_address.rs index 8ec3741034..a4dd4f0f44 100644 --- a/node-launchpad/src/components/popup/rewards_address.rs +++ b/node-launchpad/src/components/popup/rewards_address.rs @@ -34,7 +34,6 @@ pub struct RewardsAddress { can_save: bool, } -#[allow(dead_code)] enum RewardsAddressState { RewardsAddressAlreadySet, ShowTCs, diff --git a/node-launchpad/src/components/popup/upgrade_nodes.rs b/node-launchpad/src/components/popup/upgrade_nodes.rs new file mode 100644 index 0000000000..d658970867 --- /dev/null +++ b/node-launchpad/src/components/popup/upgrade_nodes.rs @@ -0,0 +1,182 @@ +// Copyright 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// 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 super::super::utils::centered_rect_fixed; +use super::super::Component; +use crate::{ + action::{Action, OptionsActions}, + mode::{InputMode, Scene}, + style::{clear_area, EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, +}; +use color_eyre::Result; +use crossterm::event::{KeyCode, KeyEvent}; +use ratatui::{prelude::*, widgets::*}; + +pub struct UpgradeNodesPopUp { + /// Whether the component is active right now, capturing keystrokes + draw things. + active: bool, +} + +impl UpgradeNodesPopUp { + pub fn new() -> Self { + Self { active: false } + } +} + +impl Default for UpgradeNodesPopUp { + fn default() -> Self { + Self::new() + } +} + +impl Component for UpgradeNodesPopUp { + fn handle_key_events(&mut self, key: KeyEvent) -> Result> { + if !self.active { + return Ok(vec![]); + } + // while in entry mode, keybinds are not captured, so gotta exit entry mode from here + let send_back = match key.code { + KeyCode::Enter => { + debug!("Got Enter, Upgrading nodes..."); + vec![ + Action::OptionsActions(OptionsActions::UpdateNodes), + Action::SwitchScene(Scene::Status), + ] + } + KeyCode::Esc => { + debug!("Got Esc, Not upgrading nodes."); + vec![Action::SwitchScene(Scene::Options)] + } + _ => vec![], + }; + Ok(send_back) + } + + fn update(&mut self, action: Action) -> Result> { + let send_back = match action { + Action::SwitchScene(scene) => match scene { + Scene::UpgradeNodesPopUp => { + self.active = true; + Some(Action::SwitchInputMode(InputMode::Entry)) + } + _ => { + self.active = false; + None + } + }, + _ => None, + }; + Ok(send_back) + } + + fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { + if !self.active { + return Ok(()); + } + + let layer_zero = centered_rect_fixed(52, 15, area); + + let layer_one = Layout::new( + Direction::Vertical, + [ + // for the pop_up_border + Constraint::Length(2), + // for the input field + Constraint::Min(1), + // for the pop_up_border + Constraint::Length(1), + ], + ) + .split(layer_zero); + + // layer zero + let pop_up_border = Paragraph::new("").block( + Block::default() + .borders(Borders::ALL) + .title(" Upgrade all nodes ") + .bold() + .title_style(Style::new().fg(VIVID_SKY_BLUE)) + .padding(Padding::uniform(2)) + .border_style(Style::new().fg(VIVID_SKY_BLUE)), + ); + clear_area(f, layer_zero); + + // split the area into 3 parts, for the lines, hypertext, buttons + let layer_two = Layout::new( + Direction::Vertical, + [ + // for the text + Constraint::Length(9), + // gap + Constraint::Length(4), + // for the buttons + Constraint::Length(1), + ], + ) + .split(layer_one[1]); + + let text = Paragraph::new(vec![ + Line::from(Span::styled("\n\n", Style::default())), + Line::from(vec![ + Span::styled("This will ", Style::default().fg(LIGHT_PERIWINKLE)), + Span::styled( + "stop and upgrade all nodes. ", + Style::default().fg(GHOST_WHITE), + ), + ]), + Line::from(Span::styled( + "No data will be lost.", + Style::default().fg(LIGHT_PERIWINKLE), + )), + Line::from(Span::styled("\n\n", Style::default())), + Line::from(Span::styled("\n\n", Style::default())), + Line::from(vec![ + Span::styled("You’ll need to ", Style::default().fg(LIGHT_PERIWINKLE)), + Span::styled("Start ", Style::default().fg(GHOST_WHITE)), + Span::styled( + "them again afterwards.", + Style::default().fg(LIGHT_PERIWINKLE), + ), + ]), + Line::from(Span::styled( + "Are you sure you want to continue?", + Style::default(), + )), + ]) + .block(Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Center) + .wrap(Wrap { trim: true }); + + f.render_widget(text, layer_two[0]); + + let dash = Block::new() + .borders(Borders::BOTTOM) + .border_style(Style::new().fg(GHOST_WHITE)); + f.render_widget(dash, layer_two[1]); + + let buttons_layer = + Layout::horizontal(vec![Constraint::Percentage(45), Constraint::Percentage(55)]) + .split(layer_two[2]); + + let button_no = Line::from(vec![Span::styled( + " No, Cancel [Esc]", + Style::default().fg(LIGHT_PERIWINKLE), + )]); + f.render_widget(button_no, buttons_layer[0]); + + let button_yes = Paragraph::new(Line::from(vec![Span::styled( + "Yes, Upgrade [Enter] ", + Style::default().fg(EUCALYPTUS), + )])) + .alignment(Alignment::Right); + f.render_widget(button_yes, buttons_layer[1]); + f.render_widget(pop_up_border, layer_zero); + + Ok(()) + } +} diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 3c82045f7b..1847ef1ee5 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -17,7 +17,7 @@ use crate::components::popup::port_range::PORT_ALLOCATION; use crate::config::get_launchpad_nodes_data_dir_path; use crate::connection_mode::ConnectionMode; use crate::error::ErrorPopup; -use crate::node_mgmt::MaintainNodesArgs; +use crate::node_mgmt::{upgrade_nodes, MaintainNodesArgs, UpgradeNodesArgs}; use crate::node_mgmt::{PORT_MAX, PORT_MIN}; use crate::style::{COOL_GREY, INDIGO}; use crate::tui::Event; @@ -111,6 +111,7 @@ pub enum LockRegistryState { StartingNodes, StoppingNodes, ResettingNodes, + UpdatingNodes, } pub struct StatusConfig { @@ -167,7 +168,7 @@ impl Status<'_> { Ok(status) } - fn update_node_items(&mut self) -> Result<()> { + fn update_node_items(&mut self, new_status: Option) -> Result<()> { // Iterate over existing node services and update their corresponding NodeItem if let Some(ref mut items) = self.items { for node_item in self.node_services.iter() { @@ -177,21 +178,27 @@ impl Status<'_> { .iter_mut() .find(|i| i.name == node_item.service_name) { - // Update status based on current node status - item.status = match node_item.status { - ServiceStatus::Running => { + if let Some(status) = new_status { + item.status = status; + } else { + // Update status based on current node status + item.status = match node_item.status { + ServiceStatus::Running => { + NodeItem::update_spinner_state(&mut item.spinner_state); + NodeStatus::Running + } + ServiceStatus::Stopped => NodeStatus::Stopped, + ServiceStatus::Added => NodeStatus::Added, + ServiceStatus::Removed => NodeStatus::Removed, + }; + + // Starting is not part of ServiceStatus so we do it manually + if let Some(LockRegistryState::StartingNodes) = self.lock_registry { NodeItem::update_spinner_state(&mut item.spinner_state); - NodeStatus::Running + if item.status != NodeStatus::Running { + item.status = NodeStatus::Starting; + } } - ServiceStatus::Stopped => NodeStatus::Stopped, - ServiceStatus::Added => NodeStatus::Added, - ServiceStatus::Removed => NodeStatus::Removed, - }; - - // Starting is not part of ServiceStatus so we do it manually - if let Some(LockRegistryState::StartingNodes) = self.lock_registry { - NodeItem::update_spinner_state(&mut item.spinner_state); - item.status = NodeStatus::Starting; } // Update peers count @@ -332,6 +339,21 @@ impl Status<'_> { }) .collect() } + + fn get_service_names_and_peer_ids(&self) -> (Vec, Vec) { + let mut service_names = Vec::new(); + let mut peers_ids = Vec::new(); + + for node in &self.node_services { + // Only include nodes with a valid peer_id + if let Some(peer_id) = &node.peer_id { + service_names.push(node.service_name.clone()); + peers_ids.push(peer_id.to_string().clone()); + } + } + + (service_names, peers_ids) + } } impl Component for Status<'_> { @@ -361,7 +383,7 @@ impl Component for Status<'_> { match action { Action::Tick => { self.try_update_node_stats(false)?; - let _ = self.update_node_items(); + let _ = self.update_node_items(None); } Action::SwitchScene(scene) => match scene { Scene::Status | Scene::StatusRewardsAddressPopUp => { @@ -431,6 +453,13 @@ impl Component for Status<'_> { self.lock_registry = None; self.load_node_registry_and_update_states()?; } + StatusActions::UpdateNodesCompleted => { + self.lock_registry = None; + self.clear_node_items(); + self.load_node_registry_and_update_states()?; + let _ = self.update_node_items(None); + debug!("Update nodes completed"); + } StatusActions::ResetNodesCompleted { trigger_start_node } => { self.lock_registry = None; self.load_node_registry_and_update_states()?; @@ -492,6 +521,18 @@ impl Component for Status<'_> { // Switch back to entry mode so we can handle key events return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); } + StatusActions::ErrorUpdatingNodes { raw_error } => { + self.error_popup = Some(ErrorPopup::new( + "Error".to_string(), + "Error upgrading nodes".to_string(), + raw_error, + )); + if let Some(error_popup) = &mut self.error_popup { + error_popup.show(); + } + // Switch back to entry mode so we can handle key events + return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); + } StatusActions::ErrorResettingNodes { raw_error } => { self.error_popup = Some(ErrorPopup::new( "Error".to_string(), @@ -591,6 +632,40 @@ impl Component for Status<'_> { } } }, + Action::OptionsActions(OptionsActions::UpdateNodes) => { + debug!("Got action to Update Nodes"); + self.load_node_registry_and_update_states()?; + if self.lock_registry.is_some() { + error!( + "Registry is locked ({:?}) Cannot Update nodes now. Stop them first.", + self.lock_registry + ); + return Ok(None); + } else { + debug!("Lock registry ({:?})", self.lock_registry); + }; + debug!("Setting lock_registry to UpdatingNodes"); + self.lock_registry = Some(LockRegistryState::UpdatingNodes); + let action_sender = self.get_actions_sender()?; + info!("Got action to update nodes"); + let _ = self.update_node_items(Some(NodeStatus::Updating)); + let (service_names, peer_ids) = self.get_service_names_and_peer_ids(); + + let upgrade_nodes_args = UpgradeNodesArgs { + action_sender, + connection_timeout_s: 5, + do_not_start: true, + custom_bin_path: None, + force: false, + fixed_interval: None, + peer_ids, + provided_env_variables: None, + service_names, + url: None, + version: None, + }; + upgrade_nodes(upgrade_nodes_args); + } Action::OptionsActions(OptionsActions::ResetNodes) => { debug!("Got action to reset nodes"); if self.lock_registry.is_some() { @@ -919,6 +994,9 @@ impl Component for Status<'_> { Line::raw("Resetting nodes..."), ] } + LockRegistryState::UpdatingNodes => { + return Ok(()); + } }; if !popup_text.is_empty() { let popup_area = centered_rect_fixed(50, 12, area); @@ -1027,6 +1105,7 @@ enum NodeStatus { Starting, Stopped, Removed, + Updating, } impl fmt::Display for NodeStatus { @@ -1037,6 +1116,7 @@ impl fmt::Display for NodeStatus { NodeStatus::Starting => write!(f, "Starting"), NodeStatus::Stopped => write!(f, "Stopped"), NodeStatus::Removed => write!(f, "Removed"), + NodeStatus::Updating => write!(f, "Updating"), } } } @@ -1100,6 +1180,18 @@ impl NodeItem<'_> { .throbber_set(throbber_widgets_tui::BRAILLE_SIX_DOUBLE) .use_type(throbber_widgets_tui::WhichUse::Full); } + NodeStatus::Updating => { + self.spinner = self + .spinner + .clone() + .throbber_style( + Style::default() + .fg(GHOST_WHITE) + .add_modifier(Modifier::BOLD), + ) + .throbber_set(throbber_widgets_tui::VERTICAL_BLOCK) + .use_type(throbber_widgets_tui::WhichUse::Full); + } _ => {} }; diff --git a/node-launchpad/src/mode.rs b/node-launchpad/src/mode.rs index b6cc6c4a40..a74047e7dc 100644 --- a/node-launchpad/src/mode.rs +++ b/node-launchpad/src/mode.rs @@ -25,6 +25,7 @@ pub enum Scene { OptionsRewardsAddressPopUp, ManageNodesPopUp, ResetNodesPopUp, + UpgradeNodesPopUp, } #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 5b7c2ae769..5875997190 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -128,8 +128,62 @@ pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_res }); } +pub struct UpgradeNodesArgs { + pub action_sender: UnboundedSender, + pub connection_timeout_s: u64, + pub do_not_start: bool, + pub custom_bin_path: Option, + pub force: bool, + pub fixed_interval: Option, + pub peer_ids: Vec, + pub provided_env_variables: Option>, + pub service_names: Vec, + pub url: Option, + pub version: Option, +} + +pub fn upgrade_nodes(args: UpgradeNodesArgs) { + tokio::task::spawn_local(async move { + if let Err(err) = sn_node_manager::cmd::node::upgrade( + args.connection_timeout_s, + args.do_not_start, + args.custom_bin_path, + args.force, + args.fixed_interval, + args.peer_ids, + args.provided_env_variables, + args.service_names, + args.url, + args.version, + VerbosityLevel::Minimal, + ) + .await + { + error!("Error while updating services {err:?}"); + send_action( + args.action_sender, + Action::StatusActions(StatusActions::ErrorUpdatingNodes { + raw_error: err.to_string(), + }), + ); + } else { + info!("Successfully updated services"); + send_action( + args.action_sender, + Action::StatusActions(StatusActions::UpdateNodesCompleted), + ); + } + }); +} + // --- Helper functions --- +fn send_action(action_sender: UnboundedSender, action: Action) { + if let Err(err) = action_sender.send(action) { + error!("Error while sending action: {err:?}"); + } +} + /// Load the node registry and handle errors async fn load_node_registry( action_sender: &UnboundedSender, diff --git a/sn_node_manager/src/cmd/mod.rs b/sn_node_manager/src/cmd/mod.rs index 9e6af9351d..fa8ec6be78 100644 --- a/sn_node_manager/src/cmd/mod.rs +++ b/sn_node_manager/src/cmd/mod.rs @@ -73,10 +73,14 @@ pub async fn download_and_get_upgrade_bin_path( .await?; Ok((upgrade_bin_path, Version::parse(&version)?)) } else { - println!("Retrieving latest version of {release_type}..."); + if verbosity != VerbosityLevel::Minimal { + println!("Retrieving latest version of {release_type}..."); + } debug!("Retrieving latest version of {release_type}..."); let latest_version = release_repo.get_latest_version(&release_type).await?; - println!("Latest version is {latest_version}"); + if verbosity != VerbosityLevel::Minimal { + println!("Latest version is {latest_version}"); + } debug!("Download latest version {latest_version} of {release_type}"); let (upgrade_bin_path, _) = download_and_extract_release( diff --git a/sn_node_manager/src/cmd/node.rs b/sn_node_manager/src/cmd/node.rs index 454295e514..049a1d2337 100644 --- a/sn_node_manager/src/cmd/node.rs +++ b/sn_node_manager/src/cmd/node.rs @@ -593,7 +593,9 @@ pub async fn upgrade( } } - print_upgrade_summary(upgrade_summary.clone()); + if verbosity != VerbosityLevel::Minimal { + print_upgrade_summary(upgrade_summary.clone()); + } if upgrade_summary.iter().any(|(_, r)| { matches!(r, UpgradeResult::Error(_)) From 907d504bac0f8be0b62a9b45231c97c90887c9be Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Tue, 29 Oct 2024 17:33:38 +0100 Subject: [PATCH 16/24] feat(launchpad): more error handling --- node-launchpad/src/node_mgmt.rs | 105 +++++++++++++++++--------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 5875997190..1e2f8a4371 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -23,20 +23,18 @@ pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) sn_node_manager::cmd::node::stop(None, vec![], services, VerbosityLevel::Minimal).await { error!("Error while stopping services {err:?}"); - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::ErrorStoppingNodes { + send_action( + action_sender, + Action::StatusActions(StatusActions::ErrorStoppingNodes { raw_error: err.to_string(), - })) - { - error!("Error while sending action: {err:?}"); - } + }), + ); } else { info!("Successfully stopped services"); - } - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::StopNodesCompleted)) - { - error!("Error while sending action: {err:?}"); + send_action( + action_sender, + Action::StatusActions(StatusActions::StopNodesCompleted), + ); } }); } @@ -94,12 +92,10 @@ pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { } debug!("Finished maintaining {} nodes", args.count); - if let Err(err) = args - .action_sender - .send(Action::StatusActions(StatusActions::StartNodesCompleted)) - { - error!("Error while sending action: {err:?}"); - } + send_action( + args.action_sender, + Action::StatusActions(StatusActions::StartNodesCompleted), + ); }); } @@ -108,22 +104,20 @@ pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_res tokio::task::spawn_local(async move { if let Err(err) = sn_node_manager::cmd::node::reset(true, VerbosityLevel::Minimal).await { error!("Error while resetting services {err:?}"); - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::ErrorResettingNodes { + send_action( + action_sender, + Action::StatusActions(StatusActions::ErrorResettingNodes { raw_error: err.to_string(), - })) - { - error!("Error while sending action: {err:?}"); - } + }), + ); } else { info!("Successfully reset services"); - } - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::ResetNodesCompleted { - trigger_start_node: start_nodes_after_reset, - })) - { - error!("Error while sending action: {err:?}"); + send_action( + action_sender, + Action::StatusActions(StatusActions::ResetNodesCompleted { + trigger_start_node: start_nodes_after_reset, + }), + ); } }); } @@ -345,7 +339,7 @@ async fn scale_down_nodes(config: &NodeConfig, count: u16) { config.data_dir_path.clone(), true, None, - Some(EvmNetwork::ArbitrumSepolia), //FIXME: should come from an UI element. + Some(EvmNetwork::ArbitrumSepolia), config.home_network, false, None, @@ -398,16 +392,15 @@ async fn add_nodes( if *current_port > max_port { error!("Reached maximum port number. Unable to find an available port."); - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::ErrorScalingUpNodes { + send_action( + action_sender.clone(), + Action::StatusActions(StatusActions::ErrorScalingUpNodes { raw_error: format!( "Reached maximum port number ({}).\nUnable to find an available port.", max_port ), - })) - { - error!("Error while sending action: {err:?}"); - } + }), + ); break; } @@ -420,7 +413,7 @@ async fn add_nodes( config.data_dir_path.clone(), true, None, - Some(EvmNetwork::ArbitrumSepolia), //FIXME: Should come from an UI element + Some(EvmNetwork::ArbitrumSepolia), config.home_network, false, None, @@ -466,16 +459,29 @@ async fn add_nodes( .contains("Failed to add one or more services") && retry_count >= NODE_ADD_MAX_RETRIES { - if let Err(err) = action_sender.send(Action::StatusActions( - StatusActions::ErrorScalingUpNodes { + send_action( + action_sender.clone(), + Action::StatusActions(StatusActions::ErrorScalingUpNodes { raw_error: "When trying to add a node, we failed.\n\ Maybe you ran out of disk space?\n\ Maybe you need to change the port range?" .to_string(), - }, - )) { - error!("Error while sending action: {err:?}"); - } + }), + ); + } else if err + .to_string() + .contains("contains a virus or potentially unwanted software") + && retry_count >= NODE_ADD_MAX_RETRIES + { + send_action( + action_sender.clone(), + Action::StatusActions(StatusActions::ErrorScalingUpNodes { + raw_error: "When trying to add a node, we failed.\n\ + You may be running an old version of safenode service?\n\ + Did you whitelisted safenode and the launchpad?" + .to_string(), + }), + ); } else { error!("Range of ports to be used {:?}", *current_port..max_port); error!("Error while adding node on port {}: {err:?}", current_port); @@ -487,17 +493,16 @@ async fn add_nodes( } } if retry_count >= NODE_ADD_MAX_RETRIES { - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::ErrorScalingUpNodes { + send_action( + action_sender.clone(), + Action::StatusActions(StatusActions::ErrorScalingUpNodes { raw_error: format!( "When trying run a node, we reached the maximum amount of retries ({}).\n\ Could this be a firewall blocking nodes starting?\n\ Or ports on your router already in use?", NODE_ADD_MAX_RETRIES ), - })) - { - error!("Error while sending action: {err:?}"); - } + }), + ); } } From d79729be39346b13a22c5e754f5b02ec22d8134f Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 30 Oct 2024 15:12:12 +0100 Subject: [PATCH 17/24] fix(launchpad): help section changed after beta --- node-launchpad/src/components/help.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/node-launchpad/src/components/help.rs b/node-launchpad/src/components/help.rs index 9270616d27..c091c18ba5 100644 --- a/node-launchpad/src/components/help.rs +++ b/node-launchpad/src/components/help.rs @@ -96,17 +96,17 @@ impl Component for Help { let quickstart_guide_link = Hyperlink::new( Span::styled( - "docs.autonomi.com/getstarted", + "autonomi.com/getstarted", Style::default().fg(VIVID_SKY_BLUE).underlined(), ), - "https://docs.autonomi.com/getstarted", + "https://autonomi.com/getstarted", ); - let beta_rewards_link = Hyperlink::new( + let terms_and_conditions_link = Hyperlink::new( Span::styled( - "autonomi.com/beta", + "autonomi.com/terms", Style::default().fg(VIVID_SKY_BLUE).underlined(), ), - "https://autonomi.com/beta", + "https://autonomi.com/terms", ); let get_direct_support_link = Hyperlink::new( Span::styled( @@ -134,7 +134,7 @@ impl Component for Help { // Render hyperlinks in the new area f.render_widget( Span::styled( - "See the quick start guides:", + "Read the quick start guides:", Style::default().fg(GHOST_WHITE), ), left_column[0], @@ -147,20 +147,17 @@ impl Component for Help { f.render_widget_ref(get_direct_support_link, left_column[3]); f.render_widget( Span::styled( - "To join the Beta Rewards Program:", + "Download the latest launchpad:", Style::default().fg(GHOST_WHITE), ), right_column[0], ); - f.render_widget_ref(beta_rewards_link, right_column[1]); + f.render_widget_ref(download_latest_link, right_column[1]); f.render_widget( - Span::styled( - "Download the latest launchpad:", - Style::default().fg(GHOST_WHITE), - ), + Span::styled("Terms & Conditions:", Style::default().fg(GHOST_WHITE)), right_column[2], ); - f.render_widget_ref(download_latest_link, right_column[3]); + f.render_widget_ref(terms_and_conditions_link, right_column[3]); f.render_widget(block, layout[1]); From 99977b94dd5a9c809b1e1894fb72ac51578740e6 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 4 Nov 2024 10:02:34 +0100 Subject: [PATCH 18/24] chore(launchpad): update ratatui and throbbber versions --- Cargo.lock | 36 ++++++++++++++++--------- node-launchpad/Cargo.toml | 4 +-- node-launchpad/src/components/status.rs | 16 +++-------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dcbc426bd6..ec2a9ddb1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1793,7 +1793,7 @@ dependencies = [ "strsim", "terminal_size", "unicase", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -1925,7 +1925,7 @@ dependencies = [ "encode_unicode 0.3.6", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] @@ -4436,9 +4436,15 @@ dependencies = [ "number_prefix", "portable-atomic", "tokio", - "unicode-width", + "unicode-width 0.1.14", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + [[package]] name = "inferno" version = "0.11.21" @@ -6568,7 +6574,7 @@ dependencies = [ "is-terminal", "lazy_static", "term", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -7091,24 +7097,24 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ "bitflags 2.6.0", "cassowary", "compact_str", "crossterm 0.28.1", + "indoc", "instability", "itertools 0.13.0", "lru", "paste", "serde", "strum", - "strum_macros", "unicode-segmentation", "unicode-truncate", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -8946,9 +8952,9 @@ dependencies = [ [[package]] name = "throbber-widgets-tui" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad9e055cadd9da8b4a67662b962e3e67e96af491ae9cec7e88aaff92e7c3666" +checksum = "1d36b5738d666a2b4c91b7c24998a8588db724b3107258343ebf8824bf55b06d" dependencies = [ "rand 0.8.5", "ratatui", @@ -9501,7 +9507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3e785f863a3af4c800a2a669d0b64c879b538738e352607e2624d03f868dc01" dependencies = [ "crossterm 0.27.0", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -9603,7 +9609,7 @@ checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools 0.13.0", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -9612,6 +9618,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 925bb282bf..2f0e4f2dae 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -44,7 +44,7 @@ libc = "0.2.148" log = "0.4.20" pretty_assertions = "1.4.0" prometheus-parse = "0.2.5" -ratatui = { version = "0.28.1", features = ["serde", "macros", "unstable-widget-ref"] } +ratatui = { version = "0.29.0", features = ["serde", "macros", "unstable-widget-ref"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } @@ -69,7 +69,7 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter", "serde"] } tui-input = "0.8.0" which = "6.0.1" faccess = "0.2.4" -throbber-widgets-tui = "0.7.0" +throbber-widgets-tui = "0.8.0" regex = "1.11.0" [build-dependencies] diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 1847ef1ee5..497198c7f7 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -184,7 +184,7 @@ impl Status<'_> { // Update status based on current node status item.status = match node_item.status { ServiceStatus::Running => { - NodeItem::update_spinner_state(&mut item.spinner_state); + item.spinner_state.calc_next(); NodeStatus::Running } ServiceStatus::Stopped => NodeStatus::Stopped, @@ -194,7 +194,7 @@ impl Status<'_> { // Starting is not part of ServiceStatus so we do it manually if let Some(LockRegistryState::StartingNodes) = self.lock_registry { - NodeItem::update_spinner_state(&mut item.spinner_state); + item.spinner_state.calc_next(); if item.status != NodeStatus::Running { item.status = NodeStatus::Starting; } @@ -923,7 +923,7 @@ impl Component for Status<'_> { let table = Table::new(items, node_widths) .header(header_row) .column_spacing(1) - .highlight_style(Style::default().bg(INDIGO)) + .row_highlight_style(Style::default().bg(INDIGO)) .highlight_spacing(HighlightSpacing::Always); f.render_widget(table, inner_area); @@ -1137,16 +1137,6 @@ pub struct NodeItem<'a> { } impl NodeItem<'_> { - fn update_spinner_state(state: &mut ThrobberState) { - // Call calc_next on the spinner state - // https://github.com/arkbig/throbber-widgets-tui/issues/19 - if state.index() == i8::MAX { - *state = ThrobberState::default(); - } else { - state.calc_next(); - } - } - fn render_as_row(&mut self, index: usize, area: Rect, f: &mut Frame<'_>) -> Row { let mut row_style = Style::default().fg(GHOST_WHITE); let mut spinner_state = self.spinner_state.clone(); From 6aad3ae2e6591ea7ce7e8cae553be6ad85c728ab Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 4 Nov 2024 12:14:10 +0100 Subject: [PATCH 19/24] feat(launchpad): ctrl v pasting on rewards address --- Cargo.lock | 291 ++++++++++++++++++ node-launchpad/Cargo.toml | 1 + .../src/components/popup/rewards_address.rs | 19 +- 3 files changed, 310 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ec2a9ddb1e..d0a9e6bc07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -726,6 +726,24 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +[[package]] +name = "arboard" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" +dependencies = [ + "clipboard-win", + "core-graphics", + "image", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "parking_lot", + "windows-sys 0.48.0", + "x11rb", +] + [[package]] name = "arc-swap" version = "1.7.1" @@ -1409,6 +1427,15 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + [[package]] name = "blst" version = "0.3.13" @@ -1545,6 +1572,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.7.2" @@ -1814,6 +1847,15 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -2009,6 +2051,30 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + [[package]] name = "core2" version = "0.4.0" @@ -2786,6 +2852,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-code" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" + [[package]] name = "event-listener" version = "5.3.1" @@ -2883,6 +2955,15 @@ dependencies = [ "bytes", ] +[[package]] +name = "fdeflate" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" +dependencies = [ + "simd-adler32", +] + [[package]] name = "ff" version = "0.12.1" @@ -3014,6 +3095,33 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -3225,6 +3333,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -4377,6 +4495,19 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "image" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" +dependencies = [ + "bytemuck", + "byteorder-lite", + "num-traits", + "png", + "tiff", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -4572,6 +4703,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.70" @@ -5475,6 +5612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -5755,6 +5893,7 @@ dependencies = [ name = "node-launchpad" version = "0.4.3-rc.2" dependencies = [ + "arboard", "atty", "better-panic", "chrono", @@ -5946,6 +6085,105 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + [[package]] name = "object" version = "0.32.2" @@ -6429,6 +6667,19 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.0", +] + [[package]] name = "polling" version = "3.7.3" @@ -8136,6 +8387,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.9" @@ -8960,6 +9217,17 @@ dependencies = [ "ratatui", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.36" @@ -9993,6 +10261,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "which" version = "4.4.2" @@ -10304,6 +10578,23 @@ dependencies = [ "tap", ] +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "gethostname", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + [[package]] name = "x25519-dalek" version = "2.0.1" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 2f0e4f2dae..4860cf7959 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -71,6 +71,7 @@ which = "6.0.1" faccess = "0.2.4" throbber-widgets-tui = "0.8.0" regex = "1.11.0" +arboard = "3.4.1" [build-dependencies] vergen = { version = "8.2.6", features = ["build", "git", "gitoxide", "cargo"] } diff --git a/node-launchpad/src/components/popup/rewards_address.rs b/node-launchpad/src/components/popup/rewards_address.rs index a4dd4f0f44..4cb2816f2b 100644 --- a/node-launchpad/src/components/popup/rewards_address.rs +++ b/node-launchpad/src/components/popup/rewards_address.rs @@ -14,8 +14,9 @@ use crate::{ style::{clear_area, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, RED, VIVID_SKY_BLUE}, widgets::hyperlink::Hyperlink, }; +use arboard::Clipboard; use color_eyre::Result; -use crossterm::event::{Event, KeyCode, KeyEvent}; +use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use ratatui::{prelude::*, widgets::*}; use regex::Regex; use tui_input::{backend::crossterm::EventHandler, Input}; @@ -112,6 +113,22 @@ impl RewardsAddress { self.validate(); vec![] } + KeyCode::Char('v') => { + if key.modifiers.contains(KeyModifiers::CONTROL) { + let mut clipboard = match Clipboard::new() { + Ok(clipboard) => clipboard, + Err(e) => { + error!("Error reading Clipboard : {:?}", e); + return vec![]; + } + }; + if let Ok(content) = clipboard.get_text() { + self.rewards_address_input_field = + self.rewards_address_input_field.clone().with_value(content); + } + } + vec![] + } _ => { if self.rewards_address_input_field.value().chars().count() < INPUT_SIZE_REWARDS_ADDRESS as usize From 3313ff2fbde47b1202128477c66b92c9a5acdb46 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Tue, 5 Nov 2024 20:28:02 +0000 Subject: [PATCH 20/24] chore(release): release candidate 2024.10.4.5 ================== Crate Versions ================== autonomi: 0.2.3-rc.3 autonomi-cli: 0.1.4-rc.3 evmlib: 0.1.3-rc.3 evm_testnet: 0.1.3-rc.3 sn_build_info: 0.1.18-rc.3 sn_evm: 0.1.3-rc.3 sn_logging: 0.2.39-rc.3 sn_metrics: 0.1.19-rc.3 nat-detection: 0.2.10-rc.3 sn_networking: 0.19.2-rc.3 sn_node: 0.112.3-rc.3 node-launchpad: 0.4.3-rc.3 sn_node_manager: 0.11.2-rc.3 sn_node_rpc_client: 0.6.34-rc.3 sn_peers_acquisition: 0.5.6-rc.3 sn_protocol: 0.17.14-rc.3 sn_registers: 0.4.2-rc.3 sn_service_management: 0.4.2-rc.3 sn_transfers: 0.20.2-rc.3 test_utils: 0.4.10-rc.3 token_supplies: 0.1.57-rc.3 =================== Binary Versions =================== nat-detection: 0.2.10-rc.3 node-launchpad: 0.4.3-rc.3 autonomi: 0.1.4-rc.3 safenode: 0.112.3-rc.3 safenode-manager: 0.11.2-rc.3 safenode_rpc_client: 0.6.34-rc.3 safenodemand: 0.11.2-rc.3 --- Cargo.lock | 42 +++++++++++++++---------------- autonomi-cli/Cargo.toml | 12 ++++----- autonomi/Cargo.toml | 18 ++++++------- evm_testnet/Cargo.toml | 6 ++--- evmlib/Cargo.toml | 2 +- nat-detection/Cargo.toml | 8 +++--- node-launchpad/Cargo.toml | 14 +++++------ release-cycle-info | 2 +- sn_build_info/Cargo.toml | 2 +- sn_build_info/src/release_info.rs | 2 +- sn_evm/Cargo.toml | 4 +-- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 12 ++++----- sn_node/Cargo.toml | 28 ++++++++++----------- sn_node_manager/Cargo.toml | 16 ++++++------ sn_node_rpc_client/Cargo.toml | 16 ++++++------ sn_peers_acquisition/Cargo.toml | 4 +-- sn_protocol/Cargo.toml | 10 ++++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++--- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 6 ++--- token_supplies/Cargo.toml | 2 +- 24 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0a9e6bc07..5a80ec8a35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1094,7 +1094,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autonomi" -version = "0.2.3-rc.2" +version = "0.2.3-rc.3" dependencies = [ "alloy", "bip39", @@ -1141,7 +1141,7 @@ dependencies = [ [[package]] name = "autonomi-cli" -version = "0.1.4-rc.2" +version = "0.1.4-rc.3" dependencies = [ "autonomi", "clap", @@ -2881,7 +2881,7 @@ dependencies = [ [[package]] name = "evm_testnet" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" dependencies = [ "clap", "dirs-next", @@ -2892,7 +2892,7 @@ dependencies = [ [[package]] name = "evmlib" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" dependencies = [ "alloy", "dirs-next", @@ -5774,7 +5774,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.10-rc.2" +version = "0.2.10-rc.3" dependencies = [ "clap", "clap-verbosity-flag", @@ -5891,7 +5891,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.4.3-rc.2" +version = "0.4.3-rc.3" dependencies = [ "arboard", "atty", @@ -8410,7 +8410,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.11.2-rc.2" +version = "0.11.2-rc.3" dependencies = [ "assert_cmd", "assert_fs", @@ -8486,7 +8486,7 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.18-rc.2" +version = "0.1.18-rc.3" dependencies = [ "chrono", "tracing", @@ -8528,7 +8528,7 @@ dependencies = [ [[package]] name = "sn_evm" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" dependencies = [ "custom_debug", "evmlib", @@ -8551,7 +8551,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.39-rc.2" +version = "0.2.39-rc.3" dependencies = [ "chrono", "color-eyre", @@ -8576,7 +8576,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.19-rc.2" +version = "0.1.19-rc.3" dependencies = [ "clap", "color-eyre", @@ -8590,7 +8590,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.19.2-rc.2" +version = "0.19.2-rc.3" dependencies = [ "aes-gcm-siv", "assert_fs", @@ -8638,7 +8638,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.112.3-rc.2" +version = "0.112.3-rc.3" dependencies = [ "assert_fs", "async-trait", @@ -8695,7 +8695,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.34-rc.2" +version = "0.6.34-rc.3" dependencies = [ "assert_fs", "async-trait", @@ -8722,7 +8722,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.6-rc.2" +version = "0.5.6-rc.3" dependencies = [ "clap", "lazy_static", @@ -8738,7 +8738,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.14-rc.2" +version = "0.17.14-rc.3" dependencies = [ "blsttc", "bytes", @@ -8768,7 +8768,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.4.2-rc.2" +version = "0.4.2-rc.3" dependencies = [ "blsttc", "crdts", @@ -8785,7 +8785,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.4.2-rc.2" +version = "0.4.2-rc.3" dependencies = [ "async-trait", "dirs-next", @@ -8811,7 +8811,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.20.2-rc.2" +version = "0.20.2-rc.3" dependencies = [ "assert_fs", "blsttc", @@ -9155,7 +9155,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.10-rc.2" +version = "0.4.10-rc.3" dependencies = [ "bytes", "color-eyre", @@ -9310,7 +9310,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.57-rc.2" +version = "0.1.57-rc.3" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/autonomi-cli/Cargo.toml b/autonomi-cli/Cargo.toml index d9214fa74e..2976882b0d 100644 --- a/autonomi-cli/Cargo.toml +++ b/autonomi-cli/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] name = "autonomi-cli" description = "Autonomi CLI" license = "GPL-3.0" -version = "0.1.4-rc.2" +version = "0.1.4-rc.3" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -24,7 +24,7 @@ name = "files" harness = false [dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = [ "data", "fs", "vault", @@ -50,9 +50,9 @@ tokio = { version = "1.32.0", features = [ "fs", ] } tracing = { version = "~0.1.26" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } walkdir = "2.5.0" serde_json = "1.0.132" serde = "1.0.210" @@ -60,7 +60,7 @@ hex = "0.4.3" ring = "0.17.8" [dev-dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = [ +autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = [ "data", "fs", ] } diff --git a/autonomi/Cargo.toml b/autonomi/Cargo.toml index ef1be61970..cbb60441a0 100644 --- a/autonomi/Cargo.toml +++ b/autonomi/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] description = "Autonomi client API" name = "autonomi" license = "GPL-3.0" -version = "0.2.3-rc.2" +version = "0.2.3-rc.3" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -38,11 +38,11 @@ rand = "0.8.5" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } -sn_protocol = { version = "0.17.14-rc.2", path = "../sn_protocol" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_protocol = { version = "0.17.14-rc.3", path = "../sn_protocol" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } thiserror = "1.0.23" tokio = { version = "1.35.0", features = ["sync"] } tracing = { version = "~0.1.26" } @@ -60,8 +60,8 @@ blstrs = "0.7.1" alloy = { version = "0.5.3", default-features = false, features = ["std", "reqwest-rustls-tls", "provider-anvil-node", "sol-types", "json", "signers", "contract", "signer-local", "network"] } eyre = "0.6.5" sha2 = "0.10.6" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } # Do not specify the version field. Release process expects even the local dev deps to be published. # Removing the version field is a workaround. test_utils = { path = "../test_utils" } @@ -71,7 +71,7 @@ wasm-bindgen-test = "0.3.43" [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.7" -evmlib = { path = "../evmlib", version = "0.1.3-rc.2", features = ["wasm-bindgen"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.3", features = ["wasm-bindgen"] } # See https://github.com/sebcrozet/instant/blob/7bd13f51f5c930239fddc0476a837870fb239ed7/README.md#using-instant-for-a-wasm-platform-where-performancenow-is-not-available instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] } js-sys = "0.3.70" diff --git a/evm_testnet/Cargo.toml b/evm_testnet/Cargo.toml index e69aaf3128..777e4ce10f 100644 --- a/evm_testnet/Cargo.toml +++ b/evm_testnet/Cargo.toml @@ -6,13 +6,13 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evm_testnet" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" [dependencies] clap = { version = "4.5", features = ["derive"] } dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } tokio = { version = "1.40", features = ["rt-multi-thread", "signal"] } [lints] diff --git a/evmlib/Cargo.toml b/evmlib/Cargo.toml index 0526db809e..5a24fba1f6 100644 --- a/evmlib/Cargo.toml +++ b/evmlib/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evmlib" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" [features] wasm-bindgen = ["alloy/wasm-bindgen"] diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 2c4aa402b8..5282b68d82 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.10-rc.2" +version = "0.2.10-rc.3" [[bin]] name = "nat-detection" @@ -31,9 +31,9 @@ libp2p = { version = "0.54.1", features = [ "macros", "upnp", ] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 4860cf7959..f9a338fb19 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.4.3-rc.2" +version = "0.4.3-rc.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -51,13 +51,13 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } -sn-node-manager = { version = "0.11.2-rc.2", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.6-rc.2", path = "../sn_peers_acquisition" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn-node-manager = { version = "0.11.2-rc.3", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.6-rc.3", path = "../sn_peers_acquisition" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.4.2-rc.2", path = "../sn_service_management" } +sn_service_management = { version = "0.4.2-rc.3", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index 0db6470d15..25eb9d78ce 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -15,4 +15,4 @@ release-year: 2024 release-month: 10 release-cycle: 4 -release-cycle-counter: 4 +release-cycle-counter: 5 diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 8819df1452..23917c3774 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.18-rc.2" +version = "0.1.18-rc.3" build = "build.rs" include = ["Cargo.toml", "src/**/*", "build.rs"] diff --git a/sn_build_info/src/release_info.rs b/sn_build_info/src/release_info.rs index 15237cd119..c5d9ad7bfc 100644 --- a/sn_build_info/src/release_info.rs +++ b/sn_build_info/src/release_info.rs @@ -1,4 +1,4 @@ pub const RELEASE_YEAR: &str = "2024"; pub const RELEASE_MONTH: &str = "10"; pub const RELEASE_CYCLE: &str = "4"; -pub const RELEASE_CYCLE_COUNTER: &str = "4"; +pub const RELEASE_CYCLE_COUNTER: &str = "5"; diff --git a/sn_evm/Cargo.toml b/sn_evm/Cargo.toml index 81d9dd01fa..2982d07dbc 100644 --- a/sn_evm/Cargo.toml +++ b/sn_evm/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_evm" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.2" +version = "0.1.3-rc.3" [features] test-utils = [] @@ -17,7 +17,7 @@ external-signer = ["evmlib/external-signer"] [dependencies] custom_debug = "~0.6.1" -evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } hex = "~0.4.3" lazy_static = "~1.4.0" libp2p = { version = "0.53", features = ["identify", "kad"] } diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 1277a6d0bc..64c98d05f5 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.39-rc.2" +version = "0.2.39-rc.3" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index d0f83aa760..55d0bb754f 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.19-rc.2" +version = "0.1.19-rc.3" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index df71cf51a3..14aa5ff528 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.2-rc.2" +version = "0.19.2-rc.3" [features] default = [] @@ -54,11 +54,11 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index a9db79409c..4f52622894 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.112.3-rc.2" +version = "0.112.3-rc.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -52,15 +52,15 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } sysinfo = { version = "0.30.8", default-features = false } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ @@ -83,16 +83,16 @@ strum = { version = "0.26.2", features = ["derive"] } color-eyre = "0.6.2" [dev-dependencies] -evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } -autonomi = { path = "../autonomi", version = "0.2.3-rc.2", features = ["registers"] } +evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } +autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = ["registers"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features = [ +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index d07b98d781..1e76bec856 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.11.2-rc.2" +version = "0.11.2-rc.3" [[bin]] name = "safenode-manager" @@ -46,14 +46,14 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } sn-releases = "0.2.6" -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index ceec7270a7..24c33d977d 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.34-rc.2" +version = "0.6.34-rc.3" [[bin]] name = "safenode_rpc_client" @@ -26,13 +26,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version = "0.54.1", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } -sn_node = { path = "../sn_node", version = "0.112.3-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_node = { path = "../sn_node", version = "0.112.3-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 88bdb8d53b..8a396e4557 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.6-rc.2" +version = "0.5.6-rc.3" [features] local = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version = "0.54.1", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false } tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index ddf615ae1c..3c9bdcc286 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.14-rc.2" +version = "0.17.14-rc.3" [features] default = [] @@ -28,10 +28,10 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.2" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index 219dc83686..d51071e507 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.2" +version = "0.4.2-rc.3" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index 79510fa25b..f146ddfebc 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.2" +version = "0.4.2-rc.3" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.2", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features = [ "rpc", ] } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index 57f6de55c1..0db3b555eb 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.20.2-rc.2" +version = "0.20.2-rc.3" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index b309b5a514..64a6ff22f5 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.10-rc.2" +version = "0.4.10-rc.3" [features] local = ["sn_peers_acquisition/local"] @@ -16,9 +16,9 @@ local = ["sn_peers_acquisition/local"] bytes = { version = "1.0.1", features = ["serde"] } color-eyre = "~0.6.2" dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.2" } +evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } libp2p = { version = "0.54.1", features = ["identify", "kad"] } rand = "0.8.5" serde = { version = "1.0.133", features = ["derive"] } serde_json = "1.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index 7a9e940da2..c4d0c33c7f 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.57-rc.2" +version = "0.1.57-rc.3" [dependencies] From f4a6f84c39c77d3be9e70ccdd20b1bbbf9fdc58b Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Wed, 6 Nov 2024 11:33:03 +0000 Subject: [PATCH 21/24] docs: changelog for 2024.10.4.5 release --- CHANGELOG.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d68be75785..6187825c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 *When editing this file, please respect a line length of 100.* +## 2024-11-06 + +### Network + +#### Added + +- Remove outdated record copies that cannot be decrypted. This is used when a node is restarted. + +#### Changed + +- The node will only restart at the end of its process if it has explicitly been requested in the + RPC restart command. This removes the potential for creation of undesired new processes. +- Range search optimization to reduce resource usage. +- Trigger record_store pruning earlier. The threshold lowered from 90% to 10% to improve the disk + usage efficiency. + +#### Fixed + +- Derive node-side record encryption details from the node's keypair. This ensures data is retained + in a restart. + +### Client + +#### Changed + +- When paying for quotes through the API, the contract allowance will be set to ~infinite instead of + the specific amount needed. This is to reduce the amount of approval transactions needed for doing + quote payments. + +### Node Manager + +#### Fixed + +- The `--rewards-address` argument is retained on an upgrade + +### Launchpad + +#### Added + +- Support for upgrading nodes version +- Support for Ctrl+V on rewards address +- More error handling + +#### Changed + +- Help screen after beta +- New Ratatui version 0.29.0 + ## 2024-10-28 ## Autonomi API/CLI From 6bb3f106dfcff68a94474dd82485ada0516e058e Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Wed, 6 Nov 2024 11:38:52 +0000 Subject: [PATCH 22/24] chore(release): stable release 2024.10.4.5 ================== Crate Versions ================== autonomi: 0.2.3 autonomi-cli: 0.1.4 evmlib: 0.1.3 evm_testnet: 0.1.3 sn_build_info: 0.1.18 sn_evm: 0.1.3 sn_logging: 0.2.39 sn_metrics: 0.1.19 nat-detection: 0.2.10 sn_networking: 0.19.2 sn_node: 0.112.3 node-launchpad: 0.4.3 sn_node_manager: 0.11.2 sn_node_rpc_client: 0.6.34 sn_peers_acquisition: 0.5.6 sn_protocol: 0.17.14 sn_registers: 0.4.2 sn_service_management: 0.4.2 sn_transfers: 0.20.2 test_utils: 0.4.10 token_supplies: 0.1.57 =================== Binary Versions =================== nat-detection: 0.2.10 node-launchpad: 0.4.3 autonomi: 0.1.4 safenode: 0.112.3 safenode-manager: 0.11.2 safenode_rpc_client: 0.6.34 safenodemand: 0.11.2 --- Cargo.lock | 42 ++++++++++++++++---------------- autonomi-cli/Cargo.toml | 12 ++++----- autonomi/Cargo.toml | 18 +++++++------- evm_testnet/Cargo.toml | 6 ++--- evmlib/Cargo.toml | 2 +- nat-detection/Cargo.toml | 8 +++--- node-launchpad/Cargo.toml | 14 +++++------ sn_build_info/Cargo.toml | 2 +- sn_evm/Cargo.toml | 4 +-- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 12 ++++----- sn_node/Cargo.toml | 28 ++++++++++----------- sn_node_manager/Cargo.toml | 16 ++++++------ sn_node_rpc_client/Cargo.toml | 16 ++++++------ sn_peers_acquisition/Cargo.toml | 4 +-- sn_protocol/Cargo.toml | 10 ++++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++--- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 6 ++--- token_supplies/Cargo.toml | 2 +- 22 files changed, 109 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a80ec8a35..c68d6a0a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1094,7 +1094,7 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "autonomi" -version = "0.2.3-rc.3" +version = "0.2.3" dependencies = [ "alloy", "bip39", @@ -1141,7 +1141,7 @@ dependencies = [ [[package]] name = "autonomi-cli" -version = "0.1.4-rc.3" +version = "0.1.4" dependencies = [ "autonomi", "clap", @@ -2881,7 +2881,7 @@ dependencies = [ [[package]] name = "evm_testnet" -version = "0.1.3-rc.3" +version = "0.1.3" dependencies = [ "clap", "dirs-next", @@ -2892,7 +2892,7 @@ dependencies = [ [[package]] name = "evmlib" -version = "0.1.3-rc.3" +version = "0.1.3" dependencies = [ "alloy", "dirs-next", @@ -5774,7 +5774,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.10-rc.3" +version = "0.2.10" dependencies = [ "clap", "clap-verbosity-flag", @@ -5891,7 +5891,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.4.3-rc.3" +version = "0.4.3" dependencies = [ "arboard", "atty", @@ -8410,7 +8410,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.11.2-rc.3" +version = "0.11.2" dependencies = [ "assert_cmd", "assert_fs", @@ -8486,7 +8486,7 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.18-rc.3" +version = "0.1.18" dependencies = [ "chrono", "tracing", @@ -8528,7 +8528,7 @@ dependencies = [ [[package]] name = "sn_evm" -version = "0.1.3-rc.3" +version = "0.1.3" dependencies = [ "custom_debug", "evmlib", @@ -8551,7 +8551,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.39-rc.3" +version = "0.2.39" dependencies = [ "chrono", "color-eyre", @@ -8576,7 +8576,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.19-rc.3" +version = "0.1.19" dependencies = [ "clap", "color-eyre", @@ -8590,7 +8590,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.19.2-rc.3" +version = "0.19.2" dependencies = [ "aes-gcm-siv", "assert_fs", @@ -8638,7 +8638,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.112.3-rc.3" +version = "0.112.3" dependencies = [ "assert_fs", "async-trait", @@ -8695,7 +8695,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.34-rc.3" +version = "0.6.34" dependencies = [ "assert_fs", "async-trait", @@ -8722,7 +8722,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.6-rc.3" +version = "0.5.6" dependencies = [ "clap", "lazy_static", @@ -8738,7 +8738,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.14-rc.3" +version = "0.17.14" dependencies = [ "blsttc", "bytes", @@ -8768,7 +8768,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.4.2-rc.3" +version = "0.4.2" dependencies = [ "blsttc", "crdts", @@ -8785,7 +8785,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.4.2-rc.3" +version = "0.4.2" dependencies = [ "async-trait", "dirs-next", @@ -8811,7 +8811,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.20.2-rc.3" +version = "0.20.2" dependencies = [ "assert_fs", "blsttc", @@ -9155,7 +9155,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.10-rc.3" +version = "0.4.10" dependencies = [ "bytes", "color-eyre", @@ -9310,7 +9310,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.57-rc.3" +version = "0.1.57" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/autonomi-cli/Cargo.toml b/autonomi-cli/Cargo.toml index 2976882b0d..83d1ffd99b 100644 --- a/autonomi-cli/Cargo.toml +++ b/autonomi-cli/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] name = "autonomi-cli" description = "Autonomi CLI" license = "GPL-3.0" -version = "0.1.4-rc.3" +version = "0.1.4" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -24,7 +24,7 @@ name = "files" harness = false [dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = [ +autonomi = { path = "../autonomi", version = "0.2.3", features = [ "data", "fs", "vault", @@ -50,9 +50,9 @@ tokio = { version = "1.32.0", features = [ "fs", ] } tracing = { version = "~0.1.26" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_logging = { path = "../sn_logging", version = "0.2.39" } walkdir = "2.5.0" serde_json = "1.0.132" serde = "1.0.210" @@ -60,7 +60,7 @@ hex = "0.4.3" ring = "0.17.8" [dev-dependencies] -autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = [ +autonomi = { path = "../autonomi", version = "0.2.3", features = [ "data", "fs", ] } diff --git a/autonomi/Cargo.toml b/autonomi/Cargo.toml index cbb60441a0..102810b9e2 100644 --- a/autonomi/Cargo.toml +++ b/autonomi/Cargo.toml @@ -3,7 +3,7 @@ authors = ["MaidSafe Developers "] description = "Autonomi client API" name = "autonomi" license = "GPL-3.0" -version = "0.2.3-rc.3" +version = "0.2.3" edition = "2021" homepage = "https://maidsafe.net" readme = "README.md" @@ -38,11 +38,11 @@ rand = "0.8.5" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } -sn_protocol = { version = "0.17.14-rc.3", path = "../sn_protocol" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.19.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } +sn_protocol = { version = "0.17.14", path = "../sn_protocol" } +sn_registers = { path = "../sn_registers", version = "0.4.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } thiserror = "1.0.23" tokio = { version = "1.35.0", features = ["sync"] } tracing = { version = "~0.1.26" } @@ -60,8 +60,8 @@ blstrs = "0.7.1" alloy = { version = "0.5.3", default-features = false, features = ["std", "reqwest-rustls-tls", "provider-anvil-node", "sol-types", "json", "signers", "contract", "signer-local", "network"] } eyre = "0.6.5" sha2 = "0.10.6" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.39" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } # Do not specify the version field. Release process expects even the local dev deps to be published. # Removing the version field is a workaround. test_utils = { path = "../test_utils" } @@ -71,7 +71,7 @@ wasm-bindgen-test = "0.3.43" [target.'cfg(target_arch = "wasm32")'.dependencies] console_error_panic_hook = "0.1.7" -evmlib = { path = "../evmlib", version = "0.1.3-rc.3", features = ["wasm-bindgen"] } +evmlib = { path = "../evmlib", version = "0.1.3", features = ["wasm-bindgen"] } # See https://github.com/sebcrozet/instant/blob/7bd13f51f5c930239fddc0476a837870fb239ed7/README.md#using-instant-for-a-wasm-platform-where-performancenow-is-not-available instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] } js-sys = "0.3.70" diff --git a/evm_testnet/Cargo.toml b/evm_testnet/Cargo.toml index 777e4ce10f..fb93f3d35e 100644 --- a/evm_testnet/Cargo.toml +++ b/evm_testnet/Cargo.toml @@ -6,13 +6,13 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evm_testnet" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.3" +version = "0.1.3" [dependencies] clap = { version = "4.5", features = ["derive"] } dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +evmlib = { path = "../evmlib", version = "0.1.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } tokio = { version = "1.40", features = ["rt-multi-thread", "signal"] } [lints] diff --git a/evmlib/Cargo.toml b/evmlib/Cargo.toml index 5a24fba1f6..a062cfe621 100644 --- a/evmlib/Cargo.toml +++ b/evmlib/Cargo.toml @@ -6,7 +6,7 @@ homepage = "https://maidsafe.net" license = "GPL-3.0" name = "evmlib" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.3" +version = "0.1.3" [features] wasm-bindgen = ["alloy/wasm-bindgen"] diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 5282b68d82..e24ea7cc11 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.10-rc.3" +version = "0.2.10" [[bin]] name = "nat-detection" @@ -31,9 +31,9 @@ libp2p = { version = "0.54.1", features = [ "macros", "upnp", ] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_networking = { path = "../sn_networking", version = "0.19.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index f9a338fb19..73cdcffb38 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.4.3-rc.3" +version = "0.4.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -51,13 +51,13 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } -sn-node-manager = { version = "0.11.2-rc.3", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.6-rc.3", path = "../sn_peers_acquisition" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } +sn-node-manager = { version = "0.11.2", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.6", path = "../sn_peers_acquisition" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.4.2-rc.3", path = "../sn_service_management" } +sn_service_management = { version = "0.4.2", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 23917c3774..ec284f3455 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.18-rc.3" +version = "0.1.18" build = "build.rs" include = ["Cargo.toml", "src/**/*", "build.rs"] diff --git a/sn_evm/Cargo.toml b/sn_evm/Cargo.toml index 2982d07dbc..c2ad676e70 100644 --- a/sn_evm/Cargo.toml +++ b/sn_evm/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_evm" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.3-rc.3" +version = "0.1.3" [features] test-utils = [] @@ -17,7 +17,7 @@ external-signer = ["evmlib/external-signer"] [dependencies] custom_debug = "~0.6.1" -evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } +evmlib = { path = "../evmlib", version = "0.1.3" } hex = "~0.4.3" lazy_static = "~1.4.0" libp2p = { version = "0.53", features = ["identify", "kad"] } diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 64c98d05f5..497102c7e7 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.39-rc.3" +version = "0.2.39" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index 55d0bb754f..5533129d28 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.19-rc.3" +version = "0.1.19" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index 14aa5ff528..9d6a39e75a 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.2-rc.3" +version = "0.19.2" [features] default = [] @@ -54,11 +54,11 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2" } +sn_registers = { path = "../sn_registers", version = "0.4.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index 4f52622894..61cbebe5af 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.112.3-rc.3" +version = "0.112.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -52,15 +52,15 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.30.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } -sn_networking = { path = "../sn_networking", version = "0.19.2-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } +sn_logging = { path = "../sn_logging", version = "0.2.39" } +sn_networking = { path = "../sn_networking", version = "0.19.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14" } +sn_registers = { path = "../sn_registers", version = "0.4.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } sysinfo = { version = "0.30.8", default-features = false } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ @@ -83,16 +83,16 @@ strum = { version = "0.26.2", features = ["derive"] } color-eyre = "0.6.2" [dev-dependencies] -evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } -autonomi = { path = "../autonomi", version = "0.2.3-rc.3", features = ["registers"] } +evmlib = { path = "../evmlib", version = "0.1.3" } +autonomi = { path = "../autonomi", version = "0.2.3", features = ["registers"] } reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features = [ +sn_protocol = { path = "../sn_protocol", version = "0.17.14", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.20.2", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 1e76bec856..c729b59edc 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.11.2-rc.3" +version = "0.11.2" [[bin]] name = "safenode-manager" @@ -46,14 +46,14 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3" } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_logging = { path = "../sn_logging", version = "0.2.39" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14" } +sn_service_management = { path = "../sn_service_management", version = "0.4.2" } sn-releases = "0.2.6" -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index 24c33d977d..126852342c 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.34-rc.3" +version = "0.6.34" [[bin]] name = "safenode_rpc_client" @@ -26,13 +26,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version = "0.54.1", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } -sn_node = { path = "../sn_node", version = "0.112.3-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.4.2-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_logging = { path = "../sn_logging", version = "0.2.39" } +sn_node = { path = "../sn_node", version = "0.112.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.4.2" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 8a396e4557..9171db793a 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.6-rc.3" +version = "0.5.6" [features] local = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version = "0.54.1", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.14", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false } tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index 3c9bdcc286..58f2c45459 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.14-rc.3" +version = "0.17.14" [features] default = [] @@ -28,10 +28,10 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.18-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.20.2-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.4.2-rc.3" } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.18" } +sn_transfers = { path = "../sn_transfers", version = "0.20.2" } +sn_registers = { path = "../sn_registers", version = "0.4.2" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index d51071e507..35e9135c3c 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.3" +version = "0.4.2" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index f146ddfebc..27be8a6715 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2-rc.3" +version = "0.4.2" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.39-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.14-rc.3", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.39" } +sn_protocol = { path = "../sn_protocol", version = "0.17.14", features = [ "rpc", ] } -sn_evm = { path = "../sn_evm", version = "0.1.3-rc.3" } +sn_evm = { path = "../sn_evm", version = "0.1.3" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index 0db3b555eb..0418a54671 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.20.2-rc.3" +version = "0.20.2" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 64a6ff22f5..d3e1f9117b 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.10-rc.3" +version = "0.4.10" [features] local = ["sn_peers_acquisition/local"] @@ -16,9 +16,9 @@ local = ["sn_peers_acquisition/local"] bytes = { version = "1.0.1", features = ["serde"] } color-eyre = "~0.6.2" dirs-next = "~2.0.0" -evmlib = { path = "../evmlib", version = "0.1.3-rc.3" } +evmlib = { path = "../evmlib", version = "0.1.3" } libp2p = { version = "0.54.1", features = ["identify", "kad"] } rand = "0.8.5" serde = { version = "1.0.133", features = ["derive"] } serde_json = "1.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.6" } diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index c4d0c33c7f..14ad221eea 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.57-rc.3" +version = "0.1.57" [dependencies] From 7219f8d17da2c83a2b65045da6686b6524f4ba41 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 6 Nov 2024 13:37:39 +0100 Subject: [PATCH 23/24] fix(launchpad): adding fixed interval when updating --- node-launchpad/src/components/status.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 497198c7f7..e4dea1afb6 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -657,7 +657,7 @@ impl Component for Status<'_> { do_not_start: true, custom_bin_path: None, force: false, - fixed_interval: None, + fixed_interval: Some(300_000), // 5 mins in millis peer_ids, provided_env_variables: None, service_names, From 930cb0c90db4a80d43dacbafe6de783de73a7914 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Wed, 6 Nov 2024 12:44:12 +0000 Subject: [PATCH 24/24] docs: update changelog for last minute addition --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6187825c86..e97ba34403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for upgrading nodes version - Support for Ctrl+V on rewards address - More error handling +- Use 5 minute interval between upgrades #### Changed