Explorar el Código

contract: Remove async-std dependencies.

parazyd hace 3 años
padre
commit
478bfa2a00

+ 101 - 87
src/contract/consensus/tests/genesis_stake_unstake.rs

@@ -30,102 +30,116 @@ use log::info;
 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<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-    // Some numbers we want to assert
-    const ALICE_INITIAL: u64 = 1000;
-
-    // Slot to verify against
-    let mut current_slot = 0;
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
-
-    // 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)?;
-
-    // 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_txs(
-        TxAction::ConsensusGenesisStake,
-        &Holder::Alice,
-        &vec![genesis_stake_tx.clone(), genesis_stake_tx.clone()],
-        current_slot,
-        1,
-    )
-    .await?;
-
-    info!(target: "consensus", "[Malicious] =============================================");
-    info!(target: "consensus", "[Malicious] Checking genesis stake tx not on genesis slot");
-    info!(target: "consensus", "[Malicious] =============================================");
-    th.execute_erroneous_txs(
-        TxAction::ConsensusGenesisStake,
-        &Holder::Alice,
-        &vec![genesis_stake_tx.clone()],
-        current_slot + 1,
-        1,
-    )
-    .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?;
-    }
+#[test]
+fn consensus_contract_genesis_stake_unstake() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
+
+        // Some numbers we want to assert
+        const ALICE_INITIAL: u64 = 1000;
+
+        // Slot to verify against
+        let mut current_slot = 0;
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
+
+        // 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)?;
+
+        // 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_txs(
+            TxAction::ConsensusGenesisStake,
+            &Holder::Alice,
+            &vec![genesis_stake_tx.clone(), genesis_stake_tx.clone()],
+            current_slot,
+            1,
+        )
+        .await?;
 
-    th.assert_trees(&HOLDERS);
+        info!(target: "consensus", "[Malicious] =============================================");
+        info!(target: "consensus", "[Malicious] Checking genesis stake tx not on genesis slot");
+        info!(target: "consensus", "[Malicious] =============================================");
+        th.execute_erroneous_txs(
+            TxAction::ConsensusGenesisStake,
+            &Holder::Alice,
+            &vec![genesis_stake_tx.clone()],
+            current_slot + 1,
+            1,
+        )
+        .await?;
 
-    // Gather new staked owncoin
-    let alice_staked_oc =
-        th.gather_consensus_staked_owncoin(&Holder::Alice, &genesis_stake_params.output, None)?;
+        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?;
+        }
 
-    // Verify values match
-    assert!(ALICE_INITIAL == alice_staked_oc.note.value);
+        th.assert_trees(&HOLDERS);
 
-    // We simulate the proposal of genesis slot
-    // We progress 1 slot and simulate its proposal
-    current_slot += 1;
-    let slot = th.generate_slot(current_slot).await?;
+        // Gather new staked owncoin
+        let alice_staked_oc =
+            th.gather_consensus_staked_owncoin(&Holder::Alice, &genesis_stake_params.output, None)?;
 
-    // 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.
-    let alice_rewarded_staked_oc =
-        th.execute_proposal(&HOLDERS, &Holder::Alice, current_slot, slot, &alice_staked_oc).await?;
+        // Verify values match
+        assert!(ALICE_INITIAL == alice_staked_oc.note.value);
 
-    // We progress after grace period
-    current_slot += calculate_grace_period() * EPOCH_LENGTH;
-    th.generate_slot(current_slot).await?;
+        // We simulate the proposal of genesis slot
+        // We progress 1 slot and simulate its proposal
+        current_slot += 1;
+        let slot = th.generate_slot(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_rewarded_staked_oc)
-        .await?;
+        // 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.
+        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
+        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;
+        // We progress after grace period
+        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
 
-    // Now Alice can unstake her owncoin
-    th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc).await?;
+        // Now Alice can unstake her owncoin
+        th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
+            .await?;
 
-    // Statistics
-    th.statistics();
+        // Statistics
+        th.statistics();
 
-    // Thanks for reading
-    Ok(())
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 187 - 175
src/contract/consensus/tests/stake_unstake.rs

@@ -38,190 +38,202 @@ 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<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-    // Some numbers we want to assert
-    const ALICE_AIRDROP: u64 = 1000;
-
-    // Slot to verify against
-    let mut current_slot = 1;
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
-
-    // Now Alice can airdrop some native tokens to herself
-    let alice_oc =
-        th.execute_airdrop(&HOLDERS, &Holder::Alice, ALICE_AIRDROP, current_slot).await?;
-
-    // Now Alice can stake her owncoin
-    let alice_staked_oc =
-        th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 489).await?;
-
-    // We progress after grace period
-    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-    let slot = th.generate_slot(current_slot).await?;
-
-    // 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.
-    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
-    let alice_unstake_request_oc = th
-        .execute_unstake_request(&HOLDERS, &Holder::Alice, current_slot, &alice_rewarded_staked_oc)
+#[test]
+fn consensus_contract_stake_unstake() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
+
+        // Some numbers we want to assert
+        const ALICE_AIRDROP: u64 = 1000;
+
+        // Slot to verify against
+        let mut current_slot = 1;
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string(), "consensus".to_string()]).await?;
+
+        // Now Alice can airdrop some native tokens to herself
+        let alice_oc =
+            th.execute_airdrop(&HOLDERS, &Holder::Alice, ALICE_AIRDROP, current_slot).await?;
+
+        // Now Alice can stake her owncoin
+        let alice_staked_oc =
+            th.execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_oc, 489).await?;
+
+        // We progress after grace period
+        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+        let slot = th.generate_slot(current_slot).await?;
+
+        // 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.
+        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
+        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, 15)
+            .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(15))
+            .await?;
+        th.execute_erroneous_txs(
+            TxAction::ConsensusStake,
+            &Holder::Alice,
+            &vec![stake_tx],
+            current_slot,
+            1,
+        )
         .await?;
 
-    // We progress after grace period
-    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+        // 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?;
 
-    // Now Alice can unstake her owncoin
-    let alice_unstaked_oc = th
-        .execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
+        // 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?;
 
-    // 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, 15).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(15)).await?;
-    th.execute_erroneous_txs(
-        TxAction::ConsensusStake,
-        &Holder::Alice,
-        &vec![stake_tx],
-        current_slot,
-        1,
-    )
-    .await?;
-
-    // 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?;
-
-    // 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?;
-
-    // We progress after grace period
-    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-    // 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)
+        // We progress after grace period
+        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+
+        // 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", "[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 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?;
-
-    // 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)
+        // 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_tx, _, _) = th.unstake(&Holder::Alice, &alice_unstake_request_oc)?;
+        th.execute_erroneous_txs(
+            TxAction::ConsensusUnstake,
+            &Holder::Alice,
+            &vec![unstake_tx],
+            current_slot,
+            1,
+        )
         .await?;
 
-    info!(target: "consensus", "[Malicious] =============================");
-    info!(target: "consensus", "[Malicious] Checking unstaking coin again");
-    info!(target: "consensus", "[Malicious] =============================");
-    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, 65).await?;
-
-    // We progress after grace period
-    current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
-
-    // 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)
+        // Now Alice can stake her unstaked owncoin again
+        let alice_staked_oc = th
+            .execute_stake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstaked_oc, 65)
+            .await?;
+
+        // We progress after grace period
+        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+
+        // 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
+        current_slot += 1;
+        let slot = th.generate_slot(current_slot).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_staked_oc).await?;
+        th.execute_erroneous_txs(
+            TxAction::ConsensusProposal,
+            &Holder::Alice,
+            &vec![proposal_tx],
+            current_slot,
+            1,
+        )
         .await?;
 
-    // Now we will test if we can reuse token in proposal
-    current_slot += 1;
-    let slot = th.generate_slot(current_slot).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_staked_oc).await?;
-    th.execute_erroneous_txs(
-        TxAction::ConsensusProposal,
-        &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
-    th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc).await?;
-
-    // Statistics
-    th.statistics();
-
-    // Thanks for reading
-    Ok(())
+        // We progress after grace period
+        current_slot += (calculate_grace_period() * EPOCH_LENGTH) + EPOCH_LENGTH;
+
+        // Now Alice can unstake her owncoin
+        th.execute_unstake(&HOLDERS, &Holder::Alice, current_slot, &alice_unstake_request_oc)
+            .await?;
+
+        // Statistics
+        th.statistics();
+
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 304 - 292
src/contract/dao/tests/integration.rs

@@ -29,298 +29,310 @@ use darkfi_sdk::{
 use log::info;
 use rand::rngs::OsRng;
 
-#[async_std::test]
-async fn integration_test() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use:
-    // * Faucet airdrops DRK
-    // * Alice, Bob, and Charlie are members of the DAO.
-    // * Rachel is the proposal recipient.
-    // * Dao is the DAO wallet
-    const HOLDERS: [Holder; 6] =
-        [Holder::Faucet, Holder::Alice, Holder::Bob, Holder::Charlie, Holder::Rachel, Holder::Dao];
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string(), "dao".to_string()]).await?;
-
-    // We'll use the ALICE token as the DAO governance token
-    let gov_token_id = th.token_id(&Holder::Alice);
-    const ALICE_GOV_SUPPLY: u64 = 100_000_000;
-    const BOB_GOV_SUPPLY: u64 = 100_000_000;
-    const CHARLIE_GOV_SUPPLY: u64 = 100_000_000;
-    // And the DRK token as the treasury token
-    let drk_token_id = *DARK_TOKEN_ID;
-    const DRK_TOKEN_SUPPLY: u64 = 1_000_000_000;
-    // The tokens we want to send via the proposal
-    const PROPOSAL_AMOUNT: u64 = 250_000_000;
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // DAO parameters
-    let dao_keypair = th.holders.get(&Holder::Dao).unwrap().keypair;
-    let dao = DaoInfo {
-        proposer_limit: 100_000_000,
-        quorum: 199_999_999,
-        approval_ratio_base: 2,
-        approval_ratio_quot: 1,
-        gov_token_id,
-        public_key: dao_keypair.public,
-        bulla_blind: pallas::Base::random(&mut OsRng),
-    };
-
-    // ====================
-    // Dao::Mint
-    // Create the DAO bulla
-    // ====================
-    info!("Stage 1. Creating DAO bulla");
-
-    info!("[Dao] Building DAO mint tx");
-    let (dao_mint_tx, dao_mint_params) = th.dao_mint(&dao, &dao_keypair)?;
-
-    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?;
-    }
-
-    th.assert_trees(&HOLDERS);
-
-    // =======================================
-    // Airdrop some treasury tokens to the DAO
-    // =======================================
-    info!("Stage 2. Send Treasury token");
-
-    info!("[Faucet] Building DAO airdrop tx");
-    let (airdrop_tx, airdrop_params) = th.airdrop_native(
-        DRK_TOKEN_SUPPLY,
-        &Holder::Dao,
-        Some(DAO_CONTRACT_ID.inner()),           // spend_hook
-        Some(dao_mint_params.dao_bulla.inner()), // user_data
-        None,
-        None,
-    )?;
-
-    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], None)?;
-
-    // ======================================
-    // Mint the governance token to 3 holders
-    // ======================================
-    info!("Stage 3. Minting governance token");
-
-    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)?;
-
-    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)?;
-
-    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)?;
-
-    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)?;
-
-    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)?;
-
-    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)?;
-
-    // ================
-    // Dao::Propose
-    // Propose the vote
-    // ================
-    info!("Stage 4. Propose the vote");
-    // TODO: look into proposal expiry once time for voting has finished
-    // TODO: Is it possible for an invalid transfer() to be constructed on exec()?
-    //       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,
-        PROPOSAL_AMOUNT,
-        drk_token_id,
-        &dao,
-        &dao_mint_params.dao_bulla,
-    )?;
-
-    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);
-
-    // =====================================
-    // Dao::Vote
-    // Proposal is accepted. Start the vote.
-    // =====================================
-    info!("Stage 5. Start voting");
-
-    info!("[Alice] Building vote tx (yes)");
-    let (alice_vote_tx, alice_vote_params) = th.dao_vote(
-        &Holder::Alice,
-        &dao_keypair,
-        true,
-        &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,
-        &dao_keypair,
-        false,
-        &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,
-        &dao_keypair,
-        true,
-        &dao,
-        &propose_info,
-        &propose_params.proposal_bulla,
-    )?;
-
-    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();
-    let vote_note_2: DaoVoteNote = bob_vote_params.note.decrypt(&dao_keypair.secret).unwrap();
-    let vote_note_3: DaoVoteNote = charlie_vote_params.note.decrypt(&dao_keypair.secret).unwrap();
-
-    // Count the votes
-    let mut total_yes_vote_value = 0;
-    let mut total_all_vote_value = 0;
-    let mut blind_total_vote = DaoBlindAggregateVote::default();
-    let mut total_yes_vote_blind = pallas::Scalar::ZERO;
-    let mut total_all_vote_blind = pallas::Scalar::ZERO;
-
-    for (i, note) in [vote_note_1, vote_note_2, vote_note_3].iter().enumerate() {
-        total_yes_vote_blind += note.yes_vote_blind;
-        total_all_vote_blind += note.all_vote_blind;
-
-        // Update private values
-        // vote_option is either 0 or 1
-        let yes_vote_value = note.vote_option as u64 * note.all_vote_value;
-        total_yes_vote_value += yes_vote_value;
-        total_all_vote_value += note.all_vote_value;
-
-        // Update public values
-        let yes_vote_commit = pedersen_commitment_u64(yes_vote_value, note.yes_vote_blind);
-        let all_vote_commit = pedersen_commitment_u64(note.all_vote_value, note.all_vote_blind);
-        let blind_vote = DaoBlindAggregateVote { yes_vote_commit, all_vote_commit };
-        blind_total_vote.aggregate(blind_vote);
-
-        // Just for the debug
-        let vote_result = match note.vote_option {
-            true => "yes",
-            false => "no",
+#[test]
+fn integration_test() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use:
+        // * Faucet airdrops DRK
+        // * Alice, Bob, and Charlie are members of the DAO.
+        // * Rachel is the proposal recipient.
+        // * Dao is the DAO wallet
+        const HOLDERS: [Holder; 6] = [
+            Holder::Faucet,
+            Holder::Alice,
+            Holder::Bob,
+            Holder::Charlie,
+            Holder::Rachel,
+            Holder::Dao,
+        ];
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string(), "dao".to_string()]).await?;
+
+        // We'll use the ALICE token as the DAO governance token
+        let gov_token_id = th.token_id(&Holder::Alice);
+        const ALICE_GOV_SUPPLY: u64 = 100_000_000;
+        const BOB_GOV_SUPPLY: u64 = 100_000_000;
+        const CHARLIE_GOV_SUPPLY: u64 = 100_000_000;
+        // And the DRK token as the treasury token
+        let drk_token_id = *DARK_TOKEN_ID;
+        const DRK_TOKEN_SUPPLY: u64 = 1_000_000_000;
+        // The tokens we want to send via the proposal
+        const PROPOSAL_AMOUNT: u64 = 250_000_000;
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // DAO parameters
+        let dao_keypair = th.holders.get(&Holder::Dao).unwrap().keypair;
+        let dao = DaoInfo {
+            proposer_limit: 100_000_000,
+            quorum: 199_999_999,
+            approval_ratio_base: 2,
+            approval_ratio_quot: 1,
+            gov_token_id,
+            public_key: dao_keypair.public,
+            bulla_blind: pallas::Base::random(&mut OsRng),
         };
 
-        info!("Voter {} voted {} with {} tokens", i, vote_result, note.all_vote_value);
-    }
-
-    info!("Outcome = {} / {}", total_yes_vote_value, total_all_vote_value);
-
-    assert!(
-        blind_total_vote.all_vote_commit ==
-            pedersen_commitment_u64(total_all_vote_value, total_all_vote_blind)
-    );
-
-    assert!(
-        blind_total_vote.yes_vote_commit ==
-            pedersen_commitment_u64(total_yes_vote_value, total_yes_vote_blind)
-    );
-
-    // ================
-    // Dao::Exec
-    // Execute the vote
-    // ================
-    info!("Stage 6. Execute the vote");
-
-    info!("[Dao] Building Dao::Exec tx");
-    let (exec_tx, xfer_params, exec_params) = th.dao_exec(
-        &dao,
-        &dao_mint_params.dao_bulla,
-        &propose_info,
-        total_yes_vote_value,
-        total_all_vote_value,
-        total_yes_vote_blind,
-        total_all_vote_blind,
-    )?;
-
-    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], 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);
-    assert!(rachel_wallet.unspent_money_coins[0].note.token_id == drk_token_id);
-
-    // FIXME: The harness doesn't register that we spent the first coin on the proposal.
-    let dao_wallet = th.holders.get(&Holder::Dao).unwrap();
-    assert!(dao_wallet.unspent_money_coins[1].note.value == DRK_TOKEN_SUPPLY - PROPOSAL_AMOUNT);
-    assert!(dao_wallet.unspent_money_coins[1].note.token_id == drk_token_id);
-
-    // Stats
-    th.statistics();
-
-    // Thanks for reading
-    Ok(())
+        // ====================
+        // Dao::Mint
+        // Create the DAO bulla
+        // ====================
+        info!("Stage 1. Creating DAO bulla");
+
+        info!("[Dao] Building DAO mint tx");
+        let (dao_mint_tx, dao_mint_params) = th.dao_mint(&dao, &dao_keypair)?;
+
+        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?;
+        }
+
+        th.assert_trees(&HOLDERS);
+
+        // =======================================
+        // Airdrop some treasury tokens to the DAO
+        // =======================================
+        info!("Stage 2. Send Treasury token");
+
+        info!("[Faucet] Building DAO airdrop tx");
+        let (airdrop_tx, airdrop_params) = th.airdrop_native(
+            DRK_TOKEN_SUPPLY,
+            &Holder::Dao,
+            Some(DAO_CONTRACT_ID.inner()),           // spend_hook
+            Some(dao_mint_params.dao_bulla.inner()), // user_data
+            None,
+            None,
+        )?;
+
+        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], None)?;
+
+        // ======================================
+        // Mint the governance token to 3 holders
+        // ======================================
+        info!("Stage 3. Minting governance token");
+
+        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)?;
+
+        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)?;
+
+        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)?;
+
+        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)?;
+
+        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)?;
+
+        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)?;
+
+        // ================
+        // Dao::Propose
+        // Propose the vote
+        // ================
+        info!("Stage 4. Propose the vote");
+        // TODO: look into proposal expiry once time for voting has finished
+        // TODO: Is it possible for an invalid transfer() to be constructed on exec()?
+        //       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,
+            PROPOSAL_AMOUNT,
+            drk_token_id,
+            &dao,
+            &dao_mint_params.dao_bulla,
+        )?;
+
+        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);
+
+        // =====================================
+        // Dao::Vote
+        // Proposal is accepted. Start the vote.
+        // =====================================
+        info!("Stage 5. Start voting");
+
+        info!("[Alice] Building vote tx (yes)");
+        let (alice_vote_tx, alice_vote_params) = th.dao_vote(
+            &Holder::Alice,
+            &dao_keypair,
+            true,
+            &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,
+            &dao_keypair,
+            false,
+            &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,
+            &dao_keypair,
+            true,
+            &dao,
+            &propose_info,
+            &propose_params.proposal_bulla,
+        )?;
+
+        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();
+        let vote_note_2: DaoVoteNote = bob_vote_params.note.decrypt(&dao_keypair.secret).unwrap();
+        let vote_note_3: DaoVoteNote =
+            charlie_vote_params.note.decrypt(&dao_keypair.secret).unwrap();
+
+        // Count the votes
+        let mut total_yes_vote_value = 0;
+        let mut total_all_vote_value = 0;
+        let mut blind_total_vote = DaoBlindAggregateVote::default();
+        let mut total_yes_vote_blind = pallas::Scalar::ZERO;
+        let mut total_all_vote_blind = pallas::Scalar::ZERO;
+
+        for (i, note) in [vote_note_1, vote_note_2, vote_note_3].iter().enumerate() {
+            total_yes_vote_blind += note.yes_vote_blind;
+            total_all_vote_blind += note.all_vote_blind;
+
+            // Update private values
+            // vote_option is either 0 or 1
+            let yes_vote_value = note.vote_option as u64 * note.all_vote_value;
+            total_yes_vote_value += yes_vote_value;
+            total_all_vote_value += note.all_vote_value;
+
+            // Update public values
+            let yes_vote_commit = pedersen_commitment_u64(yes_vote_value, note.yes_vote_blind);
+            let all_vote_commit = pedersen_commitment_u64(note.all_vote_value, note.all_vote_blind);
+            let blind_vote = DaoBlindAggregateVote { yes_vote_commit, all_vote_commit };
+            blind_total_vote.aggregate(blind_vote);
+
+            // Just for the debug
+            let vote_result = match note.vote_option {
+                true => "yes",
+                false => "no",
+            };
+
+            info!("Voter {} voted {} with {} tokens", i, vote_result, note.all_vote_value);
+        }
+
+        info!("Outcome = {} / {}", total_yes_vote_value, total_all_vote_value);
+
+        assert!(
+            blind_total_vote.all_vote_commit ==
+                pedersen_commitment_u64(total_all_vote_value, total_all_vote_blind)
+        );
+
+        assert!(
+            blind_total_vote.yes_vote_commit ==
+                pedersen_commitment_u64(total_yes_vote_value, total_yes_vote_blind)
+        );
+
+        // ================
+        // Dao::Exec
+        // Execute the vote
+        // ================
+        info!("Stage 6. Execute the vote");
+
+        info!("[Dao] Building Dao::Exec tx");
+        let (exec_tx, xfer_params, exec_params) = th.dao_exec(
+            &dao,
+            &dao_mint_params.dao_bulla,
+            &propose_info,
+            total_yes_vote_value,
+            total_all_vote_value,
+            total_yes_vote_blind,
+            total_all_vote_blind,
+        )?;
+
+        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], 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);
+        assert!(rachel_wallet.unspent_money_coins[0].note.token_id == drk_token_id);
+
+        // FIXME: The harness doesn't register that we spent the first coin on the proposal.
+        let dao_wallet = th.holders.get(&Holder::Dao).unwrap();
+        assert!(dao_wallet.unspent_money_coins[1].note.value == DRK_TOKEN_SUPPLY - PROPOSAL_AMOUNT);
+        assert!(dao_wallet.unspent_money_coins[1].note.token_id == drk_token_id);
+
+        // Stats
+        th.statistics();
+
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 182 - 167
src/contract/money/tests/genesis_mint.rs

@@ -30,173 +30,188 @@ use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
 use darkfi_sdk::crypto::DARK_TOKEN_ID;
 use log::info;
 
-#[async_std::test]
-async fn genesis_mint() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
-
-    // Some numbers we want to assert
-    const ALICE_INITIAL: u64 = 100;
-    const BOB_INITIAL: u64 = 200;
-
-    // Alice = 50 DARK
-    // Bob = 250 DARK
-    const ALICE_SEND: u64 = ALICE_INITIAL - 50;
-    // Alice = 230 DARK
-    // Bob = 50
-    const BOB_SEND: u64 = BOB_INITIAL - 20;
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string()]).await?;
-
-    let mut alice_owncoins = vec![];
-    let mut bob_owncoins = vec![];
-
-    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)?;
-
-    // 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_txs(
-        TxAction::MoneyGenesisMint,
-        &Holder::Alice,
-        &vec![genesis_mint_tx.clone(), genesis_mint_tx.clone()],
-        current_slot,
-        1,
-    )
-    .await?;
-
-    info!(target: "money", "[Malicious] ============================================");
-    info!(target: "money", "[Malicious] Checking genesis mint tx not on genesis slot");
-    info!(target: "money", "[Malicious] ============================================");
-    th.execute_erroneous_txs(
-        TxAction::MoneyGenesisMint,
-        &Holder::Alice,
-        &vec![genesis_mint_tx.clone()],
-        current_slot + 1,
-        1,
-    )
-    .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)
+#[test]
+fn genesis_mint() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
+
+        // Some numbers we want to assert
+        const ALICE_INITIAL: u64 = 100;
+        const BOB_INITIAL: u64 = 200;
+
+        // Alice = 50 DARK
+        // Bob = 250 DARK
+        const ALICE_SEND: u64 = ALICE_INITIAL - 50;
+        // Alice = 230 DARK
+        // Bob = 50
+        const BOB_SEND: u64 = BOB_INITIAL - 20;
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string()]).await?;
+
+        let mut alice_owncoins = vec![];
+        let mut bob_owncoins = vec![];
+
+        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)?;
+
+        // 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_txs(
+            TxAction::MoneyGenesisMint,
+            &Holder::Alice,
+            &vec![genesis_mint_tx.clone(), genesis_mint_tx.clone()],
+            current_slot,
+            1,
+        )
+        .await?;
+
+        info!(target: "money", "[Malicious] ============================================");
+        info!(target: "money", "[Malicious] Checking genesis mint tx not on genesis slot");
+        info!(target: "money", "[Malicious] ============================================");
+        th.execute_erroneous_txs(
+            TxAction::MoneyGenesisMint,
+            &Holder::Alice,
+            &vec![genesis_mint_tx.clone()],
+            current_slot + 1,
+            1,
+        )
+        .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)?;
-    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)?;
-
-    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)
+        }
+
+        th.assert_trees(&HOLDERS);
+
+        // Alice gathers her new owncoin
+        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)?;
+
+        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)?;
-    bob_owncoins.push(bob_oc);
-
-    // Now Alice can send a little bit of funds to Bob
-    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_SEND, &Holder::Alice, &Holder::Bob, &alice_owncoins, *DARK_TOKEN_ID)?;
-
-    // Validating transfer params
-    assert!(transfer_params.inputs.len() == 1);
-    assert!(transfer_params.outputs.len() == 2);
-    assert!(spent_coins.len() == 1);
-    alice_owncoins.retain(|x| x != &spent_coins[0]);
-    assert!(alice_owncoins.is_empty());
-
-    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], 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], None)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(alice_owncoins.len() == 1);
-    assert!(bob_owncoins.len() == 2);
-
-    // Bob can send a little bit to Alice as well
-    info!(target: "money", "[Bob] ======================================================");
-    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)?;
-
-    // Validating transfer params
-    assert!(transfer_params.inputs.len() == 1);
-    assert!(transfer_params.outputs.len() == 2);
-    assert!(spent_coins.len() == 1);
-    bob_owncoins.retain(|x| x != &spent_coins[0]);
-    assert!(bob_owncoins.len() == 1);
-
-    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], 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], None)?;
-    bob_owncoins.push(bob_oc);
-
-    // Validating transaction outcomes
-    assert!(alice_owncoins.len() == 2);
-    assert!(bob_owncoins.len() == 2);
-    assert!(alice_owncoins[0].note.value == ALICE_INITIAL - ALICE_SEND);
-    assert!(alice_owncoins[1].note.value == BOB_SEND);
-    assert!(bob_owncoins[0].note.value == ALICE_SEND);
-    assert!(bob_owncoins[1].note.value == BOB_INITIAL - BOB_SEND);
-
-    // Statistics
-    th.statistics();
-
-    // Thanks for reading
-    Ok(())
+        }
+
+        th.assert_trees(&HOLDERS);
+
+        // Bob gathers his new owncoin
+        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
+        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_SEND, &Holder::Alice, &Holder::Bob, &alice_owncoins, *DARK_TOKEN_ID)?;
+
+        // Validating transfer params
+        assert!(transfer_params.inputs.len() == 1);
+        assert!(transfer_params.outputs.len() == 2);
+        assert!(spent_coins.len() == 1);
+        alice_owncoins.retain(|x| x != &spent_coins[0]);
+        assert!(alice_owncoins.is_empty());
+
+        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], 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], None)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(alice_owncoins.len() == 1);
+        assert!(bob_owncoins.len() == 2);
+
+        // Bob can send a little bit to Alice as well
+        info!(target: "money", "[Bob] ======================================================");
+        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)?;
+
+        // Validating transfer params
+        assert!(transfer_params.inputs.len() == 1);
+        assert!(transfer_params.outputs.len() == 2);
+        assert!(spent_coins.len() == 1);
+        bob_owncoins.retain(|x| x != &spent_coins[0]);
+        assert!(bob_owncoins.len() == 1);
+
+        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], 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], None)?;
+        bob_owncoins.push(bob_oc);
+
+        // Validating transaction outcomes
+        assert!(alice_owncoins.len() == 2);
+        assert!(bob_owncoins.len() == 2);
+        assert!(alice_owncoins[0].note.value == ALICE_INITIAL - ALICE_SEND);
+        assert!(alice_owncoins[1].note.value == BOB_SEND);
+        assert!(bob_owncoins[0].note.value == ALICE_SEND);
+        assert!(bob_owncoins[1].note.value == BOB_INITIAL - BOB_SEND);
+
+        // Statistics
+        th.statistics();
+
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 318 - 306
src/contract/money/tests/mint_pay_swap.rs

@@ -31,310 +31,322 @@ use darkfi::Result;
 use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
 use log::info;
 
-#[async_std::test]
-async fn mint_pay_swap() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
-
-    // Some numbers we want to assert
-    const ALICE_INITIAL: u64 = 100;
-    const BOB_INITIAL: u64 = 200;
-
-    // Alice = 50 ALICE
-    // Bob = 200 BOB + 50 ALICE
-    const ALICE_FIRST_SEND: u64 = ALICE_INITIAL - 50;
-    // Alice = 50 ALICE + 180 BOB
-    // Bob = 20 BOB + 50 ALICE
-    const BOB_FIRST_SEND: u64 = BOB_INITIAL - 20;
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string()]).await?;
-
-    let mut alice_owncoins = vec![];
-    let mut bob_owncoins = vec![];
-
-    info!(target: "money", "[Alice] ================================");
-    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)?;
-
-    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_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)?;
-
-    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_token_id = bob_oc.note.token_id;
-    bob_owncoins.push(bob_oc);
-
-    // Now Alice can send a little bit of funds to Bob
-    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,
-    )?;
-
-    // Validating transfer params
-    assert!(transfer_params.inputs.len() == 1);
-    assert!(transfer_params.outputs.len() == 2);
-    assert!(spent_coins.len() == 1);
-    alice_owncoins.retain(|x| x != &spent_coins[0]);
-    assert!(alice_owncoins.is_empty());
-
-    for holder in &HOLDERS {
-        info!(target: "money", "[{holder:?}] ==============================");
-        info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
-        info!(target: "money", "[{holder:?}] ==============================");
-        let write = holder == &Holder::Faucet;
-        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, write).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)?;
-    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)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(alice_owncoins.len() == 1);
-    assert!(bob_owncoins.len() == 2);
-
-    th.assert_trees(&HOLDERS);
-
-    // Bob can send a little bit to Alice as well
-    info!(target: "money", "[Bob] ======================================================");
-    info!(target: "money", "[Bob] Building Money::Transfer params for a payment to Alice");
-    info!(target: "money", "[Bob] ======================================================");
-    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)?;
-
-    // Validating transfer params
-    assert!(transfer_params.inputs.len() == 1);
-    assert!(transfer_params.outputs.len() == 2);
-    assert!(spent_coins.len() == 1);
-    bob_owncoins.retain(|x| x != &spent_coins[0]);
-    assert!(bob_owncoins.len() == 1);
-
-    for holder in &HOLDERS {
-        info!(target: "money", "[{holder:?}] ==============================");
-        info!(target: "money", "[{holder:?}] Executing Bob2Alice payment tx");
-        info!(target: "money", "[{holder:?}] ==============================");
-        let write = holder == &Holder::Faucet;
-        th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, write).await?;
-    }
-
-    // Alice should now have two OwnCoins
-    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)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(alice_owncoins.len() == 2);
-    assert!(bob_owncoins.len() == 2);
-
-    assert!(alice_owncoins[0].note.value == ALICE_INITIAL - ALICE_FIRST_SEND);
-    assert!(alice_owncoins[0].note.token_id == alice_token_id);
-    assert!(alice_owncoins[1].note.value == BOB_FIRST_SEND);
-    assert!(alice_owncoins[1].note.token_id == bob_token_id);
-
-    assert!(bob_owncoins[0].note.value == ALICE_FIRST_SEND);
-    assert!(bob_owncoins[0].note.token_id == alice_token_id);
-    assert!(bob_owncoins[1].note.value == BOB_INITIAL - BOB_FIRST_SEND);
-    assert!(bob_owncoins[1].note.token_id == bob_token_id);
-
-    th.assert_trees(&HOLDERS);
-
-    // Alice and Bob decide to swap back their tokens so Alice gets back her initial
-    // tokens and Bob gets his.
-    info!(target: "money", "[Alice, Bob] ================");
-    info!(target: "money", "[Alice, Bob] Building OtcSwap");
-    info!(target: "money", "[Alice, Bob] ================");
-    let alice_oc = alice_owncoins[1].clone();
-    alice_owncoins.remove(1);
-    assert!(alice_owncoins.len() == 1);
-    let bob_oc = bob_owncoins[0].clone();
-    bob_owncoins.remove(0);
-    assert!(bob_owncoins.len() == 1);
-
-    let (otc_swap_tx, otc_swap_params) =
-        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:?}] ==========================");
-        let write = holder == &Holder::Faucet;
-        th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, write).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)?;
-    alice_owncoins.push(alice_oc);
-
-    assert!(alice_owncoins.len() == 2);
-    assert!(alice_owncoins[0].note.token_id == alice_token_id);
-    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)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(bob_owncoins.len() == 2);
-    assert!(bob_owncoins[0].note.token_id == bob_token_id);
-    assert!(bob_owncoins[1].note.token_id == bob_token_id);
-
-    th.assert_trees(&HOLDERS);
-
-    // Now Alice will create a new coin for herself to combine the two owncoins.
-    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,
-    )?;
-
-    for coin in spent_coins {
-        alice_owncoins.retain(|x| x != &coin);
-    }
-    assert!(alice_owncoins.is_empty());
-    assert!(params.inputs.len() == 2);
-    assert!(params.outputs.len() == 1);
-
-    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], None)?;
-    alice_owncoins.push(alice_oc);
-
-    assert!(alice_owncoins.len() == 1);
-    assert!(alice_owncoins[0].note.value == ALICE_INITIAL);
-    assert!(alice_owncoins[0].note.token_id == alice_token_id);
-
-    // Bob does the same
-    info!(target: "money", "[Bob] ====================================================");
-    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)?;
-
-    for coin in spent_coins {
-        bob_owncoins.retain(|x| x != &coin);
-    }
-    assert!(bob_owncoins.is_empty());
-    assert!(params.inputs.len() == 2);
-    assert!(params.outputs.len() == 1);
-
-    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], None)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(bob_owncoins.len() == 1);
-    assert!(bob_owncoins[0].note.value == BOB_INITIAL);
-    assert!(bob_owncoins[0].note.token_id == bob_token_id);
-
-    // Now they decide to swap all of their tokens
-    info!(target: "money", "[Alice, Bob] ================");
-    info!(target: "money", "[Alice, Bob] Building OtcSwap");
-    info!(target: "money", "[Alice, Bob] ================");
-    let alice_oc = alice_owncoins[0].clone();
-    alice_owncoins.remove(0);
-    assert!(alice_owncoins.is_empty());
-    let bob_oc = bob_owncoins[0].clone();
-    bob_owncoins.remove(0);
-    assert!(bob_owncoins.is_empty());
-
-    let (otc_swap_tx, otc_swap_params) =
-        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:?}] ==========================");
-        let write = holder == &Holder::Faucet;
-        th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, write).await?;
-    }
-
-    // Alice should now have Bob's BOB tokens
-    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);
-    assert!(alice_owncoins[0].note.value == BOB_INITIAL);
-    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)?;
-    bob_owncoins.push(bob_oc);
-
-    assert!(bob_owncoins.len() == 1);
-    assert!(bob_owncoins[0].note.value == ALICE_INITIAL);
-    assert!(bob_owncoins[0].note.token_id == alice_token_id);
-
-    th.assert_trees(&HOLDERS);
-
-    // Statistics
-    th.statistics();
-
-    // Thanks for reading
-    Ok(())
+#[test]
+fn mint_pay_swap() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
+
+        // Some numbers we want to assert
+        const ALICE_INITIAL: u64 = 100;
+        const BOB_INITIAL: u64 = 200;
+
+        // Alice = 50 ALICE
+        // Bob = 200 BOB + 50 ALICE
+        const ALICE_FIRST_SEND: u64 = ALICE_INITIAL - 50;
+        // Alice = 50 ALICE + 180 BOB
+        // Bob = 20 BOB + 50 ALICE
+        const BOB_FIRST_SEND: u64 = BOB_INITIAL - 20;
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string()]).await?;
+
+        let mut alice_owncoins = vec![];
+        let mut bob_owncoins = vec![];
+
+        info!(target: "money", "[Alice] ================================");
+        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)?;
+
+        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_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)?;
+
+        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_token_id = bob_oc.note.token_id;
+        bob_owncoins.push(bob_oc);
+
+        // Now Alice can send a little bit of funds to Bob
+        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,
+        )?;
+
+        // Validating transfer params
+        assert!(transfer_params.inputs.len() == 1);
+        assert!(transfer_params.outputs.len() == 2);
+        assert!(spent_coins.len() == 1);
+        alice_owncoins.retain(|x| x != &spent_coins[0]);
+        assert!(alice_owncoins.is_empty());
+
+        for holder in &HOLDERS {
+            info!(target: "money", "[{holder:?}] ==============================");
+            info!(target: "money", "[{holder:?}] Executing Alice2Bob payment tx");
+            info!(target: "money", "[{holder:?}] ==============================");
+            let write = holder == &Holder::Faucet;
+            th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, write)
+                .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)?;
+        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)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(alice_owncoins.len() == 1);
+        assert!(bob_owncoins.len() == 2);
+
+        th.assert_trees(&HOLDERS);
+
+        // Bob can send a little bit to Alice as well
+        info!(target: "money", "[Bob] ======================================================");
+        info!(target: "money", "[Bob] Building Money::Transfer params for a payment to Alice");
+        info!(target: "money", "[Bob] ======================================================");
+        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,
+        )?;
+
+        // Validating transfer params
+        assert!(transfer_params.inputs.len() == 1);
+        assert!(transfer_params.outputs.len() == 2);
+        assert!(spent_coins.len() == 1);
+        bob_owncoins.retain(|x| x != &spent_coins[0]);
+        assert!(bob_owncoins.len() == 1);
+
+        for holder in &HOLDERS {
+            info!(target: "money", "[{holder:?}] ==============================");
+            info!(target: "money", "[{holder:?}] Executing Bob2Alice payment tx");
+            info!(target: "money", "[{holder:?}] ==============================");
+            let write = holder == &Holder::Faucet;
+            th.execute_transfer_tx(holder, &transfer_tx, &transfer_params, current_slot, write)
+                .await?;
+        }
+
+        // Alice should now have two OwnCoins
+        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)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(alice_owncoins.len() == 2);
+        assert!(bob_owncoins.len() == 2);
+
+        assert!(alice_owncoins[0].note.value == ALICE_INITIAL - ALICE_FIRST_SEND);
+        assert!(alice_owncoins[0].note.token_id == alice_token_id);
+        assert!(alice_owncoins[1].note.value == BOB_FIRST_SEND);
+        assert!(alice_owncoins[1].note.token_id == bob_token_id);
+
+        assert!(bob_owncoins[0].note.value == ALICE_FIRST_SEND);
+        assert!(bob_owncoins[0].note.token_id == alice_token_id);
+        assert!(bob_owncoins[1].note.value == BOB_INITIAL - BOB_FIRST_SEND);
+        assert!(bob_owncoins[1].note.token_id == bob_token_id);
+
+        th.assert_trees(&HOLDERS);
+
+        // Alice and Bob decide to swap back their tokens so Alice gets back her initial
+        // tokens and Bob gets his.
+        info!(target: "money", "[Alice, Bob] ================");
+        info!(target: "money", "[Alice, Bob] Building OtcSwap");
+        info!(target: "money", "[Alice, Bob] ================");
+        let alice_oc = alice_owncoins[1].clone();
+        alice_owncoins.remove(1);
+        assert!(alice_owncoins.len() == 1);
+        let bob_oc = bob_owncoins[0].clone();
+        bob_owncoins.remove(0);
+        assert!(bob_owncoins.len() == 1);
+
+        let (otc_swap_tx, otc_swap_params) =
+            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:?}] ==========================");
+            let write = holder == &Holder::Faucet;
+            th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, write)
+                .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)?;
+        alice_owncoins.push(alice_oc);
+
+        assert!(alice_owncoins.len() == 2);
+        assert!(alice_owncoins[0].note.token_id == alice_token_id);
+        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)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(bob_owncoins.len() == 2);
+        assert!(bob_owncoins[0].note.token_id == bob_token_id);
+        assert!(bob_owncoins[1].note.token_id == bob_token_id);
+
+        th.assert_trees(&HOLDERS);
+
+        // Now Alice will create a new coin for herself to combine the two owncoins.
+        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,
+        )?;
+
+        for coin in spent_coins {
+            alice_owncoins.retain(|x| x != &coin);
+        }
+        assert!(alice_owncoins.is_empty());
+        assert!(params.inputs.len() == 2);
+        assert!(params.outputs.len() == 1);
+
+        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], None)?;
+        alice_owncoins.push(alice_oc);
+
+        assert!(alice_owncoins.len() == 1);
+        assert!(alice_owncoins[0].note.value == ALICE_INITIAL);
+        assert!(alice_owncoins[0].note.token_id == alice_token_id);
+
+        // Bob does the same
+        info!(target: "money", "[Bob] ====================================================");
+        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)?;
+
+        for coin in spent_coins {
+            bob_owncoins.retain(|x| x != &coin);
+        }
+        assert!(bob_owncoins.is_empty());
+        assert!(params.inputs.len() == 2);
+        assert!(params.outputs.len() == 1);
+
+        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], None)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(bob_owncoins.len() == 1);
+        assert!(bob_owncoins[0].note.value == BOB_INITIAL);
+        assert!(bob_owncoins[0].note.token_id == bob_token_id);
+
+        // Now they decide to swap all of their tokens
+        info!(target: "money", "[Alice, Bob] ================");
+        info!(target: "money", "[Alice, Bob] Building OtcSwap");
+        info!(target: "money", "[Alice, Bob] ================");
+        let alice_oc = alice_owncoins[0].clone();
+        alice_owncoins.remove(0);
+        assert!(alice_owncoins.is_empty());
+        let bob_oc = bob_owncoins[0].clone();
+        bob_owncoins.remove(0);
+        assert!(bob_owncoins.is_empty());
+
+        let (otc_swap_tx, otc_swap_params) =
+            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:?}] ==========================");
+            let write = holder == &Holder::Faucet;
+            th.execute_otc_swap_tx(holder, &otc_swap_tx, &otc_swap_params, current_slot, write)
+                .await?;
+        }
+
+        // Alice should now have Bob's BOB tokens
+        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);
+        assert!(alice_owncoins[0].note.value == BOB_INITIAL);
+        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)?;
+        bob_owncoins.push(bob_oc);
+
+        assert!(bob_owncoins.len() == 1);
+        assert!(bob_owncoins[0].note.value == ALICE_INITIAL);
+        assert!(bob_owncoins[0].note.token_id == alice_token_id);
+
+        th.assert_trees(&HOLDERS);
+
+        // Statistics
+        th.statistics();
+
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 111 - 103
src/contract/money/tests/txs_verification.rs

@@ -28,117 +28,125 @@ use darkfi::Result;
 use darkfi_contract_test_harness::{init_logger, Holder, TestHarness, TxAction};
 use log::info;
 
-#[async_std::test]
-async fn txs_verification() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
-
-    // Some numbers we want to assert
-    const ALICE_INITIAL: u64 = 100;
-
-    // Alice = 50 ALICE
-    // Bob = 50 ALICE
-    const ALICE_SEND: u64 = ALICE_INITIAL - 50;
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string()]).await?;
-
-    let mut alice_owncoins = vec![];
-    let mut bob_owncoins = vec![];
-
-    info!(target: "money", "[Alice] ================================");
-    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)?;
-
-    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_token_id = alice_oc.note.token_id;
-    alice_owncoins.push(alice_oc);
-
-    // Now Alice can send a little bit of funds to Bob.
-    // We can duplicate this transaction to simulate double spending.
-    let duplicates = 3; // Change this number to >1 to double spend
-    let mut transactions = vec![];
-    let mut txs_params = vec![];
-    for i in 0..duplicates {
-        info!(target: "money", "[Alice] ======================================================");
-        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)?;
-
-        // Validating transfer params
-        assert!(transfer_params.inputs.len() == 1);
-        assert!(transfer_params.outputs.len() == 2);
-        assert!(spent_coins.len() == 1);
-
-        // Now we simulate nodes verification, as transactions come one by one.
-        // Validation should pass, even when we are trying to double spent.
+#[test]
+fn txs_verification() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 3] = [Holder::Faucet, Holder::Alice, Holder::Bob];
+
+        // Some numbers we want to assert
+        const ALICE_INITIAL: u64 = 100;
+
+        // Alice = 50 ALICE
+        // Bob = 50 ALICE
+        const ALICE_SEND: u64 = ALICE_INITIAL - 50;
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string()]).await?;
+
+        let mut alice_owncoins = vec![];
+        let mut bob_owncoins = vec![];
+
+        info!(target: "money", "[Alice] ================================");
+        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)?;
+
         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?;
+            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_token_id = alice_oc.note.token_id;
+        alice_owncoins.push(alice_oc);
+
+        // Now Alice can send a little bit of funds to Bob.
+        // We can duplicate this transaction to simulate double spending.
+        let duplicates = 3; // Change this number to >1 to double spend
+        let mut transactions = vec![];
+        let mut txs_params = vec![];
+        for i in 0..duplicates {
+            info!(target: "money", "[Alice] ======================================================");
+            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,
+            )?;
+
+            // Validating transfer params
+            assert!(transfer_params.inputs.len() == 1);
+            assert!(transfer_params.outputs.len() == 2);
+            assert!(spent_coins.len() == 1);
+
+            // Now we simulate nodes verification, as transactions come one by one.
+            // Validation should pass, even when we are trying to double spent.
+            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);
         }
+        alice_owncoins = vec![];
+        assert_eq!(transactions.len(), duplicates);
+        assert_eq!(txs_params.len(), duplicates);
 
-        transactions.push(transfer_tx);
-        txs_params.push(transfer_params);
-    }
-    alice_owncoins = vec![];
-    assert_eq!(transactions.len(), duplicates);
-    assert_eq!(txs_params.len(), duplicates);
-
-    // 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.
-    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)
+        // 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.
+        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);
+        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], None)?;
-    alice_owncoins.push(alice_oc);
+        // 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], 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], None)?;
-    bob_owncoins.push(bob_oc);
+        // Bob should now have this new one.
+        let bob_oc = th.gather_owncoin(&Holder::Bob, &txs_params[0].outputs[1], None)?;
+        bob_owncoins.push(bob_oc);
 
-    assert!(alice_owncoins.len() == 1);
-    assert!(bob_owncoins.len() == 1);
+        assert!(alice_owncoins.len() == 1);
+        assert!(bob_owncoins.len() == 1);
 
-    // Statistics
-    th.statistics();
+        // Statistics
+        th.statistics();
 
-    // Thanks for reading
-    Ok(())
+        // Thanks for reading
+        Ok(())
+    })
 }

+ 194 - 177
src/contract/money/tests/verification_bench.rs

@@ -23,214 +23,231 @@ use darkfi_contract_test_harness::{init_logger, Holder, TestHarness};
 use log::info;
 use rand::{prelude::IteratorRandom, Rng};
 
-#[async_std::test]
-async fn alice2alice_random_amounts() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-    const ALICE_AIRDROP: u64 = 1000;
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // n transactions to loop
-    let mut n = 3;
-    for arg in env::args() {
-        match usize::from_str(&arg) {
-            Ok(v) => {
-                n = v;
-                break
-            }
-            Err(_) => continue,
-        };
-    }
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string()]).await?;
-
-    info!(target: "money", "[Faucet] ========================");
-    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)?;
-
-    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], None)?;
-    let token_id = owncoin.note.token_id;
-    owncoins.push(owncoin);
-
-    // Execute transactions loop
-    for i in 0..n {
-        info!(target: "money", "[Alice] ===============================================");
-        info!(target: "money", "[Alice] Building Money::Transfer params for transfer {}", i);
-        info!(target: "money", "[Alice] Alice coins: {}", owncoins.len());
-        for (i, c) in owncoins.iter().enumerate() {
-            info!(target: "money", "[Alice] \t coin {} value: {}", i, c.note.value);
+#[test]
+fn alice2alice_random_amounts() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
+
+        const ALICE_AIRDROP: u64 = 1000;
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // n transactions to loop
+        let mut n = 3;
+        for arg in env::args() {
+            match usize::from_str(&arg) {
+                Ok(v) => {
+                    n = v;
+                    break
+                }
+                Err(_) => continue,
+            };
         }
-        let amount = rand::thread_rng().gen_range(1..ALICE_AIRDROP);
-        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)?;
-
-        // Remove the owncoins we've spent
-        for spent in spent_coins {
-            owncoins.retain(|x| x != &spent);
-        }
-
-        // Verify transaction
-        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, false).await?;
-
-        // Gather new owncoins
-        owncoins.append(&mut th.gather_multiple_owncoins(&Holder::Alice, &params.outputs)?);
-
-        th.assert_trees(&HOLDERS);
-    }
 
-    // Statistics
-    th.statistics();
-
-    // Thanks for reading
-    Ok(())
-}
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string()]).await?;
 
-#[async_std::test]
-async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
-    init_logger();
-
-    // Holders this test will use
-    const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
-
-    // Slot to verify against
-    let current_slot = 0;
-
-    // N blocks to simulate
-    let mut n = 3;
-    for arg in env::args() {
-        match usize::from_str(&arg) {
-            Ok(v) => {
-                n = v;
-                break
-            }
-            Err(_) => continue,
-        };
-    }
-
-    // Initialize harness
-    let mut th = TestHarness::new(&["money".to_string()]).await?;
-
-    // Mint 10 coins
-    let mut token_ids = vec![];
-    let mut minted_amounts = vec![];
-    let mut owncoins = vec![];
-    for i in 0..10 {
-        let amount = rand::thread_rng().gen_range(2..1000);
-        info!(target: "money", "[Faucet] ===================================================");
-        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)?;
+        info!(target: "money", "[Faucet] ========================");
+        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)?;
 
         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?;
+            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 owncoin = th.gather_owncoin(&Holder::Alice, &mint_params.output, None)?;
+        let mut owncoins = vec![];
+        let owncoin = th.gather_owncoin(&Holder::Alice, &airdrop_params.outputs[0], None)?;
         let token_id = owncoin.note.token_id;
-        owncoins.push(vec![owncoin]);
-        minted_amounts.push(amount);
-        token_ids.push(token_id);
-    }
-
-    // Simulating N blocks
-    for b in 0..n {
-        // Get a random sized sample of owncoins
-        let sample =
-            (0..10).choose_multiple(&mut rand::thread_rng(), rand::thread_rng().gen_range(1..10));
-        info!(target: "money", "[Alice] =====================================");
-        info!(target: "money", "[Alice] Generating transactions for block: {}", b);
-        info!(target: "money", "[Alice] Coins to use: {:?}", sample);
-        info!(target: "money", "[Alice] =====================================");
-
-        // Generate a transaction for each coin
-        let mut txs = vec![];
-        let mut txs_params = vec![];
-        for index in sample {
+        owncoins.push(owncoin);
+
+        // Execute transactions loop
+        for i in 0..n {
             info!(target: "money", "[Alice] ===============================================");
-            info!(target: "money", "[Alice] Building Money::Transfer params for coin {}", index);
-            let mut coins = owncoins[index].clone();
-            let token_id = token_ids[index];
-            let mint_amount = minted_amounts[index];
-            info!(target: "money", "[Alice] Alice coins: {}", coins.len());
-            for (i, c) in coins.iter().enumerate() {
+            info!(target: "money", "[Alice] Building Money::Transfer params for transfer {}", i);
+            info!(target: "money", "[Alice] Alice coins: {}", owncoins.len());
+            for (i, c) in owncoins.iter().enumerate() {
                 info!(target: "money", "[Alice] \t coin {} value: {}", i, c.note.value);
             }
-            let amount = rand::thread_rng().gen_range(1..mint_amount);
+            let amount = rand::thread_rng().gen_range(1..ALICE_AIRDROP);
             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, &owncoins, token_id)?;
 
             // Remove the owncoins we've spent
             for spent in spent_coins {
-                coins.retain(|x| x != &spent);
+                owncoins.retain(|x| x != &spent);
             }
 
+            // Verify transaction
+            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, false).await?;
+
             // Gather new owncoins
-            coins.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);
+        }
 
-            // Store transaction and its params
-            txs.push(tx);
-            txs_params.push(params);
+        // Statistics
+        th.statistics();
 
-            // Replace coins
-            owncoins[index] = coins;
+        // Thanks for reading
+        Ok(())
+    })
+}
+
+#[test]
+fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
+    smol::block_on(async {
+        init_logger();
+
+        // Holders this test will use
+        const HOLDERS: [Holder; 2] = [Holder::Faucet, Holder::Alice];
+
+        // Slot to verify against
+        let current_slot = 0;
+
+        // N blocks to simulate
+        let mut n = 3;
+        for arg in env::args() {
+            match usize::from_str(&arg) {
+                Ok(v) => {
+                    n = v;
+                    break
+                }
+                Err(_) => continue,
+            };
         }
 
-        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)
+        // Initialize harness
+        let mut th = TestHarness::new(&["money".to_string()]).await?;
+
+        // Mint 10 coins
+        let mut token_ids = vec![];
+        let mut minted_amounts = vec![];
+        let mut owncoins = vec![];
+        for i in 0..10 {
+            let amount = rand::thread_rng().gen_range(2..1000);
+            info!(target: "money", "[Faucet] ===================================================");
+            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)?;
+
+            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 token_id = owncoin.note.token_id;
+            owncoins.push(vec![owncoin]);
+            minted_amounts.push(amount);
+            token_ids.push(token_id);
+        }
+
+        // Simulating N blocks
+        for b in 0..n {
+            // Get a random sized sample of owncoins
+            let sample = (0..10)
+                .choose_multiple(&mut rand::thread_rng(), rand::thread_rng().gen_range(1..10));
+            info!(target: "money", "[Alice] =====================================");
+            info!(target: "money", "[Alice] Generating transactions for block: {}", b);
+            info!(target: "money", "[Alice] Coins to use: {:?}", sample);
+            info!(target: "money", "[Alice] =====================================");
+
+            // Generate a transaction for each coin
+            let mut txs = vec![];
+            let mut txs_params = vec![];
+            for index in sample {
+                info!(target: "money", "[Alice] ===============================================");
+                info!(target: "money", "[Alice] Building Money::Transfer params for coin {}", index);
+                let mut coins = owncoins[index].clone();
+                let token_id = token_ids[index];
+                let mint_amount = minted_amounts[index];
+                info!(target: "money", "[Alice] Alice coins: {}", coins.len());
+                for (i, c) in coins.iter().enumerate() {
+                    info!(target: "money", "[Alice] \t coin {} value: {}", i, c.note.value);
+                }
+                let amount = rand::thread_rng().gen_range(1..mint_amount);
+                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)?;
+
+                // Remove the owncoins we've spent
+                for spent in spent_coins {
+                    coins.retain(|x| x != &spent);
+                }
+
+                // Gather new owncoins
+                coins.append(&mut th.gather_multiple_owncoins(&Holder::Alice, &params.outputs)?);
+
+                // Store transaction and its params
+                txs.push(tx);
+                txs_params.push(params);
+
+                // Replace coins
+                owncoins[index] = coins;
+            }
+
+            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,
+            )
             .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)
+            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,
+            )
             .await?;
 
-        th.assert_trees(&HOLDERS);
-    }
+            th.assert_trees(&HOLDERS);
+        }
 
-    // Statistics
-    th.statistics();
+        // Statistics
+        th.statistics();
 
-    // Thanks for reading
-    Ok(())
+        // Thanks for reading
+        Ok(())
+    })
 }