Selaa lähdekoodia

contracts/tests: made consensus coins deterministic, major cleanup in rest

aggstam 3 vuotta sitten
vanhempi
sitoutus
73500a25b4
28 muutettua tiedostoa jossa 752 lisäystä ja 1341 poistoa
  1. 2 2
      bin/darkfid2/src/tests/harness.rs
  2. 1 4
      src/consensus/proto/protocol_tx.rs
  3. 5 6
      src/contract/consensus/src/client/proposal_v1.rs
  4. 24 126
      src/contract/consensus/tests/genesis_stake_unstake.rs
  5. 129 161
      src/contract/consensus/tests/stake_unstake.rs
  6. 0 219
      src/contract/dao/tests/harness.rs
  7. 70 224
      src/contract/dao/tests/integration.rs
  8. 43 94
      src/contract/money/tests/genesis_mint.rs
  9. 17 34
      src/contract/money/tests/integration.rs
  10. 82 148
      src/contract/money/tests/mint_pay_swap.rs
  11. 32 58
      src/contract/money/tests/txs_verification.rs
  12. 24 31
      src/contract/money/tests/verification_bench.rs
  13. 4 31
      src/contract/test-harness/src/consensus_genesis_stake.rs
  14. 45 29
      src/contract/test-harness/src/consensus_proposal.rs
  15. 48 8
      src/contract/test-harness/src/consensus_stake.rs
  16. 40 8
      src/contract/test-harness/src/consensus_unstake.rs
  17. 47 27
      src/contract/test-harness/src/consensus_unstake_request.rs
  18. 7 7
      src/contract/test-harness/src/dao_exec.rs
  19. 2 2
      src/contract/test-harness/src/dao_mint.rs
  20. 7 7
      src/contract/test-harness/src/dao_propose.rs
  21. 9 9
      src/contract/test-harness/src/dao_vote.rs
  22. 41 13
      src/contract/test-harness/src/lib.rs
  23. 37 6
      src/contract/test-harness/src/money_airdrop.rs
  24. 4 31
      src/contract/test-harness/src/money_genesis_mint.rs
  25. 8 8
      src/contract/test-harness/src/money_otc_swap.rs
  26. 10 10
      src/contract/test-harness/src/money_token.rs
  27. 10 37
      src/contract/test-harness/src/money_transfer.rs
  28. 4 1
      src/validator/proto/protocol_tx.rs

+ 2 - 2
bin/darkfid2/src/tests/harness.rs

@@ -50,8 +50,8 @@ impl Harness {
     pub async fn new(config: HarnessConfig) -> Result<Self> {
         // Use test harness to generate genesis transactions
         let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
-        let (genesis_stake_tx, _) = th.genesis_stake(Holder::Alice, config.alice_initial)?;
-        let (genesis_mint_tx, _) = th.genesis_mint(Holder::Bob, config.bob_initial)?;
+        let (genesis_stake_tx, _) = th.genesis_stake(&Holder::Alice, config.alice_initial)?;
+        let (genesis_mint_tx, _) = th.genesis_mint(&Holder::Bob, config.bob_initial)?;
 
         // Generate default genesis block
         let mut genesis_block = BlockInfo::default();

+ 1 - 4
src/consensus/proto/protocol_tx.rs

@@ -24,9 +24,8 @@ use url::Url;
 
 use crate::{
     consensus::ValidatorStatePtr,
-    impl_p2p_message,
     net::{
-        ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
+        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
         ProtocolJobsManager, ProtocolJobsManagerPtr,
     },
     tx::Transaction,
@@ -41,8 +40,6 @@ pub struct ProtocolTx {
     channel_address: Url,
 }
 
-impl_p2p_message!(Transaction, "tx");
-
 impl ProtocolTx {
     pub async fn init(
         channel: ChannelPtr,

+ 5 - 6
src/contract/consensus/src/client/proposal_v1.rs

@@ -37,7 +37,7 @@ use darkfi_sdk::{
     },
     pasta::{group::ff::FromUniformBytes, pallas},
 };
-use log::{debug, info};
+use log::{debug, error, info};
 use rand::rngs::OsRng;
 
 use crate::{
@@ -265,12 +265,11 @@ fn create_proposal_proof(
     let value_pallas = pallas::Base::from(input.note.value);
     let shifted_target =
         slot.sigma1 * value_pallas + slot.sigma2 * value_pallas * value_pallas + HEADSTART;
-    // TODO: this check is true, while the proof can be created and is valid, when it shouldn't
-    log::error!("Y: {:?}", y);
-    log::error!("TARGET: {:?}", shifted_target);
+
     if y >= shifted_target {
-        info!("1) What");
-        //return Err(CoinIsNotSlotProducer)
+        error!("Y: {:?}", y);
+        error!("TARGET: {:?}", shifted_target);
+        return Err(CoinIsNotSlotProducer)
     }
 
     // Derive the input's nullifier

+ 24 - 126
src/contract/consensus/tests/genesis_stake_unstake.rs

@@ -27,8 +27,8 @@
 use darkfi::Result;
 use log::info;
 
-use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH, REWARD};
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
+use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH};
+use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
 
 #[async_std::test]
 async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
@@ -46,21 +46,22 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     // Initialize harness
     let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
 
-    // Now Alice can craate a genesis stake transaction to mint
+    // Now Alice can create a genesis stake transaction to mint
     // some staked coins
     info!(target: "consensus", "[Alice] =========================");
     info!(target: "consensus", "[Alice] Building genesis stake tx");
     info!(target: "consensus", "[Alice] =========================");
     let (genesis_stake_tx, genesis_stake_params) =
-        th.genesis_stake(Holder::Alice, ALICE_INITIAL)?;
+        th.genesis_stake(&Holder::Alice, ALICE_INITIAL)?;
 
     // We are going to use alice genesis mint transaction to
     // test some malicious cases.
     info!(target: "consensus", "[Malicious] ===================================");
     info!(target: "consensus", "[Malicious] Checking duplicate genesis stake tx");
     info!(target: "consensus", "[Malicious] ===================================");
-    th.execute_erroneous_genesis_stake_txs(
-        Holder::Alice,
+    th.execute_erroneous_txs(
+        TxAction::ConsensusGenesisStake,
+        &Holder::Alice,
         &vec![genesis_stake_tx.clone(), genesis_stake_tx.clone()],
         current_slot,
         1,
@@ -70,44 +71,28 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     info!(target: "consensus", "[Malicious] =============================================");
     info!(target: "consensus", "[Malicious] Checking genesis stake tx not on genesis slot");
     info!(target: "consensus", "[Malicious] =============================================");
-    th.execute_erroneous_genesis_stake_txs(
-        Holder::Alice,
+    th.execute_erroneous_txs(
+        TxAction::ConsensusGenesisStake,
+        &Holder::Alice,
         &vec![genesis_stake_tx.clone()],
         current_slot + 1,
         1,
     )
     .await?;
-    info!(target: "consensus", "[Malicious] ===========================");
-    info!(target: "consensus", "[Malicious] Malicious test cases passed");
-    info!(target: "consensus", "[Malicious] ===========================");
-
-    info!(target: "consensus", "[Faucet] ================================");
-    info!(target: "consensus", "[Faucet] Executing Alice genesis stake tx");
-    info!(target: "consensus", "[Faucet] ================================");
-    th.execute_genesis_stake_tx(
-        Holder::Faucet,
-        &genesis_stake_tx,
-        &genesis_stake_params,
-        current_slot,
-    )
-    .await?;
 
-    info!(target: "consensus", "[Alice] ================================");
-    info!(target: "consensus", "[Alice] Executing Alice genesis stake tx");
-    info!(target: "consensus", "[Alice] ================================");
-    th.execute_genesis_stake_tx(
-        Holder::Alice,
-        &genesis_stake_tx,
-        &genesis_stake_params,
-        current_slot,
-    )
-    .await?;
+    for holder in &HOLDERS {
+        info!(target: "consensus", "[{holder:?}] ================================");
+        info!(target: "consensus", "[{holder:?}] Executing Alice genesis stake tx");
+        info!(target: "consensus", "[{holder:?}] ================================");
+        th.execute_genesis_stake_tx(holder, &genesis_stake_tx, &genesis_stake_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather new staked owncoin
     let alice_staked_oc =
-        th.gather_consensus_staked_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
+        th.gather_consensus_staked_owncoin(&Holder::Alice, &genesis_stake_params.output, None)?;
 
     // Verify values match
     assert!(ALICE_INITIAL == alice_staked_oc.note.value);
@@ -120,110 +105,23 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
     // With alice's current coin value she can become the slot proposer,
     // so she creates a proposal transaction to burn her staked coin,
     // reward herself and mint the new coin.
-    info!(target: "consensus", "[Alice] ====================");
-    info!(target: "consensus", "[Alice] Building proposal tx");
-    info!(target: "consensus", "[Alice] ====================");
-    let (proposal_tx, proposal_params, _proposal_signing_secret_key, proposal_output_secret_key) =
-        th.proposal(Holder::Alice, slot, alice_staked_oc.clone()).await?;
-
-    info!(target: "consensus", "[Faucet] ===========================");
-    info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
-    info!(target: "consensus", "[Faucet] ===========================");
-    th.execute_proposal_tx(Holder::Faucet, &proposal_tx, &proposal_params, current_slot).await?;
-
-    info!(target: "consensus", "[Alice] ===========================");
-    info!(target: "consensus", "[Alice] Executing Alice proposal tx");
-    info!(target: "consensus", "[Alice] ===========================");
-    th.execute_proposal_tx(Holder::Alice, &proposal_tx, &proposal_params, current_slot).await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new staked owncoin which includes the reward
-    let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
-        Holder::Alice,
-        proposal_params.output,
-        Some(proposal_output_secret_key),
-    )?;
-
-    // Verify values match
-    assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
+    let alice_rewarded_staked_oc =
+        th.execute_proposal(&HOLDERS, &Holder::Alice, current_slot, slot, &alice_staked_oc).await?;
 
     // We progress after grace period
     current_slot += calculate_grace_period() * EPOCH_LENGTH;
     th.generate_slot(current_slot).await?;
 
     // Alice can request for her owncoin to get unstaked
-    info!(target: "consensus", "[Alice] ===========================");
-    info!(target: "consensus", "[Alice] Building unstake request tx");
-    info!(target: "consensus", "[Alice] ===========================");
-    let (
-        unstake_request_tx,
-        unstake_request_params,
-        unstake_request_output_secret_key,
-        _unstake_request_signature_secret_key,
-    ) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
-
-    info!(target: "consensus", "[Faucet] ==================================");
-    info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
-    info!(target: "consensus", "[Faucet] ==================================");
-    th.execute_unstake_request_tx(
-        Holder::Faucet,
-        &unstake_request_tx,
-        &unstake_request_params,
-        current_slot,
-    )
-    .await?;
-
-    info!(target: "consensus", "[Alice] ==================================");
-    info!(target: "consensus", "[Alice] Executing Alice unstake request tx");
-    info!(target: "consensus", "[Alice] ==================================");
-    th.execute_unstake_request_tx(
-        Holder::Alice,
-        &unstake_request_tx,
-        &unstake_request_params,
-        current_slot,
-    )
-    .await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new unstake request owncoin
-    let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
-        Holder::Alice,
-        unstake_request_params.output,
-        Some(unstake_request_output_secret_key),
-    )?;
-
-    // Verify values match
-    assert!(alice_rewarded_staked_oc.note.value == alice_unstake_request_oc.note.value);
+    let alice_unstake_request_oc = th
+        .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_rewarded_staked_oc)
+        .await?;
 
     // We progress after grace period
     current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
 
     // Now Alice can unstake her owncoin
-    info!(target: "consensus", "[Alice] ===================");
-    info!(target: "consensus", "[Alice] Building unstake tx");
-    info!(target: "consensus", "[Alice] ===================");
-    let (unstake_tx, unstake_params, _unstake_secret_key) =
-        th.unstake(Holder::Alice, alice_unstake_request_oc.clone())?;
-
-    info!(target: "consensus", "[Faucet] ==========================");
-    info!(target: "consensus", "[Faucet] Executing Alice unstake tx");
-    info!(target: "consensus", "[Faucet] ==========================");
-    th.execute_unstake_tx(Holder::Faucet, &unstake_tx, &unstake_params, current_slot).await?;
-
-    info!(target: "consensus", "[Alice] ==========================");
-    info!(target: "consensus", "[Alice] Executing Alice unstake tx");
-    info!(target: "consensus", "[Alice] ==========================");
-    th.execute_unstake_tx(Holder::Alice, &unstake_tx, &unstake_params, current_slot).await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new unstaked owncoin
-    let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, None)?;
-
-    // Verify values match
-    assert!(alice_unstake_request_oc.note.value == alice_unstaked_oc.note.value);
+    th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc).await?;
 
     // Statistics
     th.statistics();

+ 129 - 161
src/contract/consensus/tests/stake_unstake.rs

@@ -20,17 +20,23 @@
 //!
 //! We first airdrop Alice native tokes, and then she can stake,
 //! propose and unstake them a couple of times.
+//! The following malicious cases are also tested:
+//!     1. Repeat staking coin
+//!     2. Proposal before grace period
+//!     3. Unstaking before grace period
+//!     4. Repeat requesting unstaking coin
+//!     5. Repeat unstaking coin
+//!     6. Use unstaked coin in proposal
 //!
 //! With this test, we want to confirm the consensus contract state
 //! transitions work for a single party and are able to be verified.
-//!
-//! TODO: Malicious cases
 
 use darkfi::Result;
 use log::info;
 
-use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH, REWARD};
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
+use darkfi_consensus_contract::model::{calculate_grace_period, EPOCH_LENGTH};
+use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
+use darkfi_sdk::pasta::pallas;
 
 #[async_std::test]
 async fn consensus_contract_stake_unstake() -> Result<()> {
@@ -49,67 +55,12 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
 
     // Now Alice can airdrop some native tokens to herself
-    info!(target: "consensus", "[Faucet] =========================");
-    info!(target: "consensus", "[Faucet] Building Alice airdrop tx");
-    info!(target: "consensus", "[Faucet] =========================");
-    let (airdrop_tx, airdrop_params) =
-        th.airdrop_native(ALICE_AIRDROP, Holder::Alice, None, None, None, None)?;
-
-    info!(target: "consensus", "[Faucet] ==========================");
-    info!(target: "consensus", "[Faucet] Executing Alice airdrop tx");
-    info!(target: "consensus", "[Faucet] ==========================");
-    th.execute_airdrop_native_tx(Holder::Faucet, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!(target: "consensus", "[Alice] ==========================");
-    info!(target: "consensus", "[Alice] Executing Alice airdrop tx");
-    info!(target: "consensus", "[Alice] ==========================");
-    th.execute_airdrop_native_tx(Holder::Alice, &airdrop_tx, &airdrop_params, current_slot).await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new owncoin
-    let alice_oc = th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), None)?;
+    let alice_oc =
+        th.execute_airdrop(&HOLDERS, &Holder::Alice, ALICE_AIRDROP, current_slot).await?;
 
     // Now Alice can stake her owncoin
-    info!(target: "consensus", "[Alice] =================");
-    info!(target: "consensus", "[Alice] Building stake tx");
-    info!(target: "consensus", "[Alice] =================");
-    let (stake_tx, stake_params, stake_secret_key) =
-        th.stake(Holder::Alice, current_slot, alice_oc.clone()).await?;
-
-    info!(target: "consensus", "[Faucet] ========================");
-    info!(target: "consensus", "[Faucet] Executing Alice stake tx");
-    info!(target: "consensus", "[Faucet] ========================");
-    th.execute_stake_tx(Holder::Faucet, &stake_tx, &stake_params, current_slot).await?;
-
-    info!(target: "consensus", "[Alice] ========================");
-    info!(target: "consensus", "[Alice] Executing Alice stake tx");
-    info!(target: "consensus", "[Alice] ========================");
-    th.execute_stake_tx(Holder::Alice, &stake_tx, &stake_params, current_slot).await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new staked owncoin
-    let alice_staked_oc = th.gather_consensus_staked_owncoin(
-        Holder::Alice,
-        stake_params.output,
-        Some(stake_secret_key),
-    )?;
-
-    // Verify values match
-    assert!(alice_oc.note.value == alice_staked_oc.note.value);
-
-    // We progress one slot
-    current_slot += 1;
-    let slot = th.generate_slot(current_slot).await?;
-
-    // Since alice didn't wait for the grace period to pass, her proposal should fail
-    info!(target: "consensus", "[Malicious] =====================================");
-    info!(target: "consensus", "[Malicious] Checking proposal before grace period");
-    info!(target: "consensus", "[Malicious] =====================================");
-    let (proposal_tx, _, _, _) = th.proposal(Holder::Alice, slot, alice_staked_oc.clone()).await?;
-    th.execute_erroneous_proposal_txs(Holder::Alice, &vec![proposal_tx], current_slot, 1).await?;
+    let alice_staked_oc =
+        th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 86).await?;
 
     // We progress after grace period
     current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
@@ -118,138 +69,155 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
     // With alice's current coin value she can become the slot proposer,
     // so she creates a proposal transaction to burn her staked coin,
     // reward herself and mint the new coin.
-    info!(target: "consensus", "[Alice] ====================");
-    info!(target: "consensus", "[Alice] Building proposal tx");
-    info!(target: "consensus", "[Alice] ====================");
-    let (
-        proposal_tx,
-        proposal_params,
-        _proposal_signing_secret_key,
-        proposal_decryption_secret_key,
-    ) = th.proposal(Holder::Alice, slot, alice_staked_oc.clone()).await?;
-
-    info!(target: "consensus", "[Faucet] ===========================");
-    info!(target: "consensus", "[Faucet] Executing Alice proposal tx");
-    info!(target: "consensus", "[Faucet] ===========================");
-    th.execute_proposal_tx(Holder::Faucet, &proposal_tx, &proposal_params, current_slot).await?;
-
-    info!(target: "consensus", "[Alice] ===========================");
-    info!(target: "consensus", "[Alice] Executing Alice proposal tx");
-    info!(target: "consensus", "[Alice] ===========================");
-    th.execute_proposal_tx(Holder::Alice, &proposal_tx, &proposal_params, current_slot).await?;
-
-    th.assert_trees(&HOLDERS);
-
-    // Gather new staked owncoin which includes the reward
-    let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
-        Holder::Alice,
-        proposal_params.output,
-        Some(proposal_decryption_secret_key),
-    )?;
-
-    // Verify values match
-    assert!((alice_staked_oc.note.value + REWARD) == alice_rewarded_staked_oc.note.value);
+    let alice_rewarded_staked_oc =
+        th.execute_proposal(&HOLDERS, &Holder::Alice, current_slot, slot, &alice_staked_oc).await?;
 
     // We progress one slot
     current_slot += 1;
     th.generate_slot(current_slot).await?;
 
     // Alice can request for her owncoin to get unstaked
-    info!(target: "consensus", "[Alice] ===========================");
-    info!(target: "consensus", "[Alice] Building unstake request tx");
-    info!(target: "consensus", "[Alice] ===========================");
-    let (
-        unstake_request_tx,
-        unstake_request_params,
-        unstake_request_output_secret_key,
-        _unstake_request_signature_secret_key,
-    ) = th.unstake_request(Holder::Alice, current_slot, alice_rewarded_staked_oc.clone()).await?;
-
-    info!(target: "consensus", "[Faucet] ==================================");
-    info!(target: "consensus", "[Faucet] Executing Alice unstake request tx");
-    info!(target: "consensus", "[Faucet] ==================================");
-    th.execute_unstake_request_tx(
-        Holder::Faucet,
-        &unstake_request_tx,
-        &unstake_request_params,
+    let alice_unstake_request_oc = th
+        .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_rewarded_staked_oc)
+        .await?;
+
+    // We progress after grace period
+    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+
+    // Now Alice can unstake her owncoin
+    let alice_unstaked_oc = th
+        .execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
+        .await?;
+
+    // Now Alice can stake her unstaked owncoin again to try some mallicious cases
+    let alice_staked_oc =
+        th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 262).await?;
+
+    // Alice tries to stake her coin again
+    info!(target: "consensus", "[Malicious] ===========================");
+    info!(target: "consensus", "[Malicious] Checking staking coin again");
+    info!(target: "consensus", "[Malicious] ===========================");
+    let (stake_tx, _, _) =
+        th.stake(&Holder::Alice, current_slot, &alice_unstaked_oc, pallas::Base::from(262)).await?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusStake,
+        &Holder::Alice,
+        &vec![stake_tx],
         current_slot,
+        1,
     )
     .await?;
 
-    info!(target: "consensus", "[Alice] ==================================");
-    info!(target: "consensus", "[Alice] Executing Alice unstake request tx");
-    info!(target: "consensus", "[Alice] ==================================");
-    th.execute_unstake_request_tx(
-        Holder::Alice,
-        &unstake_request_tx,
-        &unstake_request_params,
+    // We progress one slot
+    current_slot += 1;
+    let slot = th.generate_slot(current_slot).await?;
+
+    // Since alice didn't wait for the grace period to pass, her proposal should fail
+    info!(target: "consensus", "[Malicious] =====================================");
+    info!(target: "consensus", "[Malicious] Checking proposal before grace period");
+    info!(target: "consensus", "[Malicious] =====================================");
+    let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusProposal,
+        &Holder::Alice,
+        &vec![proposal_tx],
         current_slot,
+        1,
     )
     .await?;
 
-    th.assert_trees(&HOLDERS);
+    // or be able to unstake the coin
+    info!(target: "consensus", "[Malicious] ======================================");
+    info!(target: "consensus", "[Malicious] Checking unstaking before grace period");
+    info!(target: "consensus", "[Malicious] ======================================");
+    let (unstake_request_tx, _, _, _) =
+        th.unstake_request(&Holder::Alice, current_slot, &alice_staked_oc).await?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusUnstakeRequest,
+        &Holder::Alice,
+        &vec![unstake_request_tx],
+        current_slot,
+        1,
+    )
+    .await?;
 
-    // Gather new unstake request owncoin
-    let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
-        Holder::Alice,
-        unstake_request_params.output,
-        Some(unstake_request_output_secret_key),
-    )?;
+    // We progress after grace period
+    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
 
-    // Verify values match
-    assert!(alice_rewarded_staked_oc.note.value == alice_unstake_request_oc.note.value);
+    // Alice can request for her owncoin to get unstaked
+    let alice_unstake_request_oc = th
+        .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_staked_oc)
+        .await?;
 
-    // Now we will test if we can reuse token in proposal or unstake it again
-    current_slot += 1;
-    let slot = th.generate_slot(current_slot).await?;
+    info!(target: "consensus", "[Malicious] =====================================");
+    info!(target: "consensus", "[Malicious] Checking request unstaking coin again");
+    info!(target: "consensus", "[Malicious] =====================================");
+    let (unstake_request_tx, _, _, _) =
+        th.unstake_request(&Holder::Alice, current_slot, &alice_staked_oc).await?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusUnstakeRequest,
+        &Holder::Alice,
+        &vec![unstake_request_tx],
+        current_slot,
+        1,
+    )
+    .await?;
 
-    info!(target: "consensus", "[Malicious] ========================================");
-    info!(target: "consensus", "[Malicious] Checking using unstaked coin in proposal");
-    info!(target: "consensus", "[Malicious] ========================================");
-    let (proposal_tx, _, _, _) =
-        th.proposal(Holder::Alice, slot, alice_unstake_request_oc.clone()).await?;
-    th.execute_erroneous_proposal_txs(Holder::Alice, &vec![proposal_tx], current_slot, 1).await?;
+    // We progress after grace period
+    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+
+    // Now Alice can unstake her owncoin
+    let alice_unstaked_oc = th
+        .execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
+        .await?;
 
     info!(target: "consensus", "[Malicious] =============================");
     info!(target: "consensus", "[Malicious] Checking unstaking coin again");
     info!(target: "consensus", "[Malicious] =============================");
-    let (unstake_request_tx, _, _, _) =
-        th.unstake_request(Holder::Alice, current_slot, alice_unstake_request_oc.clone()).await?;
-    th.execute_erroneous_unstake_request_txs(
-        Holder::Alice,
-        &vec![unstake_request_tx],
+    let (unstake_tx, _, _) = th.unstake(&Holder::Alice, &alice_unstake_request_oc)?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusUnstake,
+        &Holder::Alice,
+        &vec![unstake_tx],
         current_slot,
         1,
     )
     .await?;
 
+    // Now Alice can stake her unstaked owncoin again
+    let alice_staked_oc =
+        th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 70).await?;
+
     // We progress after grace period
     current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
 
-    // Now Alice can unstake her owncoin
-    info!(target: "consensus", "[Alice] ===================");
-    info!(target: "consensus", "[Alice] Building unstake tx");
-    info!(target: "consensus", "[Alice] ===================");
-    let (unstake_tx, unstake_params, _) =
-        th.unstake(Holder::Alice, alice_unstake_request_oc.clone())?;
-
-    info!(target: "consensus", "[Faucet] ==========================");
-    info!(target: "consensus", "[Faucet] Executing Alice unstake tx");
-    info!(target: "consensus", "[Faucet] ==========================");
-    th.execute_unstake_tx(Holder::Faucet, &unstake_tx, &unstake_params, current_slot).await?;
+    // Alice can request for her owncoin to get unstaked
+    let alice_unstake_request_oc = th
+        .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_staked_oc)
+        .await?;
 
-    info!(target: "consensus", "[Alice] ==========================");
-    info!(target: "consensus", "[Alice] Executing Alice unstake tx");
-    info!(target: "consensus", "[Alice] ==========================");
-    th.execute_unstake_tx(Holder::Alice, &unstake_tx, &unstake_params, current_slot).await?;
+    // Now we will test if we can reuse token in proposal
+    current_slot += 1;
+    let slot = th.generate_slot(current_slot).await?;
 
-    th.assert_trees(&HOLDERS);
+    info!(target: "consensus", "[Malicious] ========================================");
+    info!(target: "consensus", "[Malicious] Checking using unstaked coin in proposal");
+    info!(target: "consensus", "[Malicious] ========================================");
+    let (proposal_tx, _, _, _) = th.proposal(&Holder::Alice, slot, &alice_staked_oc).await?;
+    th.execute_erroneous_txs(
+        TxAction::ConsensusProposal,
+        &Holder::Alice,
+        &vec![proposal_tx],
+        current_slot,
+        1,
+    )
+    .await?;
 
-    // Gather new unstaked owncoin
-    let alice_unstaked_oc = th.gather_owncoin(Holder::Alice, unstake_params.output, None)?;
+    // We progress after grace period
+    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
 
-    // Verify values match
-    assert!(alice_unstake_request_oc.note.value == alice_unstaked_oc.note.value);
+    // Now Alice can unstake her owncoin
+    th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc).await?;
 
     // Statistics
     th.statistics();

+ 0 - 219
src/contract/dao/tests/harness.rs

@@ -1,219 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2023 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-use std::collections::HashMap;
-
-use darkfi::{
-    blockchain::BlockInfo,
-    runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
-    util::time::TimeKeeper,
-    validator::{Validator, ValidatorConfig, ValidatorPtr},
-    zk::{empty_witnesses, ProvingKey, ZkCircuit},
-    zkas::ZkBinary,
-    Result,
-};
-use darkfi_sdk::crypto::{
-    pasta_prelude::*, ContractId, Keypair, DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
-};
-use darkfi_serial::{deserialize, serialize};
-use log::{info, warn};
-use rand::rngs::OsRng;
-
-use darkfi_money_contract::{MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1};
-
-use darkfi_dao_contract::{
-    DAO_CONTRACT_ZKAS_DAO_EXEC_NS, DAO_CONTRACT_ZKAS_DAO_MINT_NS,
-    DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS,
-    DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS,
-};
-
-pub fn init_logger() -> Result<()> {
-    let mut cfg = simplelog::ConfigBuilder::new();
-    cfg.add_filter_ignore("sled".to_string());
-    if let Err(_) = simplelog::TermLogger::init(
-        //simplelog::LevelFilter::Info,
-        simplelog::LevelFilter::Debug,
-        //simplelog::LevelFilter::Trace,
-        cfg.build(),
-        simplelog::TerminalMode::Mixed,
-        simplelog::ColorChoice::Auto,
-    ) {
-        warn!(target: "dao", "Logger already initialized");
-    }
-
-    Ok(())
-}
-
-pub struct DaoTestHarness {
-    /// Minting all new coins
-    pub faucet_kp: Keypair,
-    /// Governance token holder 1
-    pub alice_kp: Keypair,
-    /// Governance token holder 2
-    pub bob_kp: Keypair,
-    /// Governance token holder 3
-    pub charlie_kp: Keypair,
-    /// Receiver for treasury tokens
-    pub rachel_kp: Keypair,
-    /// DAO keypair
-    pub dao_kp: Keypair,
-
-    pub alice_validator: ValidatorPtr,
-    pub money_contract_id: ContractId,
-    pub dao_contract_id: ContractId,
-    pub proving_keys: HashMap<[u8; 32], Vec<(&'static str, ProvingKey)>>,
-
-    pub money_mint_zkbin: ZkBinary,
-    pub money_mint_pk: ProvingKey,
-
-    pub money_burn_zkbin: ZkBinary,
-    pub money_burn_pk: ProvingKey,
-
-    pub dao_mint_zkbin: ZkBinary,
-    pub dao_mint_pk: ProvingKey,
-
-    pub dao_propose_burn_zkbin: ZkBinary,
-    pub dao_propose_burn_pk: ProvingKey,
-
-    pub dao_propose_main_zkbin: ZkBinary,
-    pub dao_propose_main_pk: ProvingKey,
-
-    pub dao_vote_burn_zkbin: ZkBinary,
-    pub dao_vote_burn_pk: ProvingKey,
-
-    pub dao_vote_main_zkbin: ZkBinary,
-    pub dao_vote_main_pk: ProvingKey,
-
-    pub dao_exec_zkbin: ZkBinary,
-    pub dao_exec_pk: ProvingKey,
-}
-
-impl DaoTestHarness {
-    pub async fn new() -> Result<Self> {
-        let faucet_kp = Keypair::random(&mut OsRng);
-        let alice_kp = Keypair::random(&mut OsRng);
-        let bob_kp = Keypair::random(&mut OsRng);
-        let charlie_kp = Keypair::random(&mut OsRng);
-        let rachel_kp = Keypair::random(&mut OsRng);
-        let dao_kp = Keypair::random(&mut OsRng);
-
-        let faucet_pubkeys = vec![faucet_kp.public];
-
-        let alice_sled_db = sled::Config::new().temporary(true).open()?;
-
-        // NOTE: we are not using consensus constants here so we
-        // don't get circular dependencies.
-        let genesis_block = BlockInfo::default();
-        let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0);
-        let config =
-            ValidatorConfig::new(time_keeper, genesis_block, 0, faucet_pubkeys.to_vec(), false);
-        let alice_validator = Validator::new(&alice_sled_db, config).await?;
-
-        let money_contract_id = *MONEY_CONTRACT_ID;
-        let dao_contract_id = *DAO_CONTRACT_ID;
-
-        let alice_sled = alice_validator.read().await.blockchain.sled_db.clone();
-        let money_db_handle = alice_validator.read().await.blockchain.contracts.lookup(
-            &alice_sled,
-            &money_contract_id,
-            SMART_CONTRACT_ZKAS_DB_NAME,
-        )?;
-        let dao_db_handle = alice_validator.read().await.blockchain.contracts.lookup(
-            &alice_sled,
-            &dao_contract_id,
-            SMART_CONTRACT_ZKAS_DB_NAME,
-        )?;
-
-        info!(target: "dao", "Creating zk proving keys");
-
-        macro_rules! mkpk {
-            ($ns:expr, $db_handle:expr) => {{
-                let zkas_bytes = $db_handle.get(&serialize(&$ns))?.unwrap();
-                let (zkbin, _): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes)?;
-                let zkbin = ZkBinary::decode(&zkbin)?;
-                let witnesses = empty_witnesses(&zkbin);
-                let circuit = ZkCircuit::new(witnesses, zkbin.clone());
-                (zkbin, ProvingKey::build(13, &circuit))
-            }};
-        }
-
-        let (money_mint_zkbin, money_mint_pk) =
-            mkpk!(MONEY_CONTRACT_ZKAS_MINT_NS_V1, money_db_handle);
-
-        let (money_burn_zkbin, money_burn_pk) =
-            mkpk!(MONEY_CONTRACT_ZKAS_BURN_NS_V1, money_db_handle);
-
-        let (dao_mint_zkbin, dao_mint_pk) = mkpk!(DAO_CONTRACT_ZKAS_DAO_MINT_NS, dao_db_handle);
-
-        let (dao_propose_burn_zkbin, dao_propose_burn_pk) =
-            mkpk!(DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, dao_db_handle);
-
-        let (dao_propose_main_zkbin, dao_propose_main_pk) =
-            mkpk!(DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS, dao_db_handle);
-
-        let (dao_vote_burn_zkbin, dao_vote_burn_pk) =
-            mkpk!(DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, dao_db_handle);
-
-        let (dao_vote_main_zkbin, dao_vote_main_pk) =
-            mkpk!(DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS, dao_db_handle);
-
-        let (dao_exec_zkbin, dao_exec_pk) = mkpk!(DAO_CONTRACT_ZKAS_DAO_EXEC_NS, dao_db_handle);
-
-        let mut proving_keys = HashMap::<[u8; 32], Vec<(&str, ProvingKey)>>::new();
-
-        let pks = vec![
-            (MONEY_CONTRACT_ZKAS_MINT_NS_V1, money_mint_pk.clone()),
-            (MONEY_CONTRACT_ZKAS_BURN_NS_V1, money_burn_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_MINT_NS, dao_mint_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS, dao_propose_burn_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS, dao_propose_burn_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS, dao_propose_burn_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS, dao_propose_burn_pk.clone()),
-            (DAO_CONTRACT_ZKAS_DAO_EXEC_NS, dao_propose_burn_pk.clone()),
-        ];
-        proving_keys.insert(dao_contract_id.inner().to_repr(), pks);
-
-        Ok(Self {
-            faucet_kp,
-            alice_kp,
-            bob_kp,
-            charlie_kp,
-            rachel_kp,
-            dao_kp,
-            alice_validator,
-            money_contract_id,
-            dao_contract_id,
-            proving_keys,
-            money_mint_pk,
-            money_mint_zkbin,
-            money_burn_pk,
-            money_burn_zkbin,
-            dao_mint_zkbin,
-            dao_mint_pk,
-            dao_propose_burn_zkbin,
-            dao_propose_burn_pk,
-            dao_propose_main_zkbin,
-            dao_propose_main_pk,
-            dao_vote_burn_zkbin,
-            dao_vote_burn_pk,
-            dao_vote_main_zkbin,
-            dao_vote_main_pk,
-            dao_exec_zkbin,
-            dao_exec_pk,
-        })
-    }
-}

+ 70 - 224
src/contract/dao/tests/integration.rs

@@ -79,25 +79,12 @@ async fn integration_test() -> Result<()> {
     info!("[Dao] Building DAO mint tx");
     let (dao_mint_tx, dao_mint_params) = th.dao_mint(&dao, &dao_keypair)?;
 
-    info!("[Faucet] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Faucet, &dao_mint_tx, &dao_mint_params, current_slot).await?;
-
-    info!("[Alice] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Alice, &dao_mint_tx, &dao_mint_params, current_slot).await?;
-
-    info!("[Bob] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Bob, &dao_mint_tx, &dao_mint_params, current_slot).await?;
-
-    info!("[Charlie] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Charlie, &dao_mint_tx, &dao_mint_params, current_slot).await?;
-
-    info!("[Rachel] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Rachel, &dao_mint_tx, &dao_mint_params, current_slot).await?;
-
-    info!("[Dao] Executing DAO Mint tx");
-    th.execute_dao_mint_tx(Holder::Dao, &dao_mint_tx, &dao_mint_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing DAO Mint tx");
+        th.execute_dao_mint_tx(holder, &dao_mint_tx, &dao_mint_params, current_slot).await?;
+    }
 
-    // TODO: assert_trees
+    th.assert_trees(&HOLDERS);
 
     // =======================================
     // Airdrop some treasury tokens to the DAO
@@ -107,38 +94,22 @@ async fn integration_test() -> Result<()> {
     info!("[Faucet] Building DAO airdrop tx");
     let (airdrop_tx, airdrop_params) = th.airdrop_native(
         DRK_TOKEN_SUPPLY,
-        Holder::Dao,
+        &Holder::Dao,
         Some(DAO_CONTRACT_ID.inner()),           // spend_hook
         Some(dao_mint_params.dao_bulla.inner()), // user_data
         None,
         None,
     )?;
 
-    info!("[Faucet] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Faucet, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Alice, &airdrop_tx, &airdrop_params, current_slot).await?;
-
-    info!("[Bob] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Bob, &airdrop_tx, &airdrop_params, current_slot).await?;
-
-    info!("[Charlie] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Charlie, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!("[Rachel] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Rachel, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing DAO airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Dao, &airdrop_tx, &airdrop_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing DAO airdrop tx");
+        th.execute_airdrop_native_tx(holder, &airdrop_tx, &airdrop_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather the DAO owncoin
-    th.gather_owncoin(Holder::Dao, airdrop_params.outputs[0].clone(), None)?;
+    th.gather_owncoin(&Holder::Dao, &airdrop_params.outputs[0], None)?;
 
     // ======================================
     // Mint the governance token to 3 holders
@@ -147,102 +118,48 @@ async fn integration_test() -> Result<()> {
 
     info!("[Alice] Building governance token mint tx for Alice");
     let (a_token_mint_tx, a_token_mint_params) =
-        th.token_mint(ALICE_GOV_SUPPLY, Holder::Alice, Holder::Alice, None, None)?;
-
-    info!("[Faucet] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Faucet, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Alice, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Bob, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Charlie] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Charlie, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
+        th.token_mint(ALICE_GOV_SUPPLY, &Holder::Alice, &Holder::Alice, None, None)?;
 
-    info!("[Rachel] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Rachel, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing governance token mint tx for Alice");
-    th.execute_token_mint_tx(Holder::Dao, &a_token_mint_tx, &a_token_mint_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing governance token mint tx for Alice");
+        th.execute_token_mint_tx(holder, &a_token_mint_tx, &a_token_mint_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather owncoin
-    th.gather_owncoin(Holder::Alice, a_token_mint_params.output, None)?;
+    th.gather_owncoin(&Holder::Alice, &a_token_mint_params.output, None)?;
 
     info!("[Alice] Building governance token mint tx for Bob");
     let (b_token_mint_tx, b_token_mint_params) =
-        th.token_mint(BOB_GOV_SUPPLY, Holder::Alice, Holder::Bob, None, None)?;
-
-    info!("[Faucet] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Faucet, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Alice, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Bob, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
+        th.token_mint(BOB_GOV_SUPPLY, &Holder::Alice, &Holder::Bob, None, None)?;
 
-    info!("[Charlie] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Charlie, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Rachel] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Rachel, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing governance token mint tx for Bob");
-    th.execute_token_mint_tx(Holder::Dao, &b_token_mint_tx, &b_token_mint_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing governance token mint tx for Bob");
+        th.execute_token_mint_tx(holder, &b_token_mint_tx, &b_token_mint_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather owncoin
-    th.gather_owncoin(Holder::Bob, b_token_mint_params.output, None)?;
+    th.gather_owncoin(&Holder::Bob, &b_token_mint_params.output, None)?;
 
     info!("[Alice] Building governance token mint tx for Charlie");
     let (c_token_mint_tx, c_token_mint_params) =
-        th.token_mint(CHARLIE_GOV_SUPPLY, Holder::Alice, Holder::Charlie, None, None)?;
-
-    info!("[Faucet] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Faucet, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Alice, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Bob, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
+        th.token_mint(CHARLIE_GOV_SUPPLY, &Holder::Alice, &Holder::Charlie, None, None)?;
 
-    info!("[Charlie] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Charlie, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Rachel] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Rachel, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing governance token mint tx for Charlie");
-    th.execute_token_mint_tx(Holder::Dao, &c_token_mint_tx, &c_token_mint_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing governance token mint tx for Charlie");
+        th.execute_token_mint_tx(holder, &c_token_mint_tx, &c_token_mint_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather owncoin
-    th.gather_owncoin(Holder::Charlie, c_token_mint_params.output, None)?;
+    th.gather_owncoin(&Holder::Charlie, &c_token_mint_params.output, None)?;
 
     // ================
     // Dao::Propose
@@ -254,31 +171,18 @@ async fn integration_test() -> Result<()> {
     //       Need to look into this.
     info!("[Alice] Building DAO proposal tx");
     let (propose_tx, propose_params, propose_info) = th.dao_propose(
-        Holder::Alice,
-        Holder::Rachel,
+        &Holder::Alice,
+        &Holder::Rachel,
         PROPOSAL_AMOUNT,
         drk_token_id,
-        dao.clone(),
-        dao_mint_params.dao_bulla,
+        &dao,
+        &dao_mint_params.dao_bulla,
     )?;
 
-    info!("[Faucet] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Faucet, &propose_tx, &propose_params, current_slot).await?;
-
-    info!("[Alice] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Alice, &propose_tx, &propose_params, current_slot).await?;
-
-    info!("[Bob] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Bob, &propose_tx, &propose_params, current_slot).await?;
-
-    info!("[Charlie] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Charlie, &propose_tx, &propose_params, current_slot).await?;
-
-    info!("[Rachel] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Rachel, &propose_tx, &propose_params, current_slot).await?;
-
-    info!("[Dao] Executing DAO proposal tx");
-    th.execute_dao_propose_tx(Holder::Dao, &propose_tx, &propose_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing DAO proposal tx");
+        th.execute_dao_propose_tx(holder, &propose_tx, &propose_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
@@ -290,84 +194,43 @@ async fn integration_test() -> Result<()> {
 
     info!("[Alice] Building vote tx (yes)");
     let (alice_vote_tx, alice_vote_params) = th.dao_vote(
-        Holder::Alice,
+        &Holder::Alice,
         &dao_keypair,
         true,
-        dao.clone(),
-        propose_info.clone(),
-        propose_params.proposal_bulla,
+        &dao,
+        &propose_info,
+        &propose_params.proposal_bulla,
     )?;
 
     info!("[Bob] Building vote tx (no)");
     let (bob_vote_tx, bob_vote_params) = th.dao_vote(
-        Holder::Bob,
+        &Holder::Bob,
         &dao_keypair,
         false,
-        dao.clone(),
-        propose_info.clone(),
-        propose_params.proposal_bulla,
+        &dao,
+        &propose_info,
+        &propose_params.proposal_bulla,
     )?;
 
     info!("[Charlie] Building vote tx (yes)");
     let (charlie_vote_tx, charlie_vote_params) = th.dao_vote(
-        Holder::Charlie,
+        &Holder::Charlie,
         &dao_keypair,
         true,
-        dao.clone(),
-        propose_info.clone(),
-        propose_params.proposal_bulla,
+        &dao,
+        &propose_info,
+        &propose_params.proposal_bulla,
     )?;
 
-    info!("[Faucet] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Faucet, &alice_vote_tx, &alice_vote_params, current_slot)
-        .await?;
-    info!("[Faucet] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Faucet, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Faucet] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Faucet, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Alice, &alice_vote_tx, &alice_vote_params, current_slot).await?;
-    info!("[Alice] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Alice, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Alice] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Alice, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Bob, &alice_vote_tx, &alice_vote_params, current_slot).await?;
-    info!("[Bob] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Bob, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Bob] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Bob, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
-
-    info!("[Charlie] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Charlie, &alice_vote_tx, &alice_vote_params, current_slot)
-        .await?;
-    info!("[Charlie] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Charlie, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Charlie] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Charlie, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
-
-    info!("[Rachel] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Rachel, &alice_vote_tx, &alice_vote_params, current_slot)
-        .await?;
-    info!("[Rachel] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Rachel, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Rachel] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Rachel, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing Alice vote tx");
-    th.execute_dao_vote_tx(Holder::Dao, &alice_vote_tx, &alice_vote_params, current_slot).await?;
-    info!("[Dao] Executing Bob vote tx");
-    th.execute_dao_vote_tx(Holder::Dao, &bob_vote_tx, &bob_vote_params, current_slot).await?;
-    info!("[Dao] Executing Charlie vote tx");
-    th.execute_dao_vote_tx(Holder::Dao, &charlie_vote_tx, &charlie_vote_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing Alice vote tx");
+        th.execute_dao_vote_tx(holder, &alice_vote_tx, &alice_vote_params, current_slot).await?;
+        info!("[{holder:?}] Executing Bob vote tx");
+        th.execute_dao_vote_tx(holder, &bob_vote_tx, &bob_vote_params, current_slot).await?;
+        info!("[{holder:?}] Executing Charlie vote tx");
+        th.execute_dao_vote_tx(holder, &charlie_vote_tx, &charlie_vote_params, current_slot)
+            .await?;
+    }
 
     // Gather and decrypt all vote notes
     let vote_note_1: DaoVoteNote = alice_vote_params.note.decrypt(&dao_keypair.secret).unwrap();
@@ -426,42 +289,25 @@ async fn integration_test() -> Result<()> {
 
     info!("[Dao] Building Dao::Exec tx");
     let (exec_tx, xfer_params, exec_params) = th.dao_exec(
-        dao,
-        dao_mint_params.dao_bulla,
-        propose_info,
+        &dao,
+        &dao_mint_params.dao_bulla,
+        &propose_info,
         total_yes_vote_value,
         total_all_vote_value,
         total_yes_vote_blind,
         total_all_vote_blind,
     )?;
 
-    info!("[Faucet] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Faucet, &exec_tx, &xfer_params, &exec_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Alice, &exec_tx, &xfer_params, &exec_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Bob, &exec_tx, &xfer_params, &exec_params, current_slot).await?;
-
-    info!("[Charlie] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Charlie, &exec_tx, &xfer_params, &exec_params, current_slot)
-        .await?;
-
-    info!("[Rachel] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Rachel, &exec_tx, &xfer_params, &exec_params, current_slot)
-        .await?;
-
-    info!("[Dao] Executing Dao::Exec tx");
-    th.execute_dao_exec_tx(Holder::Dao, &exec_tx, &xfer_params, &exec_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing Dao::Exec tx");
+        th.execute_dao_exec_tx(holder, &exec_tx, &xfer_params, &exec_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather the coins
-    th.gather_owncoin(Holder::Dao, xfer_params.outputs[0].clone(), None)?;
-    th.gather_owncoin(Holder::Rachel, xfer_params.outputs[1].clone(), None)?;
+    th.gather_owncoin(&Holder::Dao, &xfer_params.outputs[0], None)?;
+    th.gather_owncoin(&Holder::Rachel, &xfer_params.outputs[1], None)?;
 
     let rachel_wallet = th.holders.get(&Holder::Rachel).unwrap();
     assert!(rachel_wallet.unspent_money_coins[0].note.value == PROPOSAL_AMOUNT);

+ 43 - 94
src/contract/money/tests/genesis_mint.rs

@@ -26,7 +26,7 @@
 //! with detection of erroneous transactions.
 
 use darkfi::Result;
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
+use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
 use darkfi_sdk::crypto::DARK_TOKEN_ID;
 use log::info;
 
@@ -60,15 +60,16 @@ async fn genesis_mint() -> Result<()> {
     info!(target: "money", "[Alice] ========================");
     info!(target: "money", "[Alice] Building genesis mint tx");
     info!(target: "money", "[Alice] ========================");
-    let (genesis_mint_tx, genesis_mint_params) = th.genesis_mint(Holder::Alice, ALICE_INITIAL)?;
+    let (genesis_mint_tx, genesis_mint_params) = th.genesis_mint(&Holder::Alice, ALICE_INITIAL)?;
 
     // We are going to use alice genesis mint transaction to
     // test some malicious cases.
     info!(target: "money", "[Malicious] ==================================");
     info!(target: "money", "[Malicious] Checking duplicate genesis mint tx");
     info!(target: "money", "[Malicious] ==================================");
-    th.execute_erroneous_genesis_mint_tx(
-        Holder::Alice,
+    th.execute_erroneous_txs(
+        TxAction::MoneyGenesisMint,
+        &Holder::Alice,
         &vec![genesis_mint_tx.clone(), genesis_mint_tx.clone()],
         current_slot,
         1,
@@ -78,78 +79,46 @@ async fn genesis_mint() -> Result<()> {
     info!(target: "money", "[Malicious] ============================================");
     info!(target: "money", "[Malicious] Checking genesis mint tx not on genesis slot");
     info!(target: "money", "[Malicious] ============================================");
-    th.execute_erroneous_genesis_mint_tx(
-        Holder::Alice,
+    th.execute_erroneous_txs(
+        TxAction::MoneyGenesisMint,
+        &Holder::Alice,
         &vec![genesis_mint_tx.clone()],
         current_slot + 1,
         1,
     )
     .await?;
-    info!(target: "money", "[Malicious] ===========================");
-    info!(target: "money", "[Malicious] Malicious test cases passed");
-    info!(target: "money", "[Malicious] ===========================");
-
-    info!(target: "money", "[Faucet] ===============================");
-    info!(target: "money", "[Faucet] Executing Alice genesis mint tx");
-    info!(target: "money", "[Faucet] ===============================");
-    th.execute_genesis_mint_tx(
-        Holder::Faucet,
-        &genesis_mint_tx,
-        &genesis_mint_params,
-        current_slot,
-    )
-    .await?;
 
-    info!(target: "money", "[Alice] ===============================");
-    info!(target: "money", "[Alice] Executing Alice genesis mint tx");
-    info!(target: "money", "[Alice] ===============================");
-    th.execute_genesis_mint_tx(Holder::Alice, &genesis_mint_tx, &genesis_mint_params, current_slot)
-        .await?;
-
-    info!(target: "money", "[Bob] ===============================");
-    info!(target: "money", "[Bob] Executing Alice genesis mint tx");
-    info!(target: "money", "[Bob] ===============================");
-    th.execute_genesis_mint_tx(Holder::Bob, &genesis_mint_tx, &genesis_mint_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ================================");
+        info!(target: "money", "[{holder:?}] Executing Alice genesis mint tx");
+        info!(target: "money", "[{holder:?}] ================================");
+        th.execute_genesis_mint_tx(holder, &genesis_mint_tx, &genesis_mint_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice gathers her new owncoin
-    let alice_oc = th.gather_owncoin(Holder::Alice, genesis_mint_params.output, None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &genesis_mint_params.output, None)?;
     alice_owncoins.push(alice_oc);
 
     info!(target: "money", "[Bob] ========================");
     info!(target: "money", "[Bob] Building genesis mint tx");
     info!(target: "money", "[Bob] ========================");
-    let (genesis_mint_tx, genesis_mint_params) = th.genesis_mint(Holder::Bob, BOB_INITIAL)?;
-
-    info!(target: "money", "[Faucet] ===============================");
-    info!(target: "money", "[Faucet] Executing Bob genesis mint tx");
-    info!(target: "money", "[Faucet] ===============================");
-    th.execute_genesis_mint_tx(
-        Holder::Faucet,
-        &genesis_mint_tx,
-        &genesis_mint_params,
-        current_slot,
-    )
-    .await?;
-
-    info!(target: "money", "[Alice] ===============================");
-    info!(target: "money", "[Alice] Executing Bob genesis mint tx");
-    info!(target: "money", "[Alice] ===============================");
-    th.execute_genesis_mint_tx(Holder::Alice, &genesis_mint_tx, &genesis_mint_params, current_slot)
-        .await?;
+    let (genesis_mint_tx, genesis_mint_params) = th.genesis_mint(&Holder::Bob, BOB_INITIAL)?;
 
-    info!(target: "money", "[Bob] ===============================");
-    info!(target: "money", "[Bob] Executing Bob genesis mint tx");
-    info!(target: "money", "[Bob] ===============================");
-    th.execute_genesis_mint_tx(Holder::Bob, &genesis_mint_tx, &genesis_mint_params, current_slot)
-        .await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] =============================");
+        info!(target: "money", "[{holder:?}] Executing Bob genesis mint tx");
+        info!(target: "money", "[{holder:?}] =============================");
+        th.execute_genesis_mint_tx(holder, &genesis_mint_tx, &genesis_mint_params, current_slot)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Bob gathers his new owncoin
-    let bob_oc = th.gather_owncoin(Holder::Bob, genesis_mint_params.output, None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &genesis_mint_params.output, None)?;
     bob_owncoins.push(bob_oc);
 
     // Now Alice can send a little bit of funds to Bob
@@ -157,7 +126,7 @@ async fn genesis_mint() -> Result<()> {
     info!(target: "money", "[Alice] Building Money::Transfer params for a payment to Bob");
     info!(target: "money", "[Alice] ====================================================");
     let (transfer_tx, transfer_params, spent_coins) =
-        th.transfer(ALICE_SEND, Holder::Alice, Holder::Bob, &alice_owncoins, *DARK_TOKEN_ID)?;
+        th.transfer(ALICE_SEND, &Holder::Alice, &Holder::Bob, &alice_owncoins, *DARK_TOKEN_ID)?;
 
     // Validating transfer params
     assert!(transfer_params.inputs.len() == 1);
@@ -166,31 +135,21 @@ async fn genesis_mint() -> Result<()> {
     alice_owncoins.retain(|x| x != &spent_coins[0]);
     assert!(alice_owncoins.is_empty());
 
-    info!(target: "money", "[Faucet] ==============================");
-    info!(target: "money", "[Faucet] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Faucet] ==============================");
-    th.execute_transfer_tx(Holder::Faucet, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==============================");
-    info!(target: "money", "[Alice] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Alice] ==============================");
-    th.execute_transfer_tx(Holder::Alice, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Bob] ==============================");
-    info!(target: "money", "[Bob] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Bob] ==============================");
-    th.execute_transfer_tx(Holder::Bob, &transfer_tx, &transfer_params, current_slot, true).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, true).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice should now have one OwnCoin with the change from the above transaction.
-    let alice_oc = th.gather_owncoin(Holder::Alice, transfer_params.outputs[0].clone(), None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &transfer_params.outputs[0], None)?;
     alice_owncoins.push(alice_oc);
 
     // Bob should have his old one, and this new one.
-    let bob_oc = th.gather_owncoin(Holder::Bob, transfer_params.outputs[1].clone(), None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[1], None)?;
     bob_owncoins.push(bob_oc);
 
     assert!(alice_owncoins.len() == 1);
@@ -201,7 +160,7 @@ async fn genesis_mint() -> Result<()> {
     info!(target: "money", "[Bob] Building Money::Transfer params for a payment to Alice");
     info!(target: "money", "[Bob] ======================================================");
     let (transfer_tx, transfer_params, spent_coins) =
-        th.transfer(BOB_SEND, Holder::Bob, Holder::Alice, &bob_owncoins, *DARK_TOKEN_ID)?;
+        th.transfer(BOB_SEND, &Holder::Bob, &Holder::Alice, &bob_owncoins, *DARK_TOKEN_ID)?;
 
     // Validating transfer params
     assert!(transfer_params.inputs.len() == 1);
@@ -210,31 +169,21 @@ async fn genesis_mint() -> Result<()> {
     bob_owncoins.retain(|x| x != &spent_coins[0]);
     assert!(bob_owncoins.len() == 1);
 
-    info!(target: "money", "[Faucet] ==============================");
-    info!(target: "money", "[Faucet] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Faucet] ==============================");
-    th.execute_transfer_tx(Holder::Faucet, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==============================");
-    info!(target: "money", "[Alice] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Alice] ==============================");
-    th.execute_transfer_tx(Holder::Alice, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Bob] ==================+===========");
-    info!(target: "money", "[Bob] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Bob] ==================+===========");
-    th.execute_transfer_tx(Holder::Bob, &transfer_tx, &transfer_params, current_slot, true).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Bob2Alice payment tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, true).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice should now have two OwnCoins
-    let alice_oc = th.gather_owncoin(Holder::Alice, transfer_params.outputs[1].clone(), None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &transfer_params.outputs[1], None)?;
     alice_owncoins.push(alice_oc);
 
     // Bob should have two with the change from the above tx
-    let bob_oc = th.gather_owncoin(Holder::Bob, transfer_params.outputs[0].clone(), None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &transfer_params.outputs[0], None)?;
     bob_owncoins.push(bob_oc);
 
     // Validating transaction outcomes

+ 17 - 34
src/contract/money/tests/integration.rs

@@ -53,56 +53,39 @@ async fn money_integration() -> Result<()> {
 
     info!("[Faucet] Building Alice airdrop tx");
     let (airdrop_tx, airdrop_params) =
-        th.airdrop_native(ALICE_NATIVE_AIRDROP, Holder::Alice, None, None, None, None)?;
+        th.airdrop_native(ALICE_NATIVE_AIRDROP, &Holder::Alice, None, None, None, None)?;
 
-    info!("[Faucet] Executing Alice airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Faucet, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing Alice airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Alice, &airdrop_tx, &airdrop_params, current_slot).await?;
-
-    info!("[Bob] Executing Alice airdrop tx");
-    th.execute_airdrop_native_tx(Holder::Bob, &airdrop_tx, &airdrop_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing Alice airdrop tx");
+        th.execute_airdrop_native_tx(holder, &airdrop_tx, &airdrop_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice gathers her new coin
-    th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), None)?;
+    th.gather_owncoin(&Holder::Alice, &airdrop_params.outputs[0], None)?;
 
     info!("[Bob] Building BOB token mint tx");
     let (token_mint_tx, token_mint_params) =
-        th.token_mint(BOB_SUPPLY, Holder::Bob, Holder::Bob, None, None)?;
-
-    info!("[Faucet] Executing BOB token mint tx");
-    th.execute_token_mint_tx(Holder::Faucet, &token_mint_tx, &token_mint_params, current_slot)
-        .await?;
+        th.token_mint(BOB_SUPPLY, &Holder::Bob, &Holder::Bob, None, None)?;
 
-    info!("[Alice] Executing BOB token mint tx");
-    th.execute_token_mint_tx(Holder::Alice, &token_mint_tx, &token_mint_params, current_slot)
-        .await?;
-
-    info!("[Bob] Executing BOB token mint tx");
-    th.execute_token_mint_tx(Holder::Bob, &token_mint_tx, &token_mint_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing BOB token mint tx");
+        th.execute_token_mint_tx(holder, &token_mint_tx, &token_mint_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Bob gathers his new coin
-    th.gather_owncoin(Holder::Bob, token_mint_params.output, None)?;
+    th.gather_owncoin(&Holder::Bob, &token_mint_params.output, None)?;
 
     info!("[Bob] Building BOB token freeze tx");
-    let (token_frz_tx, token_frz_params) = th.token_freeze(Holder::Bob)?;
-
-    info!("[Faucet] Executing BOB token freeze tx");
-    th.execute_token_freeze_tx(Holder::Faucet, &token_frz_tx, &token_frz_params, current_slot)
-        .await?;
-
-    info!("[Alice] Executing BOB token freeze tx");
-    th.execute_token_freeze_tx(Holder::Alice, &token_frz_tx, &token_frz_params, current_slot)
-        .await?;
+    let (token_frz_tx, token_frz_params) = th.token_freeze(&Holder::Bob)?;
 
-    info!("[Bob] Executing BOB token freeze tx");
-    th.execute_token_freeze_tx(Holder::Bob, &token_frz_tx, &token_frz_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!("[{holder:?}] Executing BOB token freeze tx");
+        th.execute_token_freeze_tx(holder, &token_frz_tx, &token_frz_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 

+ 82 - 148
src/contract/money/tests/mint_pay_swap.rs

@@ -62,54 +62,38 @@ async fn mint_pay_swap() -> Result<()> {
     info!(target: "money", "[Alice] Building token mint tx for Alice");
     info!(target: "money", "[Alice] ================================");
     let (mint_tx, params) =
-        th.token_mint(ALICE_INITIAL, Holder::Alice, Holder::Alice, None, None)?;
+        th.token_mint(ALICE_INITIAL, &Holder::Alice, &Holder::Alice, None, None)?;
 
-    info!(target: "money", "[Faucet] =============================");
-    info!(target: "money", "[Faucet] Executing Alice token mint tx");
-    info!(target: "money", "[Faucet] =============================");
-    th.execute_token_mint_tx(Holder::Faucet, &mint_tx, &params, current_slot).await?;
-
-    info!(target: "money", "[Alice] ===========================");
-    info!(target: "money", "[Alice] Executing Bob token mint tx");
-    info!(target: "money", "[Alice] ===========================");
-    th.execute_token_mint_tx(Holder::Alice, &mint_tx, &params, current_slot).await?;
-
-    info!(target: "money", "[Bob] =============================");
-    info!(target: "money", "[Bob] Executing Alice token mint tx");
-    info!(target: "money", "[Bob] =============================");
-    th.execute_token_mint_tx(Holder::Bob, &mint_tx, &params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Alice token mint tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_token_mint_tx(holder, &mint_tx, &params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice gathers her new owncoin
-    let alice_oc = th.gather_owncoin(Holder::Alice, params.output, None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &params.output, None)?;
     let alice_token_id = alice_oc.note.token_id;
     alice_owncoins.push(alice_oc);
 
     info!(target: "money", "[Bob] ==============================");
     info!(target: "money", "[Bob] Building token mint tx for Bob");
     info!(target: "money", "[Bob] ==============================");
-    let (mint_tx, params) = th.token_mint(BOB_INITIAL, Holder::Bob, Holder::Bob, None, None)?;
-
-    info!(target: "money", "[Faucet] ===========================");
-    info!(target: "money", "[Faucet] Executing Bob token mint tx");
-    info!(target: "money", "[Faucet] ===========================");
-    th.execute_token_mint_tx(Holder::Faucet, &mint_tx, &params, current_slot).await?;
+    let (mint_tx, params) = th.token_mint(BOB_INITIAL, &Holder::Bob, &Holder::Bob, None, None)?;
 
-    info!(target: "money", "[Alice] =============================");
-    info!(target: "money", "[Alice] Executing Alice token mint tx");
-    info!(target: "money", "[Alice] =============================");
-    th.execute_token_mint_tx(Holder::Alice, &mint_tx, &params, current_slot).await?;
-
-    info!(target: "money", "[Bob] ===========================");
-    info!(target: "money", "[Bob] Executing Bob token mint tx");
-    info!(target: "money", "[Bob] ===========================");
-    th.execute_token_mint_tx(Holder::Bob, &mint_tx, &params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ===========================");
+        info!(target: "money", "[{holder:?}] Executing Bob token mint tx");
+        info!(target: "money", "[{holder:?}] ===========================");
+        th.execute_token_mint_tx(holder, &mint_tx, &params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Bob  gathers hist new owncoin
-    let bob_oc = th.gather_owncoin(Holder::Bob, params.output, None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &params.output, None)?;
     let bob_token_id = bob_oc.note.token_id;
     bob_owncoins.push(bob_oc);
 
@@ -117,8 +101,13 @@ async fn mint_pay_swap() -> Result<()> {
     info!(target: "money", "[Alice] ====================================================");
     info!(target: "money", "[Alice] Building Money::Transfer params for a payment to Bob");
     info!(target: "money", "[Alice] ====================================================");
-    let (transfer_tx, transfer_params, spent_coins) =
-        th.transfer(ALICE_FIRST_SEND, Holder::Alice, Holder::Bob, &alice_owncoins, alice_token_id)?;
+    let (transfer_tx, transfer_params, spent_coins) = th.transfer(
+        ALICE_FIRST_SEND,
+        &Holder::Alice,
+        &Holder::Bob,
+        &alice_owncoins,
+        alice_token_id,
+    )?;
 
     // Validating transfer params
     assert!(transfer_params.inputs.len() == 1);
@@ -127,30 +116,19 @@ async fn mint_pay_swap() -> Result<()> {
     alice_owncoins.retain(|x| x != &spent_coins[0]);
     assert!(alice_owncoins.is_empty());
 
-    info!(target: "money", "[Faucet] ==============================");
-    info!(target: "money", "[Faucet] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Faucet] ==============================");
-    th.execute_transfer_tx(Holder::Faucet, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==============================");
-    info!(target: "money", "[Alice] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Alice] ==============================");
-    th.execute_transfer_tx(Holder::Alice, &transfer_tx, &transfer_params, current_slot, false)
-        .await?;
-
-    info!(target: "money", "[Bob] ==============================");
-    info!(target: "money", "[Bob] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Bob] ==============================");
-    th.execute_transfer_tx(Holder::Bob, &transfer_tx, &transfer_params, current_slot, false)
-        .await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, true).await?;
+    }
 
     // Alice should now have one OwnCoin with the change from the above transaction.
-    let alice_oc = th.gather_owncoin_at_index(Holder::Alice, &transfer_params.outputs, 0)?;
+    let alice_oc = th.gather_owncoin_at_index(&Holder::Alice, &transfer_params.outputs, 0)?;
     alice_owncoins.push(alice_oc);
 
     // Bob should now have this new one.
-    let bob_oc = th.gather_owncoin_at_index(Holder::Bob, &transfer_params.outputs, 1)?;
+    let bob_oc = th.gather_owncoin_at_index(&Holder::Bob, &transfer_params.outputs, 1)?;
     bob_owncoins.push(bob_oc);
 
     assert!(alice_owncoins.len() == 1);
@@ -165,7 +143,7 @@ async fn mint_pay_swap() -> Result<()> {
     let mut bob_owncoins_tmp = bob_owncoins.clone();
     bob_owncoins_tmp.retain(|x| x.note.token_id == bob_token_id);
     let (transfer_tx, transfer_params, spent_coins) =
-        th.transfer(BOB_FIRST_SEND, Holder::Bob, Holder::Alice, &bob_owncoins_tmp, bob_token_id)?;
+        th.transfer(BOB_FIRST_SEND, &Holder::Bob, &Holder::Alice, &bob_owncoins_tmp, bob_token_id)?;
 
     // Validating transfer params
     assert!(transfer_params.inputs.len() == 1);
@@ -174,30 +152,19 @@ async fn mint_pay_swap() -> Result<()> {
     bob_owncoins.retain(|x| x != &spent_coins[0]);
     assert!(bob_owncoins.len() == 1);
 
-    info!(target: "money", "[Faucet] ==============================");
-    info!(target: "money", "[Faucet] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Faucet] ==============================");
-    th.execute_transfer_tx(Holder::Faucet, &transfer_tx, &transfer_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==============================");
-    info!(target: "money", "[Alice] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Alice] ==============================");
-    th.execute_transfer_tx(Holder::Alice, &transfer_tx, &transfer_params, current_slot, false)
-        .await?;
-
-    info!(target: "money", "[Bob] ==============================");
-    info!(target: "money", "[Bob] Executing Bob2Alice payment tx");
-    info!(target: "money", "[Bob] ==============================");
-    th.execute_transfer_tx(Holder::Bob, &transfer_tx, &transfer_params, current_slot, false)
-        .await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Bob2Alice payment tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, true).await?;
+    }
 
     // Alice should now have two OwnCoins
-    let alice_oc = th.gather_owncoin_at_index(Holder::Alice, &transfer_params.outputs, 1)?;
+    let alice_oc = th.gather_owncoin_at_index(&Holder::Alice, &transfer_params.outputs, 1)?;
     alice_owncoins.push(alice_oc);
 
     // Bob should have two with the change from the above tx
-    let bob_oc = th.gather_owncoin_at_index(Holder::Bob, &transfer_params.outputs, 0)?;
+    let bob_oc = th.gather_owncoin_at_index(&Holder::Bob, &transfer_params.outputs, 0)?;
     bob_owncoins.push(bob_oc);
 
     assert!(alice_owncoins.len() == 2);
@@ -228,28 +195,17 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(bob_owncoins.len() == 1);
 
     let (otc_swap_tx, otc_swap_params) =
-        th.otc_swap(Holder::Alice, alice_oc, Holder::Bob, bob_oc)?;
-
-    info!(target: "money", "[Faucet] ==========================");
-    info!(target: "money", "[Faucet] Executing AliceBob swap tx");
-    info!(target: "money", "[Faucet] ==========================");
-    th.execute_otc_swap_tx(Holder::Faucet, &otc_swap_tx, &otc_swap_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==========================");
-    info!(target: "money", "[Alice] Executing AliceBob swap tx");
-    info!(target: "money", "[Alice] ==========================");
-    th.execute_otc_swap_tx(Holder::Alice, &otc_swap_tx, &otc_swap_params, current_slot, false)
-        .await?;
-
-    info!(target: "money", "[Bob] ==========================");
-    info!(target: "money", "[Bob] Executing AliceBob swap tx");
-    info!(target: "money", "[Bob] ==========================");
-    th.execute_otc_swap_tx(Holder::Bob, &otc_swap_tx, &otc_swap_params, current_slot, false)
-        .await?;
+        th.otc_swap(&Holder::Alice, &alice_oc, &Holder::Bob, &bob_oc)?;
+
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==========================");
+        info!(target: "money", "[{holder:?}] Executing AliceBob swap tx");
+        info!(target: "money", "[{holder:?}] ==========================");
+        th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, true).await?;
+    }
 
     // Alice should now have two OwnCoins with the same token ID (ALICE)
-    let alice_oc = th.gather_owncoin_at_index(Holder::Alice, &otc_swap_params.outputs, 0)?;
+    let alice_oc = th.gather_owncoin_at_index(&Holder::Alice, &otc_swap_params.outputs, 0)?;
     alice_owncoins.push(alice_oc);
 
     assert!(alice_owncoins.len() == 2);
@@ -257,7 +213,7 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(alice_owncoins[1].note.token_id == alice_token_id);
 
     // Same for Bob with BOB tokens
-    let bob_oc = th.gather_owncoin_at_index(Holder::Bob, &otc_swap_params.outputs, 1)?;
+    let bob_oc = th.gather_owncoin_at_index(&Holder::Bob, &otc_swap_params.outputs, 1)?;
     bob_owncoins.push(bob_oc);
 
     assert!(bob_owncoins.len() == 2);
@@ -270,8 +226,13 @@ async fn mint_pay_swap() -> Result<()> {
     info!(target: "money", "[Alice] ======================================================");
     info!(target: "money", "[Alice] Building Money::Transfer params for a payment to Alice");
     info!(target: "money", "[Alice] ======================================================");
-    let (tx, params, spent_coins) =
-        th.transfer(ALICE_INITIAL, Holder::Alice, Holder::Alice, &alice_owncoins, alice_token_id)?;
+    let (tx, params, spent_coins) = th.transfer(
+        ALICE_INITIAL,
+        &Holder::Alice,
+        &Holder::Alice,
+        &alice_owncoins,
+        alice_token_id,
+    )?;
 
     for coin in spent_coins {
         alice_owncoins.retain(|x| x != &coin);
@@ -280,25 +241,17 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(params.inputs.len() == 2);
     assert!(params.outputs.len() == 1);
 
-    info!(target: "money", "[Faucet] ================================");
-    info!(target: "money", "[Faucet] Executing Alice2Alice payment tx");
-    info!(target: "money", "[Faucet] ================================");
-    th.execute_transfer_tx(Holder::Faucet, &tx, &params, current_slot, true).await?;
-
-    info!(target: "money", "[Alice] ================================");
-    info!(target: "money", "[Alice] Executing Alice2Alice payment tx");
-    info!(target: "money", "[Alice] ================================");
-    th.execute_transfer_tx(Holder::Alice, &tx, &params, current_slot, true).await?;
-
-    info!(target: "money", "[Bob] ================================");
-    info!(target: "money", "[Bob] Executing Alice2Alice payment tx");
-    info!(target: "money", "[Bob] ================================");
-    th.execute_transfer_tx(Holder::Bob, &tx, &params, current_slot, true).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ================================");
+        info!(target: "money", "[{holder:?}] Executing Alice2Alice payment tx");
+        info!(target: "money", "[{holder:?}] ================================");
+        th.execute_transfer_tx(holder, &tx, &params, current_slot, true).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice should now have a single OwnCoin with her initial airdrop
-    let alice_oc = th.gather_owncoin(Holder::Alice, params.outputs[0].clone(), None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &params.outputs[0], None)?;
     alice_owncoins.push(alice_oc);
 
     assert!(alice_owncoins.len() == 1);
@@ -310,7 +263,7 @@ async fn mint_pay_swap() -> Result<()> {
     info!(target: "money", "[Bob] Building Money::Transfer params for a payment to Bob");
     info!(target: "money", "[Bob] ====================================================");
     let (tx, params, spent_coins) =
-        th.transfer(BOB_INITIAL, Holder::Bob, Holder::Bob, &bob_owncoins, bob_token_id)?;
+        th.transfer(BOB_INITIAL, &Holder::Bob, &Holder::Bob, &bob_owncoins, bob_token_id)?;
 
     for coin in spent_coins {
         bob_owncoins.retain(|x| x != &coin);
@@ -319,25 +272,17 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(params.inputs.len() == 2);
     assert!(params.outputs.len() == 1);
 
-    info!(target: "money", "[Faucet] ============================");
-    info!(target: "money", "[Faucet] Executing Bob2Bob payment tx");
-    info!(target: "money", "[Faucet] ============================");
-    th.execute_transfer_tx(Holder::Faucet, &tx, &params, current_slot, true).await?;
-
-    info!(target: "money", "[Alice] ============================");
-    info!(target: "money", "[Alice] Executing Bob2Bob payment tx");
-    info!(target: "money", "[Alice] ============================");
-    th.execute_transfer_tx(Holder::Alice, &tx, &params, current_slot, true).await?;
-
-    info!(target: "money", "[Bob] ============================");
-    info!(target: "money", "[Bob] Executing Bob2Bob payment tx");
-    info!(target: "money", "[Bob] ============================");
-    th.execute_transfer_tx(Holder::Bob, &tx, &params, current_slot, true).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ============================");
+        info!(target: "money", "[{holder:?}] Executing Bob2Bob payment tx");
+        info!(target: "money", "[{holder:?}] ============================");
+        th.execute_transfer_tx(holder, &tx, &params, current_slot, true).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Bob should now have a single OwnCoin with his initial airdrop
-    let bob_oc = th.gather_owncoin(Holder::Bob, params.outputs[0].clone(), None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &params.outputs[0], None)?;
     bob_owncoins.push(bob_oc);
 
     assert!(bob_owncoins.len() == 1);
@@ -356,28 +301,17 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(bob_owncoins.is_empty());
 
     let (otc_swap_tx, otc_swap_params) =
-        th.otc_swap(Holder::Alice, alice_oc, Holder::Bob, bob_oc)?;
-
-    info!(target: "money", "[Faucet] ==========================");
-    info!(target: "money", "[Faucet] Executing AliceBob swap tx");
-    info!(target: "money", "[Faucet] ==========================");
-    th.execute_otc_swap_tx(Holder::Faucet, &otc_swap_tx, &otc_swap_params, current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==========================");
-    info!(target: "money", "[Alice] Executing AliceBob swap tx");
-    info!(target: "money", "[Alice] ==========================");
-    th.execute_otc_swap_tx(Holder::Alice, &otc_swap_tx, &otc_swap_params, current_slot, false)
-        .await?;
-
-    info!(target: "money", "[Bob] ==========================");
-    info!(target: "money", "[Bob] Executing AliceBob swap tx");
-    info!(target: "money", "[Bob] ==========================");
-    th.execute_otc_swap_tx(Holder::Bob, &otc_swap_tx, &otc_swap_params, current_slot, false)
-        .await?;
+        th.otc_swap(&Holder::Alice, &alice_oc, &Holder::Bob, &bob_oc)?;
+
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==========================");
+        info!(target: "money", "[{holder:?}] Executing AliceBob swap tx");
+        info!(target: "money", "[{holder:?}] ==========================");
+        th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, true).await?;
+    }
 
     // Alice should now have Bob's BOB tokens
-    let alice_oc = th.gather_owncoin_at_index(Holder::Alice, &otc_swap_params.outputs, 0)?;
+    let alice_oc = th.gather_owncoin_at_index(&Holder::Alice, &otc_swap_params.outputs, 0)?;
     alice_owncoins.push(alice_oc);
 
     assert!(alice_owncoins.len() == 1);
@@ -385,7 +319,7 @@ async fn mint_pay_swap() -> Result<()> {
     assert!(alice_owncoins[0].note.token_id == bob_token_id);
 
     // And Bob should have Alice's ALICE tokens
-    let bob_oc = th.gather_owncoin_at_index(Holder::Bob, &otc_swap_params.outputs, 1)?;
+    let bob_oc = th.gather_owncoin_at_index(&Holder::Bob, &otc_swap_params.outputs, 1)?;
     bob_owncoins.push(bob_oc);
 
     assert!(bob_owncoins.len() == 1);

+ 32 - 58
src/contract/money/tests/txs_verification.rs

@@ -25,7 +25,7 @@
 //! between multiple parties, with detection of erroneous transactions.
 
 use darkfi::Result;
-use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
+use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
 use log::info;
 
 #[async_std::test]
@@ -55,29 +55,19 @@ async fn txs_verification() -> Result<()> {
     info!(target: "money", "[Alice] Building token mint tx for Alice");
     info!(target: "money", "[Alice] ================================");
     let (token_mint_tx, token_mint_params) =
-        th.token_mint(ALICE_INITIAL, Holder::Alice, Holder::Alice, None, None)?;
+        th.token_mint(ALICE_INITIAL, &Holder::Alice, &Holder::Alice, None, None)?;
 
-    info!(target: "money", "[Faucet] =============================");
-    info!(target: "money", "[Faucet] Executing Alice token mint tx");
-    info!(target: "money", "[Faucet] =============================");
-    th.execute_token_mint_tx(Holder::Faucet, &token_mint_tx, &token_mint_params, current_slot)
-        .await?;
-
-    info!(target: "money", "[Alice] =============================");
-    info!(target: "money", "[Alice] Executing Alice token mint tx");
-    info!(target: "money", "[Alice] =============================");
-    th.execute_token_mint_tx(Holder::Alice, &token_mint_tx, &token_mint_params, current_slot)
-        .await?;
-
-    info!(target: "money", "[Bob] =============================");
-    info!(target: "money", "[Bob] Executing Alice token mint tx");
-    info!(target: "money", "[Bob] =============================");
-    th.execute_token_mint_tx(Holder::Bob, &token_mint_tx, &token_mint_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] =============================");
+        info!(target: "money", "[{holder:?}] Executing Alice token mint tx");
+        info!(target: "money", "[{holder:?}] =============================");
+        th.execute_token_mint_tx(holder, &token_mint_tx, &token_mint_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice gathers her new owncoin
-    let alice_oc = th.gather_owncoin(Holder::Alice, token_mint_params.output, None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &token_mint_params.output, None)?;
     let alice_token_id = alice_oc.note.token_id;
     alice_owncoins.push(alice_oc);
 
@@ -91,7 +81,7 @@ async fn txs_verification() -> Result<()> {
         info!(target: "money", "[Alice] Building Money::Transfer params for payment {i} to Bob");
         info!(target: "money", "[Alice] ======================================================");
         let (transfer_tx, transfer_params, spent_coins) =
-            th.transfer(ALICE_SEND, Holder::Alice, Holder::Bob, &alice_owncoins, alice_token_id)?;
+            th.transfer(ALICE_SEND, &Holder::Alice, &Holder::Bob, &alice_owncoins, alice_token_id)?;
 
         // Validating transfer params
         assert!(transfer_params.inputs.len() == 1);
@@ -100,20 +90,12 @@ async fn txs_verification() -> Result<()> {
 
         // Now we simulate nodes verification, as transactions come one by one.
         // Validation should pass, even when we are trying to double spent.
-        info!(target: "money", "[Faucet] ==================================");
-        info!(target: "money", "[Faucet] Verifying Alice2Bob payment tx {i}");
-        info!(target: "money", "[Faucet] ==================================");
-        th.verify_transfer_tx(Holder::Faucet, &transfer_tx, current_slot).await?;
-
-        info!(target: "money", "[Alice] ==================================");
-        info!(target: "money", "[Alice] Verifying Alice2Bob payment tx {i}");
-        info!(target: "money", "[Alice] ==================================");
-        th.verify_transfer_tx(Holder::Alice, &transfer_tx, current_slot).await?;
-
-        info!(target: "money", "[Bob] ==================================");
-        info!(target: "money", "[Bob] Verifying Alice2Bob payment tx {i}");
-        info!(target: "money", "[Bob] ==================================");
-        th.verify_transfer_tx(Holder::Bob, &transfer_tx, current_slot).await?;
+        for holder in &HOLDERS {
+            info!(target: "money", "[{holder:?}] ==================================");
+            info!(target: "money", "[{holder:?}] Verifying Alice2Bob payment tx {i}");
+            info!(target: "money", "[{holder:?}] ==================================");
+            th.verify_transfer_tx(holder, &transfer_tx, current_slot).await?;
+        }
 
         transactions.push(transfer_tx);
         txs_params.push(transfer_params);
@@ -125,38 +107,30 @@ async fn txs_verification() -> Result<()> {
     // Now we can try to execute the transactions sequentialy.
     // Each node will detect the duplicate txs and filter them out,
     // then only apply the first txs from the set.
-    info!(target: "money", "[Faucet] ==============================");
-    info!(target: "money", "[Faucet] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Faucet] ==============================");
-    th.execute_erroneous_transfer_tx(Holder::Faucet, &transactions, current_slot, duplicates - 1)
-        .await?;
-    th.execute_transfer_tx(Holder::Faucet, &transactions[0], &txs_params[0], current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Alice] ==============================");
-    info!(target: "money", "[Alice] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Alice] ==============================");
-    th.execute_erroneous_transfer_tx(Holder::Alice, &transactions, current_slot, duplicates - 1)
-        .await?;
-    th.execute_transfer_tx(Holder::Alice, &transactions[0], &txs_params[0], current_slot, true)
-        .await?;
-
-    info!(target: "money", "[Bob] ==============================");
-    info!(target: "money", "[Bob] Executing Alice2Bob payment tx");
-    info!(target: "money", "[Bob] ==============================");
-    th.execute_erroneous_transfer_tx(Holder::Bob, &transactions, current_slot, duplicates - 1)
-        .await?;
-    th.execute_transfer_tx(Holder::Bob, &transactions[0], &txs_params[0], current_slot, true)
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==============================");
+        info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
+        info!(target: "money", "[{holder:?}] ==============================");
+        th.execute_erroneous_txs(
+            TxAction::MoneyTransfer,
+            holder,
+            &transactions,
+            current_slot,
+            duplicates - 1,
+        )
         .await?;
+        th.execute_transfer_tx(holder, &transactions[0], &txs_params[0], current_slot, true)
+            .await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Alice should now have one OwnCoin with the change from the above transaction.
-    let alice_oc = th.gather_owncoin(Holder::Alice, txs_params[0].outputs[0].clone(), None)?;
+    let alice_oc = th.gather_owncoin(&Holder::Alice, &txs_params[0].outputs[0], None)?;
     alice_owncoins.push(alice_oc);
 
     // Bob should now have this new one.
-    let bob_oc = th.gather_owncoin(Holder::Bob, txs_params[0].outputs[1].clone(), None)?;
+    let bob_oc = th.gather_owncoin(&Holder::Bob, &txs_params[0].outputs[1], None)?;
     bob_owncoins.push(bob_oc);
 
     assert!(alice_owncoins.len() == 1);

+ 24 - 31
src/contract/money/tests/verification_bench.rs

@@ -54,24 +54,20 @@ async fn alice2alice_random_amounts() -> Result<()> {
     info!(target: "money", "[Faucet] Building Alice's airdrop");
     info!(target: "money", "[Faucet] ========================");
     let (airdrop_tx, airdrop_params) =
-        th.airdrop_native(ALICE_AIRDROP, Holder::Alice, None, None, None, None)?;
+        th.airdrop_native(ALICE_AIRDROP, &Holder::Alice, None, None, None, None)?;
 
-    info!(target: "money", "[Faucet] ==========================");
-    info!(target: "money", "[Faucet] Executing Alice airdrop tx");
-    info!(target: "money", "[Faucet] ==========================");
-    th.execute_airdrop_native_tx(Holder::Faucet, &airdrop_tx, &airdrop_params, current_slot)
-        .await?;
-
-    info!(target: "money", "[Alice] ==========================");
-    info!(target: "money", "[Alice] Executing Alice airdrop tx");
-    info!(target: "money", "[Alice] ==========================");
-    th.execute_airdrop_native_tx(Holder::Alice, &airdrop_tx, &airdrop_params, current_slot).await?;
+    for holder in &HOLDERS {
+        info!(target: "money", "[{holder:?}] ==========================");
+        info!(target: "money", "[{holder:?}] Executing Alice airdrop tx");
+        info!(target: "money", "[{holder:?}] ==========================");
+        th.execute_airdrop_native_tx(holder, &airdrop_tx, &airdrop_params, current_slot).await?;
+    }
 
     th.assert_trees(&HOLDERS);
 
     // Gather new owncoins
     let mut owncoins = vec![];
-    let owncoin = th.gather_owncoin(Holder::Alice, airdrop_params.outputs[0].clone(), None)?;
+    let owncoin = th.gather_owncoin(&Holder::Alice, &airdrop_params.outputs[0], None)?;
     let token_id = owncoin.note.token_id;
     owncoins.push(owncoin);
 
@@ -87,7 +83,7 @@ async fn alice2alice_random_amounts() -> Result<()> {
         info!(target: "money", "[Alice] Sending: {}", amount);
         info!(target: "money", "[Alice] ===============================================");
         let (tx, params, spent_coins) =
-            th.transfer(amount, Holder::Alice, Holder::Alice, &owncoins, token_id)?;
+            th.transfer(amount, &Holder::Alice, &Holder::Alice, &owncoins, token_id)?;
 
         // Remove the owncoins we've spent
         for spent in spent_coins {
@@ -98,15 +94,15 @@ async fn alice2alice_random_amounts() -> Result<()> {
         info!(target: "money", "[Faucet] ================================");
         info!(target: "money", "[Faucet] Executing Alice2Alice payment tx");
         info!(target: "money", "[Faucet] ================================");
-        th.execute_transfer_tx(Holder::Faucet, &tx, &params, current_slot, true).await?;
+        th.execute_transfer_tx(&Holder::Faucet, &tx, &params, current_slot, true).await?;
 
         info!(target: "money", "[Alice] ================================");
         info!(target: "money", "[Alice] Executing Alice2Alice payment tx");
         info!(target: "money", "[Alice] ================================");
-        th.execute_transfer_tx(Holder::Alice, &tx, &params, current_slot, false).await?;
+        th.execute_transfer_tx(&Holder::Alice, &tx, &params, current_slot, false).await?;
 
         // Gather new owncoins
-        owncoins.append(&mut th.gather_multiple_owncoins(Holder::Alice, &params.outputs)?);
+        owncoins.append(&mut th.gather_multiple_owncoins(&Holder::Alice, &params.outputs)?);
 
         th.assert_trees(&HOLDERS);
     }
@@ -153,22 +149,19 @@ async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
         info!(target: "money", "[Faucet] Building Money::Mint params for Alice's mint for token {} and amount {}", i, amount);
         info!(target: "money", "[Faucet] ===================================================");
         let (mint_tx, mint_params) =
-            th.token_mint(amount, Holder::Alice, Holder::Alice, None, None)?;
+            th.token_mint(amount, &Holder::Alice, &Holder::Alice, None, None)?;
 
-        info!(target: "money", "[Faucet] =======================");
-        info!(target: "money", "[Faucet] Executing Alice mint tx");
-        info!(target: "money", "[Faucet] =======================");
-        th.execute_token_mint_tx(Holder::Faucet, &mint_tx, &mint_params, current_slot).await?;
-
-        info!(target: "money", "[Alice] =======================");
-        info!(target: "money", "[Alice] Executing Alice mint tx");
-        info!(target: "money", "[Alice] =======================");
-        th.execute_token_mint_tx(Holder::Alice, &mint_tx, &mint_params, current_slot).await?;
+        for holder in &HOLDERS {
+            info!(target: "money", "[{holder:?}] =======================");
+            info!(target: "money", "[{holder:?}] Executing Alice mint tx");
+            info!(target: "money", "[{holder:?}] =======================");
+            th.execute_token_mint_tx(holder, &mint_tx, &mint_params, current_slot).await?;
+        }
 
         th.assert_trees(&HOLDERS);
 
         // Gather new owncoins
-        let owncoin = th.gather_owncoin(Holder::Alice, mint_params.output, None)?;
+        let owncoin = th.gather_owncoin(&Holder::Alice, &mint_params.output, None)?;
         let token_id = owncoin.note.token_id;
         owncoins.push(vec![owncoin]);
         minted_amounts.push(amount);
@@ -202,7 +195,7 @@ async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
             info!(target: "money", "[Alice] Sending: {}", amount);
             info!(target: "money", "[Alice] ===============================================");
             let (tx, params, spent_coins) =
-                th.transfer(amount, Holder::Alice, Holder::Alice, &coins, token_id)?;
+                th.transfer(amount, &Holder::Alice, &Holder::Alice, &coins, token_id)?;
 
             // Remove the owncoins we've spent
             for spent in spent_coins {
@@ -210,7 +203,7 @@ async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
             }
 
             // Gather new owncoins
-            coins.append(&mut th.gather_multiple_owncoins(Holder::Alice, &params.outputs)?);
+            coins.append(&mut th.gather_multiple_owncoins(&Holder::Alice, &params.outputs)?);
 
             // Store transaction and its params
             txs.push(tx);
@@ -223,13 +216,13 @@ async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
         info!(target: "money", "[Faucet] =================================");
         info!(target: "money", "[Faucet] Executing Alice2Alice payment txs");
         info!(target: "money", "[Faucet] =================================");
-        th.execute_multiple_transfer_txs(Holder::Faucet, &txs, &txs_params, current_slot, true)
+        th.execute_multiple_transfer_txs(&Holder::Faucet, &txs, &txs_params, current_slot, true)
             .await?;
 
         info!(target: "money", "[Alice] =================================");
         info!(target: "money", "[Alice] Executing Alice2Alice payment txs");
         info!(target: "money", "[Alice] =================================");
-        th.execute_multiple_transfer_txs(Holder::Alice, &txs, &txs_params, current_slot, false)
+        th.execute_multiple_transfer_txs(&Holder::Alice, &txs, &txs_params, current_slot, false)
             .await?;
 
         th.assert_trees(&HOLDERS);

+ 4 - 31
src/contract/test-harness/src/consensus_genesis_stake.rs

@@ -37,10 +37,10 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn genesis_stake(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         amount: u64,
     ) -> Result<(Transaction, ConsensusGenesisStakeParamsV1)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (mint_pk, mint_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -89,12 +89,12 @@ impl TestHarness {
 
     pub async fn execute_genesis_stake_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &ConsensusGenesisStakeParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::ConsensusGenesisStake).unwrap();
         let timer = Instant::now();
@@ -105,31 +105,4 @@ impl TestHarness {
 
         Ok(())
     }
-
-    pub async fn execute_erroneous_genesis_stake_txs(
-        &mut self,
-        holder: Holder,
-        txs: &[Transaction],
-        slot: u64,
-        erroneous: usize,
-    ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusGenesisStake).unwrap();
-        let timer = Instant::now();
-
-        let erroneous_txs = wallet
-            .validator
-            .read()
-            .await
-            .add_transactions(txs, slot, false)
-            .await
-            .err()
-            .unwrap()
-            .retrieve_erroneous_txs()?;
-        assert_eq!(erroneous_txs.len(), erroneous);
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
 }

+ 45 - 29
src/contract/test-harness/src/consensus_proposal.rs

@@ -20,7 +20,8 @@ use std::time::Instant;
 
 use darkfi::{tx::Transaction, Result};
 use darkfi_consensus_contract::{
-    client::proposal_v1::ConsensusProposalCallBuilder, model::ConsensusProposalParamsV1,
+    client::proposal_v1::ConsensusProposalCallBuilder,
+    model::{ConsensusProposalParamsV1, REWARD},
     ConsensusFunction,
 };
 use darkfi_money_contract::{client::ConsensusOwnCoin, CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1};
@@ -30,6 +31,7 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
+use log::info;
 use rand::rngs::OsRng;
 
 use super::{Holder, TestHarness, TxAction};
@@ -37,11 +39,11 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub async fn proposal(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         slot: Slot,
-        staked_oc: ConsensusOwnCoin,
+        staked_oc: &ConsensusOwnCoin,
     ) -> Result<(Transaction, ConsensusProposalParamsV1, SecretKey, SecretKey)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (proposal_pk, proposal_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_PROPOSAL_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -53,7 +55,7 @@ impl TestHarness {
 
         // Building Consensus::Propose params
         let proposal_call_debris = ConsensusProposalCallBuilder {
-            owncoin: staked_oc,
+            owncoin: staked_oc.clone(),
             slot,
             fork_hash,
             fork_previous_hash: fork_hash,
@@ -94,12 +96,12 @@ impl TestHarness {
 
     pub async fn execute_proposal_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &ConsensusProposalParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
         let timer = Instant::now();
@@ -111,30 +113,44 @@ impl TestHarness {
         Ok(())
     }
 
-    pub async fn execute_erroneous_proposal_txs(
+    // Execute a proposal transaction and gather rewarded coin
+    pub async fn execute_proposal(
         &mut self,
-        holder: Holder,
-        txs: &[Transaction],
-        slot: u64,
-        erroneous: usize,
-    ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusProposal).unwrap();
-        let timer = Instant::now();
+        holders: &[Holder],
+        holder: &Holder,
+        current_slot: u64,
+        slot: Slot,
+        staked_oc: &ConsensusOwnCoin,
+    ) -> Result<ConsensusOwnCoin> {
+        info!(target: "consensus", "[{holder:?}] ====================");
+        info!(target: "consensus", "[{holder:?}] Building proposal tx");
+        info!(target: "consensus", "[{holder:?}] ====================");
+        let (
+            proposal_tx,
+            proposal_params,
+            _proposal_signing_secret_key,
+            proposal_decryption_secret_key,
+        ) = self.proposal(holder, slot, staked_oc).await?;
+
+        for h in holders {
+            info!(target: "consensus", "[{h:?}] ===========================");
+            info!(target: "consensus", "[{h:?}] Executing {holder:?} proposal tx");
+            info!(target: "consensus", "[{h:?}] ===========================");
+            self.execute_proposal_tx(h, &proposal_tx, &proposal_params, current_slot).await?;
+        }
 
-        let erroneous_txs = wallet
-            .validator
-            .read()
-            .await
-            .add_transactions(txs, slot, false)
-            .await
-            .err()
-            .unwrap()
-            .retrieve_erroneous_txs()?;
-        assert_eq!(erroneous_txs.len(), erroneous);
-        tx_action_benchmark.verify_times.push(timer.elapsed());
+        self.assert_trees(holders);
 
-        Ok(())
+        // Gather new staked owncoin which includes the reward
+        let rewarded_staked_oc = self.gather_consensus_staked_owncoin(
+            holder,
+            &proposal_params.output,
+            Some(proposal_decryption_secret_key),
+        )?;
+
+        // Verify values match
+        assert!((staked_oc.note.value + REWARD) == rewarded_staked_oc.note.value);
+
+        Ok(rewarded_staked_oc)
     }
 }

+ 48 - 8
src/contract/test-harness/src/consensus_stake.rs

@@ -21,15 +21,17 @@ use std::time::Instant;
 use darkfi::{tx::Transaction, Result};
 use darkfi_consensus_contract::{client::stake_v1::ConsensusStakeCallBuilder, ConsensusFunction};
 use darkfi_money_contract::{
-    client::{stake_v1::MoneyStakeCallBuilder, OwnCoin},
+    client::{stake_v1::MoneyStakeCallBuilder, ConsensusOwnCoin, OwnCoin},
     model::ConsensusStakeParamsV1,
     MoneyFunction, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
 };
 use darkfi_sdk::{
     crypto::{MerkleNode, SecretKey, CONSENSUS_CONTRACT_ID, MONEY_CONTRACT_ID},
+    pasta::pallas,
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
+use log::info;
 use rand::rngs::OsRng;
 
 use super::{Holder, TestHarness, TxAction};
@@ -37,11 +39,12 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub async fn stake(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         slot: u64,
-        owncoin: OwnCoin,
+        owncoin: &OwnCoin,
+        serial: pallas::Base,
     ) -> Result<(Transaction, ConsensusStakeParamsV1, SecretKey)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (mint_pk, mint_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
@@ -73,14 +76,14 @@ impl TestHarness {
 
         // Building Consensus::Stake params
         let consensus_stake_call_debris = ConsensusStakeCallBuilder {
-            coin: owncoin,
+            coin: owncoin.clone(),
             epoch,
             value_blind: money_stake_value_blind,
             money_input: money_stake_params.input.clone(),
             mint_zkbin: mint_zkbin.clone(),
             mint_pk: mint_pk.clone(),
         }
-        .build()?;
+        .build_with_params(serial)?;
 
         let (consensus_stake_params, consensus_stake_proofs, consensus_stake_secret_key) = (
             consensus_stake_call_debris.params,
@@ -118,12 +121,12 @@ impl TestHarness {
 
     pub async fn execute_stake_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &ConsensusStakeParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::ConsensusStake).unwrap();
         let timer = Instant::now();
@@ -134,4 +137,41 @@ impl TestHarness {
 
         Ok(())
     }
+
+    // Execute a stake transaction and gather the coin
+    pub async fn execute_stake(
+        &mut self,
+        holders: &[Holder],
+        holder: &Holder,
+        current_slot: u64,
+        oc: &OwnCoin,
+        serial: u64,
+    ) -> Result<ConsensusOwnCoin> {
+        info!(target: "consensus", "[{holder:?}] =================");
+        info!(target: "consensus", "[{holder:?}] Building stake tx");
+        info!(target: "consensus", "[{holder:?}] =================");
+        let (stake_tx, stake_params, stake_secret_key) =
+            self.stake(holder, current_slot, oc, pallas::Base::from(serial)).await?;
+
+        for h in holders {
+            info!(target: "consensus", "[{h:?}] =============================");
+            info!(target: "consensus", "[{h:?}] Executing {holder:?} stake tx");
+            info!(target: "consensus", "[{h:?}] =============================");
+            self.execute_stake_tx(h, &stake_tx, &stake_params, current_slot).await?;
+        }
+
+        self.assert_trees(holders);
+
+        // Gather new staked owncoin
+        let staked_oc = self.gather_consensus_staked_owncoin(
+            holder,
+            &stake_params.output,
+            Some(stake_secret_key),
+        )?;
+
+        // Verify values match
+        assert!(oc.note.value == staked_oc.note.value);
+
+        Ok(staked_oc)
+    }
 }

+ 40 - 8
src/contract/test-harness/src/consensus_unstake.rs

@@ -23,7 +23,7 @@ use darkfi_consensus_contract::{
     client::unstake_v1::ConsensusUnstakeCallBuilder, ConsensusFunction,
 };
 use darkfi_money_contract::{
-    client::{unstake_v1::MoneyUnstakeCallBuilder, ConsensusOwnCoin},
+    client::{unstake_v1::MoneyUnstakeCallBuilder, ConsensusOwnCoin, OwnCoin},
     model::MoneyUnstakeParamsV1,
     MoneyFunction, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
@@ -32,6 +32,7 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
+use log::info;
 use rand::rngs::OsRng;
 
 use super::{Holder, TestHarness, TxAction};
@@ -39,10 +40,10 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn unstake(
         &mut self,
-        holder: Holder,
-        staked_oc: ConsensusOwnCoin,
+        holder: &Holder,
+        staked_oc: &ConsensusOwnCoin,
     ) -> Result<(Transaction, MoneyUnstakeParamsV1, SecretKey)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (burn_pk, burn_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
         let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
@@ -72,8 +73,8 @@ impl TestHarness {
 
         // Building Money::Unstake params
         let money_unstake_call_debris = MoneyUnstakeCallBuilder {
-            owncoin: staked_oc,
-            recipient: self.holders.get_mut(&holder).unwrap().keypair.public,
+            owncoin: staked_oc.clone(),
+            recipient: self.holders.get_mut(holder).unwrap().keypair.public,
             value_blind: consensus_unstake_value_blind,
             nullifier: consensus_unstake_params.input.nullifier,
             merkle_root: consensus_unstake_params.input.merkle_root,
@@ -115,12 +116,12 @@ impl TestHarness {
 
     pub async fn execute_unstake_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyUnstakeParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstake).unwrap();
         let timer = Instant::now();
@@ -131,4 +132,35 @@ impl TestHarness {
 
         Ok(())
     }
+
+    // Execute an unstake transaction and gather unstaked coin
+    pub async fn execute_unstake(
+        &mut self,
+        holders: &[Holder],
+        holder: &Holder,
+        current_slot: u64,
+        unstake_request_oc: &ConsensusOwnCoin,
+    ) -> Result<OwnCoin> {
+        info!(target: "consensus", "[{holder:?}] ===================");
+        info!(target: "consensus", "[{holder:?}] Building unstake tx");
+        info!(target: "consensus", "[{holder:?}] ===================");
+        let (unstake_tx, unstake_params, _) = self.unstake(holder, unstake_request_oc)?;
+
+        for h in holders {
+            info!(target: "consensus", "[{h:?}] ===============================");
+            info!(target: "consensus", "[{h:?}] Executing {holder:?} unstake tx");
+            info!(target: "consensus", "[{h:?}] ===============================");
+            self.execute_unstake_tx(h, &unstake_tx, &unstake_params, current_slot).await?;
+        }
+
+        self.assert_trees(holders);
+
+        // Gather new unstaked owncoin
+        let unstaked_oc = self.gather_owncoin(holder, &unstake_params.output, None)?;
+
+        // Verify values match
+        assert!(unstake_request_oc.note.value == unstaked_oc.note.value);
+
+        Ok(unstaked_oc)
+    }
 }

+ 47 - 27
src/contract/test-harness/src/consensus_unstake_request.rs

@@ -31,6 +31,7 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
+use log::info;
 use rand::rngs::OsRng;
 
 use super::{Holder, TestHarness, TxAction};
@@ -38,11 +39,11 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub async fn unstake_request(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         slot: u64,
-        staked_oc: ConsensusOwnCoin,
+        staked_oc: &ConsensusOwnCoin,
     ) -> Result<(Transaction, ConsensusUnstakeReqParamsV1, SecretKey, SecretKey)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (burn_pk, burn_zkbin) =
             self.proving_keys.get(&CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
         let (mint_pk, mint_zkbin) =
@@ -106,12 +107,12 @@ impl TestHarness {
 
     pub async fn execute_unstake_request_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &ConsensusUnstakeReqParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstakeRequest).unwrap();
         let timer = Instant::now();
@@ -123,30 +124,49 @@ impl TestHarness {
         Ok(())
     }
 
-    pub async fn execute_erroneous_unstake_request_txs(
+    // Execute an unstake request transaction and gather requested unstaked coin
+    pub async fn execute_unstake_request(
         &mut self,
-        holder: Holder,
-        txs: &[Transaction],
-        slot: u64,
-        erroneous: usize,
-    ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::ConsensusUnstakeRequest).unwrap();
-        let timer = Instant::now();
+        holders: &[Holder],
+        holder: &Holder,
+        current_slot: u64,
+        rewarded_staked_oc: &ConsensusOwnCoin,
+    ) -> Result<ConsensusOwnCoin> {
+        info!(target: "consensus", "[{holder:?}] ===========================");
+        info!(target: "consensus", "[{holder:?}] Building unstake request tx");
+        info!(target: "consensus", "[{holder:?}] ===========================");
+        let (
+            unstake_request_tx,
+            unstake_request_params,
+            unstake_request_output_secret_key,
+            _unstake_request_signature_secret_key,
+        ) = self.unstake_request(holder, current_slot, rewarded_staked_oc).await?;
 
-        let erroneous_txs = wallet
-            .validator
-            .read()
-            .await
-            .add_transactions(txs, slot, false)
-            .await
-            .err()
-            .unwrap()
-            .retrieve_erroneous_txs()?;
-        assert_eq!(erroneous_txs.len(), erroneous);
-        tx_action_benchmark.verify_times.push(timer.elapsed());
+        for h in holders {
+            info!(target: "consensus", "[{h:?}] ==================================");
+            info!(target: "consensus", "[{h:?}] Executing {holder:?} unstake request tx");
+            info!(target: "consensus", "[{h:?}] ==================================");
+            self.execute_unstake_request_tx(
+                h,
+                &unstake_request_tx,
+                &unstake_request_params,
+                current_slot,
+            )
+            .await?;
+        }
 
-        Ok(())
+        self.assert_trees(holders);
+
+        // Gather new unstake request owncoin
+        let unstake_request_oc = self.gather_consensus_unstaked_owncoin(
+            holder,
+            &unstake_request_params.output,
+            Some(unstake_request_output_secret_key),
+        )?;
+
+        // Verify values match
+        assert!(rewarded_staked_oc.note.value == unstake_request_oc.note.value);
+
+        Ok(unstake_request_oc)
     }
 }

+ 7 - 7
src/contract/test-harness/src/dao_exec.rs

@@ -42,9 +42,9 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn dao_exec(
         &mut self,
-        dao: DaoInfo,
-        dao_bulla: DaoBulla,
-        proposal: DaoProposalInfo,
+        dao: &DaoInfo,
+        dao_bulla: &DaoBulla,
+        proposal: &DaoProposalInfo,
         yes_vote_value: u64,
         all_vote_value: u64,
         yes_vote_blind: pallas::Scalar,
@@ -116,8 +116,8 @@ impl TestHarness {
         let user_serial = xfer_debris.minted_coins[1].note.serial;
 
         let exec_builder = DaoExecCall {
-            proposal,
-            dao,
+            proposal: proposal.clone(),
+            dao: dao.clone(),
             yes_vote_value,
             all_vote_value,
             yes_vote_blind,
@@ -158,13 +158,13 @@ impl TestHarness {
 
     pub async fn execute_dao_exec_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         xfer_params: &MoneyTransferParamsV1,
         _exec_params: &DaoExecParams,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoExec).unwrap();
         let timer = Instant::now();
 

+ 2 - 2
src/contract/test-harness/src/dao_mint.rs

@@ -67,12 +67,12 @@ impl TestHarness {
 
     pub async fn execute_dao_mint_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &DaoMintParams,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoMint).unwrap();
         let timer = Instant::now();
 

+ 7 - 7
src/contract/test-harness/src/dao_propose.rs

@@ -38,12 +38,12 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn dao_propose(
         &mut self,
-        proposer: Holder,
-        recipient: Holder,
+        proposer: &Holder,
+        recipient: &Holder,
         amount: u64,
         tx_token_id: TokenId,
-        dao: DaoInfo,
-        dao_bulla: DaoBulla,
+        dao: &DaoInfo,
+        dao_bulla: &DaoBulla,
     ) -> Result<(Transaction, DaoProposeParams, DaoProposalInfo)> {
         let (dao_propose_burn_pk, dao_propose_burn_zkbin) =
             self.proving_keys.get(&DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS).unwrap();
@@ -82,7 +82,7 @@ impl TestHarness {
         let call = DaoProposeCall {
             inputs: vec![input],
             proposal: proposal.clone(),
-            dao,
+            dao: dao.clone(),
             dao_leaf_position: *wallet.dao_leafs.get(&dao_bulla).unwrap(),
             dao_merkle_path: wallet
                 .dao_merkle_tree
@@ -120,12 +120,12 @@ impl TestHarness {
 
     pub async fn execute_dao_propose_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &DaoProposeParams,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoPropose).unwrap();
         let timer = Instant::now();
 

+ 9 - 9
src/contract/test-harness/src/dao_vote.rs

@@ -38,12 +38,12 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn dao_vote(
         &mut self,
-        voter: Holder,
+        voter: &Holder,
         dao_kp: &Keypair,
         vote_option: bool,
-        dao: DaoInfo,
-        proposal: DaoProposalInfo,
-        proposal_bulla: DaoProposalBulla,
+        dao: &DaoInfo,
+        proposal: &DaoProposalInfo,
+        proposal_bulla: &DaoProposalBulla,
     ) -> Result<(Transaction, DaoVoteParams)> {
         let (dao_vote_burn_pk, dao_vote_burn_zkbin) =
             self.proving_keys.get(&DAO_CONTRACT_ZKAS_DAO_VOTE_BURN_NS).unwrap();
@@ -52,7 +52,7 @@ impl TestHarness {
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoVote).unwrap();
         let timer = Instant::now();
 
-        let wallet = self.holders.get(&voter).unwrap();
+        let wallet = self.holders.get(voter).unwrap();
 
         let (_proposal_leaf_pos, money_merkle_tree) =
             wallet.dao_prop_leafs.get(&proposal_bulla).unwrap();
@@ -78,8 +78,8 @@ impl TestHarness {
             vote_option,
             yes_vote_blind: pallas::Scalar::random(&mut OsRng),
             vote_keypair: *dao_kp,
-            proposal,
-            dao,
+            proposal: proposal.clone(),
+            dao: dao.clone(),
         };
 
         let (params, proofs) = call.make(
@@ -111,12 +111,12 @@ impl TestHarness {
 
     pub async fn execute_dao_vote_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         _params: &DaoVoteParams,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&TxAction::DaoVote).unwrap();
         let timer = Instant::now();
 

+ 41 - 13
src/contract/test-harness/src/lib.rs

@@ -16,11 +16,12 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::collections::HashMap;
+use std::{collections::HashMap, time::Instant};
 
 use darkfi::{
     blockchain::BlockInfo,
     runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
+    tx::Transaction,
     util::{
         pcg::Pcg32,
         time::{TimeKeeper, Timestamp},
@@ -327,10 +328,37 @@ impl TestHarness {
         })
     }
 
+    pub async fn execute_erroneous_txs(
+        &mut self,
+        action: TxAction,
+        holder: &Holder,
+        txs: &[Transaction],
+        slot: u64,
+        erroneous: usize,
+    ) -> Result<()> {
+        let wallet = self.holders.get(holder).unwrap();
+        let tx_action_benchmark = self.tx_action_benchmarks.get_mut(&action).unwrap();
+        let timer = Instant::now();
+
+        let erroneous_txs = wallet
+            .validator
+            .read()
+            .await
+            .add_transactions(txs, slot, false)
+            .await
+            .err()
+            .unwrap()
+            .retrieve_erroneous_txs()?;
+        assert_eq!(erroneous_txs.len(), erroneous);
+        tx_action_benchmark.verify_times.push(timer.elapsed());
+
+        Ok(())
+    }
+
     pub fn gather_owncoin(
         &mut self,
-        holder: Holder,
-        output: Output,
+        holder: &Holder,
+        output: &Output,
         secret_key: Option<SecretKey>,
     ) -> Result<OwnCoin> {
         let wallet = self.holders.get_mut(&holder).unwrap();
@@ -358,10 +386,10 @@ impl TestHarness {
     /// before each output coin. Assumes using wallet secret key.
     pub fn gather_multiple_owncoins(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         outputs: &[Output],
     ) -> Result<Vec<OwnCoin>> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let secret_key = wallet.keypair.secret;
         let mut owncoins = vec![];
         for output in outputs {
@@ -389,11 +417,11 @@ impl TestHarness {
 
     pub fn gather_owncoin_at_index(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         outputs: &[Output],
         index: usize,
     ) -> Result<OwnCoin> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let secret_key = wallet.keypair.secret;
         let mut owncoin = None;
         for (i, output) in outputs.iter().enumerate() {
@@ -423,11 +451,11 @@ impl TestHarness {
 
     pub fn gather_consensus_staked_owncoin(
         &mut self,
-        holder: Holder,
-        output: ConsensusOutput,
+        holder: &Holder,
+        output: &ConsensusOutput,
         secret_key: Option<SecretKey>,
     ) -> Result<ConsensusOwnCoin> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let leaf_position = wallet.consensus_staked_merkle_tree.mark().unwrap();
         let secret_key = match secret_key {
             Some(key) => key,
@@ -447,11 +475,11 @@ impl TestHarness {
 
     pub fn gather_consensus_unstaked_owncoin(
         &mut self,
-        holder: Holder,
-        output: ConsensusOutput,
+        holder: &Holder,
+        output: &ConsensusOutput,
         secret_key: Option<SecretKey>,
     ) -> Result<ConsensusOwnCoin> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let leaf_position = wallet.consensus_unstaked_merkle_tree.mark().unwrap();
         let secret_key = match secret_key {
             Some(key) => key,

+ 37 - 6
src/contract/test-harness/src/money_airdrop.rs

@@ -20,8 +20,9 @@ use std::time::Instant;
 
 use darkfi::{tx::Transaction, zk::halo2::Field, Result};
 use darkfi_money_contract::{
-    client::transfer_v1::TransferCallBuilder, model::MoneyTransferParamsV1, MoneyFunction,
-    MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
+    client::{transfer_v1::TransferCallBuilder, OwnCoin},
+    model::MoneyTransferParamsV1,
+    MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
     crypto::{MerkleNode, DARK_TOKEN_ID, MONEY_CONTRACT_ID},
@@ -29,6 +30,7 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
+use log::info;
 use rand::rngs::OsRng;
 
 use super::{Holder, TestHarness, TxAction};
@@ -37,13 +39,13 @@ impl TestHarness {
     pub fn airdrop_native(
         &mut self,
         value: u64,
-        holder: Holder,
+        holder: &Holder,
         rcpt_spend_hook: Option<pallas::Base>,
         rcpt_user_data: Option<pallas::Base>,
         change_spend_hook: Option<pallas::Base>,
         change_user_data: Option<pallas::Base>,
     ) -> Result<(Transaction, MoneyTransferParamsV1)> {
-        let recipient = self.holders.get(&holder).unwrap().keypair.public;
+        let recipient = self.holders.get(holder).unwrap().keypair.public;
         let faucet = self.holders.get(&Holder::Faucet).unwrap();
         let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
@@ -95,12 +97,12 @@ impl TestHarness {
 
     pub async fn execute_airdrop_native_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyTransferParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyAirdrop).unwrap();
         let timer = Instant::now();
@@ -111,4 +113,33 @@ impl TestHarness {
 
         Ok(())
     }
+
+    // Execute an airdrop transaction and gather the coin
+    pub async fn execute_airdrop(
+        &mut self,
+        holders: &[Holder],
+        holder: &Holder,
+        value: u64,
+        current_slot: u64,
+    ) -> Result<OwnCoin> {
+        info!(target: "consensus", "[Faucet] ==============================");
+        info!(target: "consensus", "[Faucet] Building {holder:?} airdrop tx");
+        info!(target: "consensus", "[Faucet] ==============================");
+        let (airdrop_tx, airdrop_params) =
+            self.airdrop_native(value, holder, None, None, None, None)?;
+
+        for h in holders {
+            info!(target: "consensus", "[{h:?}] ===============================");
+            info!(target: "consensus", "[{h:?}] Executing {holder:?} airdrop tx");
+            info!(target: "consensus", "[{h:?}] ===============================");
+            self.execute_airdrop_native_tx(h, &airdrop_tx, &airdrop_params, current_slot).await?;
+        }
+
+        self.assert_trees(holders);
+
+        // Gather new owncoin
+        let oc = self.gather_owncoin(holder, &airdrop_params.outputs[0], None)?;
+
+        Ok(oc)
+    }
 }

+ 4 - 31
src/contract/test-harness/src/money_genesis_mint.rs

@@ -36,10 +36,10 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn genesis_mint(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         amount: u64,
     ) -> Result<(Transaction, MoneyTokenMintParamsV1)> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyGenesisMint).unwrap();
@@ -82,12 +82,12 @@ impl TestHarness {
 
     pub async fn execute_genesis_mint_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyTokenMintParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyGenesisMint).unwrap();
         let timer = Instant::now();
@@ -98,31 +98,4 @@ impl TestHarness {
 
         Ok(())
     }
-
-    pub async fn execute_erroneous_genesis_mint_tx(
-        &mut self,
-        holder: Holder,
-        txs: &[Transaction],
-        slot: u64,
-        erroneous: usize,
-    ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::MoneyGenesisMint).unwrap();
-        let timer = Instant::now();
-
-        let erroneous_txs = wallet
-            .validator
-            .read()
-            .await
-            .add_transactions(txs, slot, false)
-            .await
-            .err()
-            .unwrap()
-            .retrieve_erroneous_txs()?;
-        assert_eq!(erroneous_txs.len(), erroneous);
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
 }

+ 8 - 8
src/contract/test-harness/src/money_otc_swap.rs

@@ -37,13 +37,13 @@ use super::{Holder, TestHarness, TxAction};
 impl TestHarness {
     pub fn otc_swap(
         &mut self,
-        holder0: Holder,
-        owncoin0: OwnCoin,
-        holder1: Holder,
-        owncoin1: OwnCoin,
+        holder0: &Holder,
+        owncoin0: &OwnCoin,
+        holder1: &Holder,
+        owncoin1: &OwnCoin,
     ) -> Result<(Transaction, MoneyTransferParamsV1)> {
-        let wallet0 = self.holders.get(&holder0).unwrap();
-        let wallet1 = self.holders.get(&holder1).unwrap();
+        let wallet0 = self.holders.get(holder0).unwrap();
+        let wallet1 = self.holders.get(holder1).unwrap();
         let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -98,7 +98,7 @@ impl TestHarness {
             user_data_recv: rcpt_user_data,
             value_blinds: [value_recv_blind, value_send_blind],
             token_blinds: [token_recv_blind, token_send_blind],
-            coin: owncoin1,
+            coin: owncoin1.clone(),
             tree: wallet1.money_merkle_tree.clone(),
             mint_zkbin: mint_zkbin.clone(),
             mint_pk: mint_pk.clone(),
@@ -154,7 +154,7 @@ impl TestHarness {
 
     pub async fn execute_otc_swap_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyTransferParamsV1,
         slot: u64,

+ 10 - 10
src/contract/test-harness/src/money_token.rs

@@ -38,13 +38,13 @@ impl TestHarness {
     pub fn token_mint(
         &mut self,
         amount: u64,
-        holder: Holder,
-        recipient: Holder,
+        holder: &Holder,
+        recipient: &Holder,
         spend_hook: Option<pallas::Base>,
         user_data: Option<pallas::Base>,
     ) -> Result<(Transaction, MoneyTokenMintParamsV1)> {
-        let rcpt = self.holders.get(&recipient).unwrap().keypair.public;
-        let mint_authority = self.holders.get(&holder).unwrap().token_mint_authority;
+        let rcpt = self.holders.get(recipient).unwrap().keypair.public;
+        let mint_authority = self.holders.get(holder).unwrap().token_mint_authority;
         let (mint_pk, mint_zkbin) =
             self.proving_keys.get(&MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -85,12 +85,12 @@ impl TestHarness {
 
     pub async fn execute_token_mint_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyTokenMintParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyTokenMint).unwrap();
         let timer = Instant::now();
@@ -104,9 +104,9 @@ impl TestHarness {
 
     pub fn token_freeze(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
     ) -> Result<(Transaction, MoneyTokenFreezeParamsV1)> {
-        let mint_authority = self.holders.get(&holder).unwrap().token_mint_authority;
+        let mint_authority = self.holders.get(holder).unwrap().token_mint_authority;
         let (frz_pk, frz_zkbin) =
             self.proving_keys.get(&MONEY_CONTRACT_ZKAS_TOKEN_FRZ_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -143,12 +143,12 @@ impl TestHarness {
 
     pub async fn execute_token_freeze_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         _params: &MoneyTokenFreezeParamsV1,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyTokenFreeze).unwrap();
         let timer = Instant::now();

+ 10 - 37
src/contract/test-harness/src/money_transfer.rs

@@ -38,13 +38,13 @@ impl TestHarness {
     pub fn transfer(
         &mut self,
         amount: u64,
-        holder: Holder,
-        recipient: Holder,
+        holder: &Holder,
+        recipient: &Holder,
         owncoins: &[OwnCoin],
         token_id: TokenId,
     ) -> Result<(Transaction, MoneyTransferParamsV1, Vec<OwnCoin>)> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let rcpt = self.holders.get(&recipient).unwrap().keypair.public;
+        let wallet = self.holders.get(holder).unwrap();
+        let rcpt = self.holders.get(recipient).unwrap().keypair.public;
         let (mint_pk, mint_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_MINT_NS_V1).unwrap();
         let (burn_pk, burn_zkbin) = self.proving_keys.get(&MONEY_CONTRACT_ZKAS_BURN_NS_V1).unwrap();
         let tx_action_benchmark =
@@ -105,13 +105,13 @@ impl TestHarness {
 
     pub async fn execute_transfer_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         params: &MoneyTransferParamsV1,
         slot: u64,
         append: bool,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyTransfer).unwrap();
         let timer = Instant::now();
@@ -129,13 +129,13 @@ impl TestHarness {
 
     pub async fn execute_multiple_transfer_txs(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         txs: &[Transaction],
         txs_params: &Vec<MoneyTransferParamsV1>,
         slot: u64,
         append: bool,
     ) -> Result<()> {
-        let wallet = self.holders.get_mut(&holder).unwrap();
+        let wallet = self.holders.get_mut(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyTransfer).unwrap();
         let timer = Instant::now();
@@ -155,11 +155,11 @@ impl TestHarness {
 
     pub async fn verify_transfer_tx(
         &mut self,
-        holder: Holder,
+        holder: &Holder,
         tx: &Transaction,
         slot: u64,
     ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
+        let wallet = self.holders.get(holder).unwrap();
         let tx_action_benchmark =
             self.tx_action_benchmarks.get_mut(&TxAction::MoneyTransfer).unwrap();
         let timer = Instant::now();
@@ -169,31 +169,4 @@ impl TestHarness {
 
         Ok(())
     }
-
-    pub async fn execute_erroneous_transfer_tx(
-        &mut self,
-        holder: Holder,
-        txs: &[Transaction],
-        slot: u64,
-        erroneous: usize,
-    ) -> Result<()> {
-        let wallet = self.holders.get(&holder).unwrap();
-        let tx_action_benchmark =
-            self.tx_action_benchmarks.get_mut(&TxAction::MoneyTransfer).unwrap();
-        let timer = Instant::now();
-
-        let erroneous_txs = wallet
-            .validator
-            .read()
-            .await
-            .add_transactions(txs, slot, false)
-            .await
-            .err()
-            .unwrap()
-            .retrieve_erroneous_txs()?;
-        assert_eq!(erroneous_txs.len(), erroneous);
-        tx_action_benchmark.verify_times.push(timer.elapsed());
-
-        Ok(())
-    }
 }

+ 4 - 1
src/validator/proto/protocol_tx.rs

@@ -23,8 +23,9 @@ use smol::Executor;
 use url::Url;
 
 use crate::{
+    impl_p2p_message,
     net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
+        ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
         ProtocolJobsManager, ProtocolJobsManagerPtr,
     },
     tx::Transaction,
@@ -40,6 +41,8 @@ pub struct ProtocolTx {
     channel_address: Url,
 }
 
+impl_p2p_message!(Transaction, "tx");
+
 impl ProtocolTx {
     pub async fn init(
         channel: ChannelPtr,