From 98521da0debafaf19cec574e59d427dbf0192ffa Mon Sep 17 00:00:00 2001 From: parazyd Date: Sun, 11 Feb 2024 12:08:22 +0100 Subject: [PATCH] contract/dao: Integration test port --- src/contract/dao/tests/integration.rs | 304 +++++++++++------- src/contract/test-harness/src/lib.rs | 1 + .../test-harness/src/money_genesis_mint.rs | 6 +- src/contract/test-harness/src/money_token.rs | 2 +- 4 files changed, 186 insertions(+), 127 deletions(-) diff --git a/src/contract/dao/tests/integration.rs b/src/contract/dao/tests/integration.rs index 1f9b7a6b0..ba330c70f 100644 --- a/src/contract/dao/tests/integration.rs +++ b/src/contract/dao/tests/integration.rs @@ -31,7 +31,7 @@ use darkfi_sdk::{ pasta_prelude::*, pedersen_commitment_u64, poseidon_hash, util::{fp_mod_fv, fp_to_u64}, - Blind, FuncId, FuncRef, DAO_CONTRACT_ID, MONEY_CONTRACT_ID, + BaseBlind, Blind, FuncId, FuncRef, DAO_CONTRACT_ID, MONEY_CONTRACT_ID, }, pasta::pallas, }; @@ -44,26 +44,19 @@ 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, - ]; + // * Rachel is the proposal recipient. + const HOLDERS: [Holder; 5] = + [Holder::Alice, Holder::Bob, Holder::Charlie, Holder::Dao, Holder::Rachel]; // Initialize harness - let mut th = TestHarness::new(&["money".to_string(), "dao".to_string()], false).await?; + let mut th = TestHarness::new(&HOLDERS, false).await?; // We'll use the ALICE token as the DAO governance token let wallet = th.holders.get(&Holder::Alice).unwrap(); let mint_authority = wallet.token_mint_authority; - let token_blind = wallet.token_blind; + let gov_token_blind = BaseBlind::random(&mut OsRng); let auth_func_id = FuncRef { contract_id: *MONEY_CONTRACT_ID, @@ -73,7 +66,7 @@ fn integration_test() -> Result<()> { let token_attrs = TokenAttributes { auth_parent: auth_func_id, user_data: poseidon_hash([mint_authority.public.x(), mint_authority.public.y()]), - blind: token_blind, + blind: gov_token_blind, }; let gov_token_id = token_attrs.to_token_id(); @@ -108,12 +101,20 @@ fn integration_test() -> Result<()> { 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)?; + let (dao_mint_tx, dao_mint_params, fee_params) = + th.dao_mint(&Holder::Alice, &dao, &dao_keypair, current_block_height).await?; for holder in &HOLDERS { info!("[{holder:?}] Executing DAO Mint tx"); - th.execute_dao_mint_tx(holder, &dao_mint_tx, &dao_mint_params, current_block_height) - .await?; + th.execute_dao_mint_tx( + holder, + dao_mint_tx.clone(), + &dao_mint_params, + &fee_params, + current_block_height, + true, + ) + .await?; } th.assert_trees(&HOLDERS); @@ -121,35 +122,37 @@ fn integration_test() -> Result<()> { // ======================================= // Airdrop some treasury tokens to the DAO // ======================================= - info!("Stage 2. Send Treasury token"); - - info!("[Faucet] Building DAO airdrop tx"); + info!("[Dao] Building DAO airdrop tx"); let spend_hook = FuncRef { contract_id: *DAO_CONTRACT_ID, func_code: DaoFunction::Exec as u8 } .to_func_id(); - let (airdrop_tx, airdrop_params) = th.airdrop_native( - DRK_TOKEN_SUPPLY, - &Holder::Dao, - Some(spend_hook), // spend_hook - Some(dao_mint_params.dao_bulla.inner()), // user_data - )?; + let (genesis_mint_tx, genesis_mint_params) = th + .genesis_mint( + &Holder::Dao, + DRK_TOKEN_SUPPLY, + Some(spend_hook), + Some(dao_mint_params.dao_bulla.inner()), + ) + .await?; for holder in &HOLDERS { - info!("[{holder:?}] Executing DAO airdrop tx"); - th.execute_airdrop_native_tx( + th.execute_genesis_mint_tx( holder, - &airdrop_tx, - &airdrop_params, + genesis_mint_tx.clone(), + &genesis_mint_params, current_block_height, + true, ) .await?; } th.assert_trees(&HOLDERS); - // Gather the DAO owncoin - th.gather_owncoin_from_output(&Holder::Dao, &airdrop_params.outputs[0], None)?; + let _dao_tokens = &th.holders.get(&Holder::Dao).unwrap().unspent_money_coins; + assert!(_dao_tokens.len() == 1); + assert!(_dao_tokens[0].note.token_id == *DARK_TOKEN_ID); + assert!(_dao_tokens[0].note.value == DRK_TOKEN_SUPPLY); // ====================================== // Mint the governance token to 3 holders @@ -157,79 +160,106 @@ fn integration_test() -> Result<()> { info!("Stage 3. Minting governance token"); info!("[Alice] Building governance token mint tx for Alice"); - let (a_token_mint_tx, a_token_mint_params, a_auth_token_mint_params) = - th.token_mint(ALICE_GOV_SUPPLY, &Holder::Alice, &Holder::Alice, None, None)?; + let (a_token_mint_tx, a_token_mint_params, a_auth_token_mint_params, a_fee_params) = th + .token_mint( + ALICE_GOV_SUPPLY, + &Holder::Alice, + &Holder::Alice, + gov_token_blind, + None, + None, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing governance token mint tx for Alice"); th.execute_token_mint_tx( holder, - &a_token_mint_tx, + a_token_mint_tx.clone(), &a_token_mint_params, + &a_auth_token_mint_params, + &a_fee_params, current_block_height, + true, ) .await?; } th.assert_trees(&HOLDERS); - // Gather owncoin - th.gather_owncoin( - &Holder::Alice, - &a_token_mint_params.coin, - &a_auth_token_mint_params.enc_note, - None, - )?; + let _alice_tokens = &th.holders.get(&Holder::Alice).unwrap().unspent_money_coins; + assert!(_alice_tokens.len() == 1); + assert!(_alice_tokens[0].note.token_id == gov_token_id); + assert!(_alice_tokens[0].note.value == ALICE_GOV_SUPPLY); info!("[Alice] Building governance token mint tx for Bob"); - let (b_token_mint_tx, b_token_mint_params, b_auth_token_mint_params) = - th.token_mint(BOB_GOV_SUPPLY, &Holder::Alice, &Holder::Bob, None, None)?; + let (b_token_mint_tx, b_token_mint_params, b_auth_token_mint_params, b_fee_params) = th + .token_mint( + BOB_GOV_SUPPLY, + &Holder::Alice, + &Holder::Bob, + gov_token_blind, + None, + None, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing governance token mint tx for Bob"); th.execute_token_mint_tx( holder, - &b_token_mint_tx, + b_token_mint_tx.clone(), &b_token_mint_params, + &b_auth_token_mint_params, + &b_fee_params, current_block_height, + true, ) .await?; } th.assert_trees(&HOLDERS); - // Gather owncoin - th.gather_owncoin( - &Holder::Bob, - &b_token_mint_params.coin, - &b_auth_token_mint_params.enc_note, - None, - )?; + let _bob_tokens = &th.holders.get(&Holder::Bob).unwrap().unspent_money_coins; + assert!(_bob_tokens.len() == 1); + assert!(_bob_tokens[0].note.token_id == gov_token_id); + assert!(_bob_tokens[0].note.value == BOB_GOV_SUPPLY); info!("[Alice] Building governance token mint tx for Charlie"); - let (c_token_mint_tx, c_token_mint_params, c_auth_token_mint_params) = - th.token_mint(CHARLIE_GOV_SUPPLY, &Holder::Alice, &Holder::Charlie, None, None)?; + let (c_token_mint_tx, c_token_mint_params, c_auth_token_mint_params, c_fee_params) = th + .token_mint( + CHARLIE_GOV_SUPPLY, + &Holder::Alice, + &Holder::Charlie, + gov_token_blind, + None, + None, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing governance token mint tx for Charlie"); th.execute_token_mint_tx( holder, - &c_token_mint_tx, + c_token_mint_tx.clone(), &c_token_mint_params, + &c_auth_token_mint_params, + &c_fee_params, current_block_height, + true, ) .await?; } th.assert_trees(&HOLDERS); - // Gather owncoin - th.gather_owncoin( - &Holder::Charlie, - &c_token_mint_params.coin, - &c_auth_token_mint_params.enc_note, - None, - )?; + let _charlie_tokens = &th.holders.get(&Holder::Charlie).unwrap().unspent_money_coins; + assert!(_charlie_tokens.len() == 1); + assert!(_charlie_tokens[0].note.token_id == gov_token_id); + assert!(_charlie_tokens[0].note.value == CHARLIE_GOV_SUPPLY); // ================ // Dao::Propose @@ -255,19 +285,28 @@ fn integration_test() -> Result<()> { // It's up to the auth module to decide what to do with it. let user_data = pallas::Base::ZERO; - let (propose_tx, propose_params, propose_info) = th.dao_propose( - &Holder::Alice, - &proposal_coinattrs, - user_data, - &dao, - &dao_mint_params.dao_bulla, - current_block_height, - )?; + let (propose_tx, (propose_params, fee_params), propose_info) = th + .dao_propose( + &Holder::Alice, + &proposal_coinattrs, + user_data, + &dao, + &dao_mint_params.dao_bulla, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing DAO proposal tx"); - th.execute_dao_propose_tx(holder, &propose_tx, &propose_params, current_block_height) - .await?; + th.execute_dao_propose_tx( + holder, + propose_tx.clone(), + &propose_params, + &fee_params, + current_block_height, + true, + ) + .await?; } th.assert_trees(&HOLDERS); @@ -279,56 +318,75 @@ fn integration_test() -> Result<()> { info!("Stage 5. Start voting"); info!("[Alice] Building vote tx (yes)"); - let (alice_vote_tx, alice_vote_params) = th.dao_vote( - &Holder::Alice, - true, - &dao, - &dao_keypair, - &propose_info, - &propose_params.proposal_bulla, - current_block_height, - )?; + let (alice_vote_tx, alice_vote_params, alice_vote_fee_params) = th + .dao_vote( + &Holder::Alice, + true, + &dao, + &dao_keypair, + &propose_info, + &propose_params.proposal_bulla, + current_block_height, + ) + .await?; info!("[Bob] Building vote tx (no)"); - let (bob_vote_tx, bob_vote_params) = th.dao_vote( - &Holder::Bob, - false, - &dao, - &dao_keypair, - &propose_info, - &propose_params.proposal_bulla, - current_block_height, - )?; + let (bob_vote_tx, bob_vote_params, bob_vote_fee_params) = th + .dao_vote( + &Holder::Bob, + false, + &dao, + &dao_keypair, + &propose_info, + &propose_params.proposal_bulla, + current_block_height, + ) + .await?; info!("[Charlie] Building vote tx (yes)"); - let (charlie_vote_tx, charlie_vote_params) = th.dao_vote( - &Holder::Charlie, - true, - &dao, - &dao_keypair, - &propose_info, - &propose_params.proposal_bulla, - current_block_height, - )?; + let (charlie_vote_tx, charlie_vote_params, charlie_vote_fee_params) = th + .dao_vote( + &Holder::Charlie, + true, + &dao, + &dao_keypair, + &propose_info, + &propose_params.proposal_bulla, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing Alice vote tx"); th.execute_dao_vote_tx( holder, - &alice_vote_tx, + alice_vote_tx.clone(), &alice_vote_params, + &alice_vote_fee_params, current_block_height, + true, ) .await?; + info!("[{holder:?}] Executing Bob vote tx"); - th.execute_dao_vote_tx(holder, &bob_vote_tx, &bob_vote_params, current_block_height) - .await?; + th.execute_dao_vote_tx( + holder, + bob_vote_tx.clone(), + &bob_vote_params, + &bob_vote_fee_params, + current_block_height, + true, + ) + .await?; + info!("[{holder:?}] Executing Charlie vote tx"); th.execute_dao_vote_tx( holder, - &charlie_vote_tx, + charlie_vote_tx.clone(), &charlie_vote_params, + &charlie_vote_fee_params, current_block_height, + true, ) .await?; } @@ -407,46 +465,44 @@ fn integration_test() -> Result<()> { 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, - proposal_coinattrs, - total_yes_vote_value, - total_all_vote_value, - total_yes_vote_blind, - total_all_vote_blind, - )?; + let (exec_tx, xfer_params, exec_params, exec_fee_params) = th + .dao_exec( + &Holder::Alice, + &dao, + &dao_mint_params.dao_bulla, + &propose_info, + proposal_coinattrs, + total_yes_vote_value, + total_all_vote_value, + total_yes_vote_blind, + total_all_vote_blind, + current_block_height, + ) + .await?; for holder in &HOLDERS { info!("[{holder:?}] Executing Dao::Exec tx"); th.execute_dao_exec_tx( holder, - &exec_tx, + exec_tx.clone(), &xfer_params, &exec_params, + &exec_fee_params, current_block_height, + true, ) .await?; } th.assert_trees(&HOLDERS); - // Gather the coins - th.gather_owncoin_from_output(&Holder::Rachel, &xfer_params.outputs[0], None)?; - th.gather_owncoin_from_output(&Holder::Dao, &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(); + assert!(dao_wallet.unspent_money_coins[0].note.value == DRK_TOKEN_SUPPLY - PROPOSAL_AMOUNT); + assert!(dao_wallet.unspent_money_coins[0].note.token_id == drk_token_id); // Thanks for reading Ok(()) diff --git a/src/contract/test-harness/src/lib.rs b/src/contract/test-harness/src/lib.rs index 516db5102..9a6480622 100644 --- a/src/contract/test-harness/src/lib.rs +++ b/src/contract/test-harness/src/lib.rs @@ -101,6 +101,7 @@ pub enum Holder { Bob, Charlie, Dao, + Rachel, } /// Wallet instance for a single [`Holder`] diff --git a/src/contract/test-harness/src/money_genesis_mint.rs b/src/contract/test-harness/src/money_genesis_mint.rs index 08310ed04..6f498aca1 100644 --- a/src/contract/test-harness/src/money_genesis_mint.rs +++ b/src/contract/test-harness/src/money_genesis_mint.rs @@ -45,6 +45,8 @@ impl TestHarness { &mut self, holder: &Holder, amount: u64, + spend_hook: Option, + user_data: Option, ) -> Result<(Transaction, MoneyGenesisMintParamsV1)> { let wallet = self.holders.get(holder).unwrap(); @@ -55,8 +57,8 @@ impl TestHarness { let builder = GenesisMintCallBuilder { keypair: wallet.keypair, amount, - spend_hook: FuncId::none(), - user_data: pallas::Base::ZERO, + spend_hook: spend_hook.unwrap_or(FuncId::none()), + user_data: user_data.unwrap_or(pallas::Base::ZERO), mint_zkbin: mint_zkbin.clone(), mint_pk: mint_pk.clone(), }; diff --git a/src/contract/test-harness/src/money_token.rs b/src/contract/test-harness/src/money_token.rs index 9a80b91ee..4a56ca616 100644 --- a/src/contract/test-harness/src/money_token.rs +++ b/src/contract/test-harness/src/money_token.rs @@ -52,6 +52,7 @@ impl TestHarness { amount: u64, holder: &Holder, recipient: &Holder, + token_blind: BaseBlind, spend_hook: Option, user_data: Option, block_height: u64, @@ -79,7 +80,6 @@ impl TestHarness { .to_func_id(); let (mint_auth_x, mint_auth_y) = mint_authority.public.xy(); - let token_blind = BaseBlind::random(&mut OsRng); let token_attrs = TokenAttributes { auth_parent: auth_func_id,