From c028fbd9d24d0cc759992e1e8004e0fe958cb58f Mon Sep 17 00:00:00 2001 From: Maciej Kot Date: Mon, 15 Jan 2024 13:01:42 +0900 Subject: [PATCH] Duplicate check for send --- cycles-ledger/src/storage.rs | 13 ++++---- cycles-ledger/tests/tests.rs | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/cycles-ledger/src/storage.rs b/cycles-ledger/src/storage.rs index 8d481a8..a5ba311 100644 --- a/cycles-ledger/src/storage.rs +++ b/cycles-ledger/src/storage.rs @@ -1466,6 +1466,13 @@ pub async fn send( return Err(InsufficientFunds { balance: balance_of(&from).into() }); }; + let transaction = Transaction { + operation: Operation::Burn { from, amount }, + created_at_time, + memo: Some(encode_send_memo(&to)), + }; + check_duplicate(&transaction)?; + // check that the `from` account has enough funds read_state(|state| state.check_debit_from_account(&from, amount_with_fee)).map_err( |balance| InsufficientFunds { @@ -1485,12 +1492,6 @@ pub async fn send( // 1. burn cycles + fee - let transaction = Transaction { - operation: Operation::Burn { from, amount }, - created_at_time, - memo: Some(encode_send_memo(&to)), - }; - let block_index = process_block(transaction.clone(), now, Some(config::FEE))?; if let Err(err) = mutate_state(|state| state.debit(&from, amount_with_fee)) { diff --git a/cycles-ledger/tests/tests.rs b/cycles-ledger/tests/tests.rs index 4d0e430..40d8a54 100644 --- a/cycles-ledger/tests/tests.rs +++ b/cycles-ledger/tests/tests.rs @@ -318,6 +318,70 @@ fn test_send_flow() { assert_eq!(total_supply(env, ledger_id), expected_total_supply); } +#[test] +fn test_send_duplicate() { + let env = &new_state_machine(); + let ledger_id = install_ledger(env); + let depositor_id = install_depositor(env, ledger_id); + let user_main_account = Account { + owner: Principal::from_slice(&[1]), + subaccount: None, + }; + let send_receiver = env.create_canister(None); + + // make deposits to the user and check the result + let deposit_res = deposit(env, depositor_id, user_main_account, 1_000_000_000); + assert_eq!(deposit_res.block_index, 0); + assert_eq!(deposit_res.balance, 1_000_000_000); + + let now = env + .time() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_nanos() as u64; + // send cycles from main account + let send_receiver_balance = env.cycle_balance(send_receiver); + let send_amount = 900_000_000_u128; + let send_idx = send( + env, + ledger_id, + user_main_account, + SendArgs { + from_subaccount: None, + to: send_receiver, + created_at_time: Some(now), + amount: Nat::from(send_amount), + }, + ) + .unwrap(); + assert_eq!( + send_receiver_balance + send_amount, + env.cycle_balance(send_receiver) + ); + assert_eq!( + balance_of(env, ledger_id, user_main_account), + 1_000_000_000 - send_amount - FEE + ); + + assert_eq!( + SendError::Duplicate { + duplicate_of: send_idx + }, + send( + env, + ledger_id, + user_main_account, + SendArgs { + from_subaccount: None, + to: send_receiver, + created_at_time: Some(now), + amount: Nat::from(send_amount), + }, + ) + .unwrap_err() + ); +} + #[test] fn test_send_fails() { let env = &new_state_machine();