Skip to content

Commit

Permalink
test(node): poisoning old spend should not affect descendants
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandSherwin committed Jun 24, 2024
1 parent d666639 commit 7d2f3de
Showing 1 changed file with 119 additions and 4 deletions.
123 changes: 119 additions & 4 deletions sn_node/tests/double_spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use sn_transfers::{
get_genesis_sk, rng, DerivationIndex, HotWallet, NanoTokens, OfflineTransfer, SpendReason,
WalletError, GENESIS_CASHNOTE,
};
use tracing::info;
use std::time::Duration;
use tracing::*;

#[tokio::test]
async fn cash_note_transfer_double_spend_fail() -> Result<()> {
Expand Down Expand Up @@ -69,15 +70,16 @@ async fn cash_note_transfer_double_spend_fail() -> Result<()> {
assert!(res.is_ok());

// check the CashNotes, it should fail
info!("Verifying the transfers from first wallet...");
info!("Verifying the transfers from first wallet... Sleeping for 3 seconds.");
tokio::time::sleep(Duration::from_secs(3)).await;

let cash_notes_for_2: Vec<_> = transfer_to_2.cash_notes_for_recipient.clone();
let cash_notes_for_3: Vec<_> = transfer_to_3.cash_notes_for_recipient.clone();

let could_err1 = client.verify_cashnote(&cash_notes_for_2[0]).await;
let could_err2 = client.verify_cashnote(&cash_notes_for_3[0]).await;
info!("Verifying at least one fails : {could_err1:?} {could_err2:?}");
assert!(could_err1.is_err() || could_err2.is_err());
info!("Both should fail during GET record accumulation : {could_err1:?} {could_err2:?}");
assert!(could_err1.is_err() && could_err2.is_err());

Ok(())
}
Expand Down Expand Up @@ -152,3 +154,116 @@ async fn genesis_double_spend_fail() -> Result<()> {

Ok(())
}

#[tokio::test]
async fn poisoning_old_spend_should_not_affect_descendant() -> Result<()> {
let _log_guards = LogBuilder::init_single_threaded_tokio_test("double_spend", true);
let mut rng = rng::thread_rng();
let reason = SpendReason::default();
// create 1 wallet add money from faucet
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 to1 = wallet_1.address();

// Send from 1 -> 2
let wallet_dir_2 = TempDir::new()?;
let mut wallet_2 = get_wallet(wallet_dir_2.path());
assert_eq!(wallet_2.balance(), NanoTokens::zero());

let to2 = wallet_2.address();
let (cash_notes_1, _exclusive_access) = wallet_1.available_cash_notes()?;
let to_2_unique_key = (amount, to2, DerivationIndex::random(&mut rng));
let transfer_to_2 = OfflineTransfer::new(
cash_notes_1.clone(),
vec![to_2_unique_key],
to1,
reason.clone(),
)
.unwrap();

info!("Sending 1->2 to the network...");
client
.send_spends(transfer_to_2.all_spend_requests.iter(), false)
.await?;
// std::mem::drop(exclusive_access);

info!("Verifying the transfers from 1 -> 2 wallet...");
let cash_notes_for_2: Vec<_> = transfer_to_2.cash_notes_for_recipient.clone();
client.verify_cashnote(&cash_notes_for_2[0]).await?;
wallet_2.deposit_and_store_to_disk(&cash_notes_for_2)?; // store inside 2

// Send from 2 -> 22
let wallet_dir_22 = TempDir::new()?;
let mut wallet_22 = get_wallet(wallet_dir_22.path());
assert_eq!(wallet_22.balance(), NanoTokens::zero());

let (cash_notes_2, _exclusive_access) = wallet_2.available_cash_notes()?;
assert!(!cash_notes_2.is_empty());
let to_22_unique_key = (
wallet_2.balance(),
wallet_22.address(),
DerivationIndex::random(&mut rng),
);
let transfer_to_22 =
OfflineTransfer::new(cash_notes_2, vec![to_22_unique_key], to2, reason.clone()).unwrap();

client
.send_spends(transfer_to_22.all_spend_requests.iter(), false)
.await?;
// std::mem::drop(exclusive_access);

info!("Verifying the transfers from 2 -> 22 wallet...");
let cash_notes_for_22: Vec<_> = transfer_to_22.cash_notes_for_recipient.clone();
client.verify_cashnote(&cash_notes_for_22[0]).await?;
wallet_22.deposit_and_store_to_disk(&cash_notes_for_22)?; // store inside 22

// Try to double spend from 1 -> 3
let wallet_dir_3 = TempDir::new()?;
let wallet_3 = get_wallet(wallet_dir_3.path());
assert_eq!(wallet_3.balance(), NanoTokens::zero());

let to_3_unique_key = (
amount,
wallet_3.address(),
DerivationIndex::random(&mut rng),
);
let transfer_to_3 =
OfflineTransfer::new(cash_notes_1, vec![to_3_unique_key], to1, reason.clone()).unwrap(); // reuse the old cash notes
client
.send_spends(transfer_to_3.all_spend_requests.iter(), false)
.await?;
info!("Verifying the transfers from 1 -> 3 wallet... It should error out.");
let cash_notes_for_3: Vec<_> = transfer_to_3.cash_notes_for_recipient.clone();
assert!(client.verify_cashnote(&cash_notes_for_3[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()?;
let wallet_222 = get_wallet(wallet_dir_222.path());
assert_eq!(wallet_222.balance(), NanoTokens::zero());

let (cash_notes_22, _exclusive_access) = wallet_22.available_cash_notes()?;
assert!(!cash_notes_22.is_empty());
let to_222_unique_key = (
wallet_22.balance(),
wallet_222.address(),
DerivationIndex::random(&mut rng),
);
let transfer_to_222 = OfflineTransfer::new(
cash_notes_22,
vec![to_222_unique_key],
wallet_22.address(),
reason,
)
.unwrap();
client
.send_spends(transfer_to_222.all_spend_requests.iter(), false)
.await?;
info!("Verifying the transfers from 22 -> 222 wallet...");
let cash_notes_for_222: Vec<_> = transfer_to_222.cash_notes_for_recipient.clone();
client.verify_cashnote(&cash_notes_for_222[0]).await?;

Ok(())
}

0 comments on commit 7d2f3de

Please sign in to comment.