Skip to content

Commit

Permalink
test(ci): isolate nodes rewards test run to prevent from unrelated re…
Browse files Browse the repository at this point in the history
…wards
  • Loading branch information
bochaco committed Sep 4, 2023
1 parent 8faf662 commit d099105
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 90 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ jobs:
SN_LOG: "all"
timeout-minutes: 25

- name: execute the nodes rewards tests
run: cargo test --release -p sn_node --features="local-discovery" --test nodes_rewards -- --nocapture
env:
SN_LOG: "all"
timeout-minutes: 25

- name: Stop the local network and upload logs
if: always()
uses: maidsafe/sn-local-testnet-action@main
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ jobs:
env:
SN_LOG: "all"
timeout-minutes: 10

- name: execute the nodes rewards tests
run: cargo test --release -p sn_node --features="local-discovery" --test nodes_rewards -- --nocapture
env:
SN_LOG: "all"
timeout-minutes: 25

- name: Stop the local network and upload logs
if: always()
Expand Down
30 changes: 29 additions & 1 deletion sn_node/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@ pub mod safenode_proto {
}

use safenode_proto::{safe_node_client::SafeNodeClient, NodeInfoRequest, RestartRequest};
use sn_client::{load_faucet_wallet_from_genesis_wallet, send, Client};
use self_encryption::MIN_ENCRYPTABLE_BYTES;
use sn_client::{load_faucet_wallet_from_genesis_wallet, send, Client, Files};
use sn_peers_acquisition::parse_peer_addr;
use sn_protocol::storage::{Chunk, ChunkAddress};
use sn_transfers::wallet::LocalWallet;

use bytes::Bytes;
use eyre::{eyre, Result};
use lazy_static::lazy_static;
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use sn_dbc::Token;
use sn_logging::{LogFormat, LogOutputDest};
use std::{net::SocketAddr, path::Path, sync::Once};
Expand Down Expand Up @@ -107,6 +114,27 @@ pub async fn get_client_and_wallet(root_dir: &Path, amount: u64) -> Result<(Clie
Ok((client, local_wallet))
}

pub fn random_content(client: &Client) -> Result<(Files, Bytes, ChunkAddress, Vec<Chunk>)> {
let mut rng = rand::thread_rng();

let random_len = rng.gen_range(MIN_ENCRYPTABLE_BYTES..1024 * MIN_ENCRYPTABLE_BYTES);
let random_length_content: Vec<u8> =
<Standard as Distribution<u8>>::sample_iter(Standard, &mut rng)
.take(random_len)
.collect();

let files_api = Files::new(client.clone());
let content_bytes = Bytes::from(random_length_content);
let (file_addr, chunks) = files_api.chunk_bytes(content_bytes.clone())?;

Ok((
files_api,
content_bytes,
ChunkAddress::new(file_addr),
chunks,
))
}

pub async fn node_restart(addr: SocketAddr) -> Result<()> {
let endpoint = format!("https://{addr}");
let mut client = SafeNodeClient::connect(endpoint).await?;
Expand Down
76 changes: 76 additions & 0 deletions sn_node/tests/nodes_rewards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2023 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.

mod common;

use common::{get_client_and_wallet, random_content};

use sn_client::WalletClient;
use sn_dbc::Token;
use sn_transfers::wallet::LocalWallet;

use assert_fs::TempDir;
use eyre::{eyre, Result};
use tokio::time::{sleep, Duration};

#[tokio::test]
async fn nodes_rewards_for_storing_chunks() -> Result<()> {
let paying_wallet_balance = 10_000_000_000_333;
let paying_wallet_dir = TempDir::new()?;

let (client, paying_wallet) =
get_client_and_wallet(paying_wallet_dir.path(), paying_wallet_balance).await?;
let mut wallet_client = WalletClient::new(client.clone(), paying_wallet);

let (files_api, content_bytes, _content_addr, chunks) = random_content(&client)?;

println!("Paying for {} random addresses...", chunks.len());

let cost = wallet_client
.pay_for_storage(chunks.iter().map(|c| c.network_address()), true)
.await?;

let prev_rewards_balance = current_rewards_balance()?;

files_api
.upload_with_payments(content_bytes, &wallet_client, true)
.await?;

// sleep for 1 second to allow nodes to process and store the payment
sleep(Duration::from_secs(1)).await;

let new_rewards_balance = current_rewards_balance()?;

let expected_rewards_balance = prev_rewards_balance
.checked_add(cost)
.ok_or_else(|| eyre!("Failed to sum up rewards balance"))?;

assert_eq!(expected_rewards_balance, new_rewards_balance);

Ok(())
}

// Helper which reads all nodes local wallets returning the total balance
fn current_rewards_balance() -> Result<Token> {
let mut total_rewards = Token::zero();
let node_dir_path = dirs_next::data_dir()
.ok_or_else(|| eyre!("Failed to obtain data directory path"))?
.join("safe")
.join("node");

for entry in std::fs::read_dir(node_dir_path)? {
let path = entry?.path();
let wallet = LocalWallet::try_load_from(&path)?;
let balance = wallet.balance();
total_rewards = total_rewards
.checked_add(balance)
.ok_or_else(|| eyre!("Faied to sum up rewards balance"))?;
}

Ok(total_rewards)
}
94 changes: 5 additions & 89 deletions sn_node/tests/storage_payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,19 @@ mod common;

use std::collections::BTreeMap;

use common::{get_client_and_wallet, init_logging};
use common::{get_client_and_wallet, init_logging, random_content};

use self_encryption::MIN_ENCRYPTABLE_BYTES;
use sn_client::{Client, Error as ClientError, Files, WalletClient};
use sn_client::{Error as ClientError, WalletClient};
use sn_dbc::{PublicAddress, Token};
use sn_networking::Error as NetworkError;
use sn_protocol::storage::{Chunk, ChunkAddress};
use sn_transfers::wallet::LocalWallet;
use sn_protocol::storage::ChunkAddress;

use assert_fs::TempDir;
use bytes::Bytes;
use eyre::{eyre, Result};
use rand::{
distributions::{Distribution, Standard},
Rng,
};
use eyre::Result;
use rand::Rng;
use tokio::time::{sleep, Duration};
use xor_name::XorName;

fn random_content(client: &Client) -> Result<(Files, Bytes, ChunkAddress, Vec<Chunk>)> {
let mut rng = rand::thread_rng();

let random_len = rng.gen_range(MIN_ENCRYPTABLE_BYTES..1024 * MIN_ENCRYPTABLE_BYTES);
let random_length_content: Vec<u8> =
<Standard as Distribution<u8>>::sample_iter(Standard, &mut rng)
.take(random_len)
.collect();

let files_api = Files::new(client.clone());
let content_bytes = Bytes::from(random_length_content);
let (file_addr, chunks) = files_api.chunk_bytes(content_bytes.clone())?;

Ok((
files_api,
content_bytes,
ChunkAddress::new(file_addr),
chunks,
))
}

#[tokio::test(flavor = "multi_thread")]
async fn storage_payment_succeeds() -> Result<()> {
init_logging();
Expand Down Expand Up @@ -264,60 +237,3 @@ async fn storage_payment_chunk_upload_fails() -> Result<()> {

Ok(())
}

#[tokio::test]
async fn storage_payment_chunk_nodes_rewarded() -> Result<()> {
let paying_wallet_balance = 10_000_000_000_333;
let paying_wallet_dir = TempDir::new()?;

let (client, paying_wallet) =
get_client_and_wallet(paying_wallet_dir.path(), paying_wallet_balance).await?;
let mut wallet_client = WalletClient::new(client.clone(), paying_wallet);

let (files_api, content_bytes, _content_addr, chunks) = random_content(&client)?;

println!("Paying for {} random addresses...", chunks.len());

let cost = wallet_client
.pay_for_storage(chunks.iter().map(|c| c.network_address()), true)
.await?;

let prev_rewards_balance = current_rewards_balance()?;

files_api
.upload_with_payments(content_bytes, &wallet_client, true)
.await?;

// sleep for 1 second to allow nodes to process and store the payment
sleep(Duration::from_secs(1)).await;

let new_rewards_balance = current_rewards_balance()?;

let expected_rewards_balance = prev_rewards_balance
.checked_add(cost)
.ok_or_else(|| eyre!("Failed to sum up rewards balance"))?;

assert_eq!(expected_rewards_balance, new_rewards_balance);

Ok(())
}

// Helper which reads all nodes local wallets returning the total balance
fn current_rewards_balance() -> Result<Token> {
let mut total_rewards = Token::zero();
let node_dir_path = dirs_next::data_dir()
.ok_or_else(|| eyre!("Failed to obtain data directory path"))?
.join("safe")
.join("node");

for entry in std::fs::read_dir(node_dir_path)? {
let path = entry?.path();
let wallet = LocalWallet::try_load_from(&path)?;
let balance = wallet.balance();
total_rewards = total_rewards
.checked_add(balance)
.ok_or_else(|| eyre!("Faied to sum up rewards balance"))?;
}

Ok(total_rewards)
}

0 comments on commit d099105

Please sign in to comment.