darkfi_contract_test_harness/
dao_vote.rs
1use darkfi::{
20 tx::{ContractCallLeaf, Transaction, TransactionBuilder},
21 Result,
22};
23use darkfi_dao_contract::{
24 blockwindow,
25 client::{DaoVoteCall, DaoVoteInput},
26 model::{Dao, DaoProposal, DaoVoteParams},
27 DaoFunction, DAO_CONTRACT_ZKAS_DAO_VOTE_INPUT_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS,
28};
29use darkfi_money_contract::{
30 client::{MoneyNote, OwnCoin},
31 model::MoneyFeeParamsV1,
32};
33use darkfi_sdk::{
34 crypto::{contract_id::DAO_CONTRACT_ID, MerkleNode, SecretKey},
35 ContractCall,
36};
37use darkfi_serial::AsyncEncodable;
38use log::debug;
39use rand::rngs::OsRng;
40
41use super::{Holder, TestHarness};
42
43impl TestHarness {
44 pub async fn dao_vote(
46 &mut self,
47 voter: &Holder,
48 vote_option: bool,
49 dao: &Dao,
50 proposal: &DaoProposal,
51 block_height: u32,
52 ) -> Result<(Transaction, DaoVoteParams, Option<MoneyFeeParamsV1>)> {
53 let wallet = self.holders.get(voter).unwrap();
54
55 let (dao_vote_burn_pk, dao_vote_burn_zkbin) =
56 self.proving_keys.get(DAO_CONTRACT_ZKAS_DAO_VOTE_INPUT_NS).unwrap();
57
58 let (dao_vote_main_pk, dao_vote_main_zkbin) =
59 self.proving_keys.get(DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS).unwrap();
60
61 let (_, snapshot_money_merkle_tree) =
62 wallet.dao_prop_leafs.get(&proposal.to_bulla()).unwrap();
63
64 let vote_owncoin: OwnCoin = wallet
65 .unspent_money_coins
66 .iter()
67 .find(|x| x.note.token_id == dao.gov_token_id)
68 .unwrap()
69 .clone();
70
71 let signature_secret = SecretKey::random(&mut OsRng);
72
73 let input = DaoVoteInput {
74 secret: wallet.keypair.secret,
75 note: vote_owncoin.note.clone(),
76 leaf_position: vote_owncoin.leaf_position,
77 merkle_path: snapshot_money_merkle_tree.witness(vote_owncoin.leaf_position, 0).unwrap(),
78 signature_secret,
79 };
80
81 let block_target = wallet.validator.consensus.module.read().await.target;
82 let current_blockwindow = blockwindow(block_height, block_target);
83 let call = DaoVoteCall {
84 money_null_smt: wallet.money_null_smt_snapshot.as_ref().unwrap(),
85 inputs: vec![input],
86 vote_option,
87 proposal: proposal.clone(),
88 dao: dao.clone(),
89 current_blockwindow,
90 };
91
92 let (params, proofs) = call.make(
93 dao_vote_burn_zkbin,
94 dao_vote_burn_pk,
95 dao_vote_main_zkbin,
96 dao_vote_main_pk,
97 )?;
98
99 let mut data = vec![DaoFunction::Vote as u8];
101 params.encode_async(&mut data).await?;
102 let call = ContractCall { contract_id: *DAO_CONTRACT_ID, data };
103 let mut tx_builder = TransactionBuilder::new(ContractCallLeaf { call, proofs }, vec![])?;
104
105 let mut fee_params = None;
107 let mut fee_signature_secrets = None;
108 if self.verify_fees {
109 let mut tx = tx_builder.build()?;
110 let sigs = tx.create_sigs(&[signature_secret])?;
111 tx.signatures = vec![sigs];
112
113 let (fee_call, fee_proofs, fee_secrets, _spent_fee_coins, fee_call_params) =
114 self.append_fee_call(voter, tx, block_height, &[]).await?;
115
116 tx_builder.append(ContractCallLeaf { call: fee_call, proofs: fee_proofs }, vec![])?;
118 fee_signature_secrets = Some(fee_secrets);
119 fee_params = Some(fee_call_params);
120 }
121
122 let mut tx = tx_builder.build()?;
124 let sigs = tx.create_sigs(&[signature_secret])?;
125 tx.signatures = vec![sigs];
126 if let Some(fee_signature_secrets) = fee_signature_secrets {
127 let sigs = tx.create_sigs(&fee_signature_secrets)?;
128 tx.signatures.push(sigs);
129 }
130
131 Ok((tx, params, fee_params))
132 }
133
134 pub async fn execute_dao_vote_tx(
138 &mut self,
139 holder: &Holder,
140 tx: Transaction,
141 fee_params: &Option<MoneyFeeParamsV1>,
142 block_height: u32,
143 append: bool,
144 ) -> Result<Vec<OwnCoin>> {
145 let wallet = self.holders.get_mut(holder).unwrap();
146
147 wallet.add_transaction("dao::vote", tx, block_height).await?;
149
150 if !append {
151 return Ok(vec![])
152 }
153
154 if let Some(ref fee_params) = fee_params {
155 let nullifier = fee_params.input.nullifier.inner();
156 wallet
157 .money_null_smt
158 .insert_batch(vec![(nullifier, nullifier)])
159 .expect("smt.insert_batch()");
160
161 if let Some(spent_coin) = wallet
162 .unspent_money_coins
163 .iter()
164 .find(|x| x.nullifier() == fee_params.input.nullifier)
165 .cloned()
166 {
167 debug!("Found spent OwnCoin({}) for {:?}", spent_coin.coin, holder);
168 wallet.unspent_money_coins.retain(|x| x.nullifier() != fee_params.input.nullifier);
169 wallet.spent_money_coins.push(spent_coin.clone());
170 }
171
172 wallet.money_merkle_tree.append(MerkleNode::from(fee_params.output.coin.inner()));
173
174 let Ok(note) = fee_params.output.note.decrypt::<MoneyNote>(&wallet.keypair.secret)
175 else {
176 return Ok(vec![])
177 };
178
179 let owncoin = OwnCoin {
180 coin: fee_params.output.coin,
181 note: note.clone(),
182 secret: wallet.keypair.secret,
183 leaf_position: wallet.money_merkle_tree.mark().unwrap(),
184 };
185
186 debug!("Found new OwnCoin({}) for {:?}", owncoin.coin, holder);
187 wallet.unspent_money_coins.push(owncoin.clone());
188 return Ok(vec![owncoin])
189 }
190
191 Ok(vec![])
192 }
193}