contract/dao: Integration test port

This commit is contained in:
parazyd
2024-02-11 12:08:22 +01:00
parent 260a0d99d8
commit 98521da0de
4 changed files with 186 additions and 127 deletions

View File

@@ -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(())

View File

@@ -101,6 +101,7 @@ pub enum Holder {
Bob,
Charlie,
Dao,
Rachel,
}
/// Wallet instance for a single [`Holder`]

View File

@@ -45,6 +45,8 @@ impl TestHarness {
&mut self,
holder: &Holder,
amount: u64,
spend_hook: Option<FuncId>,
user_data: Option<pallas::Base>,
) -> 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(),
};

View File

@@ -52,6 +52,7 @@ impl TestHarness {
amount: u64,
holder: &Holder,
recipient: &Holder,
token_blind: BaseBlind,
spend_hook: Option<FuncId>,
user_data: Option<pallas::Base>,
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,