txs_verification.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! Test for transaction verification correctness between Alice and Bob.
  19. //!
  20. //! We first mint Alice some tokens, and then she send some to Bob
  21. //! a couple of times, including some double spending transactions.
  22. //!
  23. //! With this test, we want to confirm the transactions execution works
  24. //! between multiple parties, with detection of erroneous transactions.
  25. use darkfi::Result;
  26. use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
  27. use log::info;
  28. #[test]
  29. fn txs_verification() -> Result<()> {
  30. smol::block_on(async {
  31. init_logger();
  32. // Holders this test will use
  33. const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
  34. // Some numbers we want to assert
  35. const ALICE_INITIAL: u64 = 100;
  36. // Alice = 50 ALICE
  37. // Bob = 50 ALICE
  38. const ALICE_SEND: u64 = ALICE_INITIAL - 50;
  39. // Slot to verify against
  40. let current_slot = 0;
  41. // Initialize harness
  42. let mut th = TestHarness::new(&["money".to_string()]).await?;
  43. let mut alice_owncoins = vec![];
  44. let mut bob_owncoins = vec![];
  45. info!(target: "money", "[Alice] ================================");
  46. info!(target: "money", "[Alice] Building token mint tx for Alice");
  47. info!(target: "money", "[Alice] ================================");
  48. let (token_mint_tx, token_mint_params) =
  49. th.token_mint(ALICE_INITIAL, &Holder::Alice, &Holder::Alice, None, None)?;
  50. for holder in &HOLDERS {
  51. info!(target: "money", "[{holder:?}] =============================");
  52. info!(target: "money", "[{holder:?}] Executing Alice token mint tx");
  53. info!(target: "money", "[{holder:?}] =============================");
  54. th.execute_token_mint_tx(holder, &token_mint_tx, &token_mint_params, current_slot)
  55. .await?;
  56. }
  57. th.assert_trees(&HOLDERS);
  58. // Alice gathers her new owncoin
  59. let alice_oc = th.gather_owncoin(&Holder::Alice, &token_mint_params.output, None)?;
  60. let alice_token_id = alice_oc.note.token_id;
  61. alice_owncoins.push(alice_oc);
  62. // Now Alice can send a little bit of funds to Bob.
  63. // We can duplicate this transaction to simulate double spending.
  64. let duplicates = 3; // Change this number to >1 to double spend
  65. let mut transactions = vec![];
  66. let mut txs_params = vec![];
  67. for i in 0..duplicates {
  68. info!(target: "money", "[Alice] ======================================================");
  69. info!(target: "money", "[Alice] Building Money::Transfer params for payment {i} to Bob");
  70. info!(target: "money", "[Alice] ======================================================");
  71. let (transfer_tx, transfer_params, spent_coins) = th.transfer(
  72. ALICE_SEND,
  73. &Holder::Alice,
  74. &Holder::Bob,
  75. &alice_owncoins,
  76. alice_token_id,
  77. )?;
  78. // Validating transfer params
  79. assert!(transfer_params.inputs.len() == 1);
  80. assert!(transfer_params.outputs.len() == 2);
  81. assert!(spent_coins.len() == 1);
  82. // Now we simulate nodes verification, as transactions come one by one.
  83. // Validation should pass, even when we are trying to double spent.
  84. for holder in &HOLDERS {
  85. info!(target: "money", "[{holder:?}] ==================================");
  86. info!(target: "money", "[{holder:?}] Verifying Alice2Bob payment tx {i}");
  87. info!(target: "money", "[{holder:?}] ==================================");
  88. th.verify_transfer_tx(holder, &transfer_tx, current_slot).await?;
  89. }
  90. transactions.push(transfer_tx);
  91. txs_params.push(transfer_params);
  92. }
  93. alice_owncoins = vec![];
  94. assert_eq!(transactions.len(), duplicates);
  95. assert_eq!(txs_params.len(), duplicates);
  96. // Now we can try to execute the transactions sequentialy.
  97. // Each node will detect the duplicate txs and filter them out,
  98. // then only apply the first txs from the set.
  99. for holder in &HOLDERS {
  100. info!(target: "money", "[{holder:?}] ==============================");
  101. info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
  102. info!(target: "money", "[{holder:?}] ==============================");
  103. th.execute_erroneous_txs(
  104. TxAction::MoneyTransfer,
  105. holder,
  106. &transactions,
  107. current_slot,
  108. duplicates - 1,
  109. )
  110. .await?;
  111. th.execute_transfer_tx(holder, &transactions[0], &txs_params[0], current_slot, true)
  112. .await?;
  113. }
  114. th.assert_trees(&HOLDERS);
  115. // Bob should now have the new OwnCoin.
  116. let bob_oc = th.gather_owncoin(&Holder::Bob, &txs_params[0].outputs[0], None)?;
  117. bob_owncoins.push(bob_oc);
  118. // Alice should now have one OwnCoin with the change from the above transaction.
  119. let alice_oc = th.gather_owncoin(&Holder::Alice, &txs_params[0].outputs[1], None)?;
  120. alice_owncoins.push(alice_oc);
  121. assert!(alice_owncoins.len() == 1);
  122. assert!(bob_owncoins.len() == 1);
  123. // Statistics
  124. th.statistics();
  125. // Thanks for reading
  126. Ok(())
  127. })
  128. }