Просмотр исходного кода

contract/dao/client: use diff signatures per input in propose and vote

skoupidi 7 месяцев назад
Родитель
Сommit
d5be2cf726

+ 20 - 28
bin/drk/src/dao.rs

@@ -58,6 +58,7 @@ use darkfi_money_contract::{
 use darkfi_sdk::{
     bridgetree,
     crypto::{
+        keypair::{Address, StandardAddress},
         pasta_prelude::PrimeField,
         poseidon_hash,
         smt::{MemoryStorageFp, PoseidonFp, SmtMemoryFp, EMPTY_NODES_FP},
@@ -1587,8 +1588,6 @@ impl Drk {
 
     /// Import given DAO vote into the wallet.
     pub async fn put_dao_vote(&self, vote: &VoteRecord) -> WalletDbResult<()> {
-        println!("Importing DAO vote into wallet");
-
         // Create an SQL `INSERT OR REPLACE` query
         let query = format!(
             "INSERT INTO {} ({}, {}, {}, {}, {}, {}, {}, {}, {}) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);",
@@ -1620,8 +1619,6 @@ impl Drk {
         // Execute the query
         self.wallet.exec_sql(&query, params)?;
 
-        println!("DAO vote added to wallet");
-
         Ok(())
     }
 
@@ -1872,6 +1869,9 @@ impl Drk {
         if let Some(name) = name {
             let dao = self.get_dao_by_name(name).await?;
             output.push(format!("{dao}"));
+            let address: Address =
+                StandardAddress::from_public(self.network, dao.params.dao.notes_public_key).into();
+            output.push(format!("Wallet Address: {address}"));
             return Ok(());
         }
 
@@ -2521,10 +2521,8 @@ impl Drk {
             inputs.push(input);
         }
 
-        // Now create the parameters for the proposal tx
-        let signature_secret = SecretKey::random(&mut OsRng);
-
-        // Fetch the daos Merkle tree to compute the DAO Merkle path and root
+        // Now create the parameters for the proposal tx.
+        // Fetch the daos Merkle tree to compute the DAO Merkle path and root.
         let (daos_tree, _) = self.get_dao_trees().await?;
         let (dao_merkle_path, dao_merkle_root) = {
             let root = daos_tree.root(0).unwrap();
@@ -2546,10 +2544,9 @@ impl Drk {
             dao_leaf_position: dao.leaf_position.unwrap(),
             dao_merkle_path,
             dao_merkle_root,
-            signature_secret,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             &dao.params.proposer_secret_key.unwrap(),
             &propose_burn_zkbin,
             &propose_burn_pk,
@@ -2568,8 +2565,8 @@ impl Drk {
         // We first have to execute the fee-less tx to gather its used gas, and then we feed
         // it into the fee-creating function.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
 
         let tree = self.get_money_tree().await?;
         let (fee_call, fee_proofs, fee_secrets) =
@@ -2580,7 +2577,7 @@ impl Drk {
 
         // Now build the actual transaction and sign it with all necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
+        let sigs = tx.create_sigs(&signature_secrets)?;
         tx.signatures.push(sigs);
         let sigs = tx.create_sigs(&fee_secrets)?;
         tx.signatures.push(sigs);
@@ -2704,10 +2701,8 @@ impl Drk {
             inputs.push(input);
         }
 
-        // Now create the parameters for the proposal tx
-        let signature_secret = SecretKey::random(&mut OsRng);
-
-        // Fetch the daos Merkle tree to compute the DAO Merkle path and root
+        // Now create the parameters for the proposal tx.
+        // Fetch the daos Merkle tree to compute the DAO Merkle path and root.
         let (daos_tree, _) = self.get_dao_trees().await?;
         let (dao_merkle_path, dao_merkle_root) = {
             let root = daos_tree.root(0).unwrap();
@@ -2729,10 +2724,9 @@ impl Drk {
             dao_leaf_position: dao.leaf_position.unwrap(),
             dao_merkle_path,
             dao_merkle_root,
-            signature_secret,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             &dao.params.proposer_secret_key.unwrap(),
             &propose_burn_zkbin,
             &propose_burn_pk,
@@ -2751,8 +2745,8 @@ impl Drk {
         // We first have to execute the fee-less tx to gather its used gas, and then we feed
         // it into the fee-creating function.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
 
         let tree = self.get_money_tree().await?;
         let (fee_call, fee_proofs, fee_secrets) =
@@ -2763,7 +2757,7 @@ impl Drk {
 
         // Now build the actual transaction and sign it with all necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
+        let sigs = tx.create_sigs(&signature_secrets)?;
         tx.signatures.push(sigs);
         let sigs = tx.create_sigs(&fee_secrets)?;
         tx.signatures.push(sigs);
@@ -2891,7 +2885,6 @@ impl Drk {
         let dao_vote_main_pk = ProvingKey::build(dao_vote_main_zkbin.k, &dao_vote_main_circuit);
 
         // Now create the parameters for the vote tx
-        let signature_secret = SecretKey::random(&mut OsRng);
         let mut inputs = Vec::with_capacity(gov_owncoins_to_use.len());
         for gov_owncoin in gov_owncoins_to_use {
             // Skip governance coins that are not part of the snapshot
@@ -2915,7 +2908,6 @@ impl Drk {
                 note: gov_owncoin.note.clone(),
                 leaf_position: gov_owncoin.leaf_position,
                 merkle_path,
-                signature_secret,
             };
             inputs.push(input);
         }
@@ -2946,7 +2938,7 @@ impl Drk {
             current_blockwindow,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             &dao_vote_burn_zkbin,
             &dao_vote_burn_pk,
             &dao_vote_main_zkbin,
@@ -2964,8 +2956,8 @@ impl Drk {
         // We first have to execute the fee-less tx to gather its used gas, and then we feed
         // it into the fee-creating function.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
 
         let tree = self.get_money_tree().await?;
         let (fee_call, fee_proofs, fee_secrets) =
@@ -2976,7 +2968,7 @@ impl Drk {
 
         // Now build the actual transaction and sign it with all necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
+        let sigs = tx.create_sigs(&signature_secrets)?;
         tx.signatures.push(sigs);
         let sigs = tx.create_sigs(&fee_secrets)?;
         tx.signatures.push(sigs);

+ 9 - 5
doc/src/testnet/dao.md

@@ -135,6 +135,7 @@ Bulla blind: 6TVkmM...Jjd5zC
 Leaf position: None
 Transaction hash: None
 Call index: None
+Wallet Address: DX7N6v...5Lz8Pp
 ```
 
 ## Minting
@@ -186,13 +187,14 @@ Leaf position: Position(0)
 Mint height: 10
 Transaction hash: 2e7931f200c1485ea7752076e199708b011a504d71e69d60ed606817c5ff4bd5
 Call index: 0
+Wallet Address: DX7N6v...5Lz8Pp
 ```
 
 ## Sending money to the treasury
 
 Let's send some tokens to the DAO's treasury so we're able to make
-a proposal to send those somewhere. First, find the DAO bulla, the
-dao contract spend hook and the DAO notes public key.
+a proposal to send those somewhere. First, find the DAO wallet address,
+the DAO bulla and the dao contract spend hook.
 
 Then create a transfer transaction as follows:
 
@@ -231,10 +233,11 @@ Leaf position: Position(0)
 Mint height: 10
 Transaction hash: 2e7931f200c1485ea7752076e199708b011a504d71e69d60ed606817c5ff4bd5
 Call index: 0
+Wallet Address: DX7N6v...5Lz8Pp
 ```
 
 ```shell
-drk> transfer 10 DAWN {DAO_NOTES_PUBLIC_KEY} {DAO_CONTRACT_SPEND_HOOK} {DAO_BULLA} | broadcast
+drk> transfer 10 DAWN {DAO_WALLET_ADDRESS} {DAO_CONTRACT_SPEND_HOOK} {DAO_BULLA} | broadcast
 
 [mark_tx_spend] Processing transaction: a4db439f75de88457cadd849131394ae37723c943ea5c088b218d6dc0f7982f1
 [mark_tx_spend] Found Money contract in call 0
@@ -565,7 +568,7 @@ instead of transfering some to the DAO, we will mint them
 directly into it:
 
 ```shell
-drk> token mint ANON 20 {DAO_NOTES_PUBLIC_KEY} {DAO_CONTRACT_SPEND_HOOK} {DAO_BULLA} | broadcast
+drk> token mint ANON 20 {DAO_WALLET_ADDRESS} {DAO_CONTRACT_SPEND_HOOK} {DAO_BULLA} | broadcast
 
 [mark_tx_spend] Processing transaction: 781632eb1d0e4566582c1bb34f4a99516d62357761659d4e5e965ac9d199b581
 [mark_tx_spend] Found Money contract in call 0
@@ -638,10 +641,11 @@ Leaf position: Position(3)
 Mint height: 23
 Transaction hash: cfc31bee7d198d7d59e9f40f76a98e93230320ec6dd8c606af32d9bee28fcf0e
 Call index: 0
+Wallet Address: Ui5C2e...1IO4Aa
 ```
 
 ```shell
-drk> dao propose-transfer AnonDAO 1 6.9 ANON {DAWN_DAO_NOTES_PUBLIC_KEY} {DAO_CONTRACT_SPEND_HOOK} {DAWN_DAO_BULLA}
+drk> dao propose-transfer AnonDAO 1 6.9 ANON {DAWN_DAO_WALLET_ADDRESS} {DAO_CONTRACT_SPEND_HOOK} {DAWN_DAO_BULLA}
 
 Generated proposal: {PROPOSAL_BULLA}
 ```

+ 9 - 7
src/contract/dao/src/client/propose.rs

@@ -59,7 +59,6 @@ pub struct DaoProposeCall<'a, T: StorageAdapter<Value = pallas::Base>> {
     pub dao_leaf_position: bridgetree::Position,
     pub dao_merkle_path: Vec<MerkleNode>,
     pub dao_merkle_root: MerkleNode,
-    pub signature_secret: SecretKey,
 }
 
 impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
@@ -70,14 +69,12 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
         burn_pk: &ProvingKey,
         main_zkbin: &ZkBinary,
         main_pk: &ProvingKey,
-    ) -> Result<(DaoProposeParams, Vec<Proof>)> {
+    ) -> Result<(DaoProposeParams, Vec<Proof>, Vec<SecretKey>)> {
         let mut proofs = vec![];
+        let mut signature_secrets = vec![];
 
         let gov_token_blind = Blind::random(&mut OsRng);
-
         let smt_null_root = self.money_null_smt.root();
-        let signature_public = PublicKey::from_secret(self.signature_secret);
-        let (sig_x, sig_y) = signature_public.xy();
 
         let mut inputs = vec![];
         let mut total_funds = 0;
@@ -111,6 +108,10 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
                 )
             }
 
+            let signature_secret = SecretKey::random(&mut OsRng);
+            let signature_public = PublicKey::from_secret(signature_secret);
+            let (sig_x, sig_y) = signature_public.xy();
+
             let prover_witnesses = vec![
                 Witness::Base(Value::known(input.secret.inner())),
                 Witness::Base(Value::known(pallas::Base::from(note.value))),
@@ -123,7 +124,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
                 Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
                 Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
                 Witness::SparseMerklePath(Value::known(smt_null_path.path)),
-                Witness::Base(Value::known(self.signature_secret.inner())),
+                Witness::Base(Value::known(signature_secret.inner())),
             ];
 
             // TODO: We need a generic ZkSet widget to avoid doing this all the time
@@ -165,6 +166,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
             let proving_key = &burn_pk;
             let input_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)?;
             proofs.push(input_proof);
+            signature_secrets.push(signature_secret);
 
             let input = DaoProposeParamsInput {
                 value_commit,
@@ -258,6 +260,6 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoProposeCall<'_, T> {
             inputs,
         };
 
-        Ok((params, proofs))
+        Ok((params, proofs, signature_secrets))
     }
 }

+ 7 - 5
src/contract/dao/src/client/vote.rs

@@ -49,7 +49,6 @@ pub struct DaoVoteInput {
     pub note: darkfi_money_contract::client::MoneyNote,
     pub leaf_position: bridgetree::Position,
     pub merkle_path: Vec<MerkleNode>,
-    pub signature_secret: SecretKey,
 }
 
 // Inside ZK proof, check proposal is correct.
@@ -70,7 +69,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
         burn_pk: &ProvingKey,
         main_zkbin: &ZkBinary,
         main_pk: &ProvingKey,
-    ) -> Result<(DaoVoteParams, Vec<Proof>)> {
+    ) -> Result<(DaoVoteParams, Vec<Proof>, Vec<SecretKey>)> {
         debug!(target: "contract::dao::client::vote", "make()");
 
         if self.dao.to_bulla() != self.proposal.dao_bulla {
@@ -79,6 +78,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
         let proposal_bulla = self.proposal.to_bulla();
 
         let mut proofs = vec![];
+        let mut signature_secrets = vec![];
 
         let gov_token_blind = pallas::Base::random(&mut OsRng);
 
@@ -113,7 +113,8 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
             all_vote_value += input.note.value;
             all_vote_blind += value_blind;
 
-            let signature_public = PublicKey::from_secret(input.signature_secret);
+            let signature_secret = SecretKey::random(&mut OsRng);
+            let signature_public = PublicKey::from_secret(signature_secret);
 
             // Note from the previous output
             let note = input.note;
@@ -152,7 +153,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
                 Witness::Uint32(Value::known(leaf_pos.try_into().unwrap())),
                 Witness::MerklePath(Value::known(input.merkle_path.clone().try_into().unwrap())),
                 Witness::SparseMerklePath(Value::known(smt_null_path.path)),
-                Witness::Base(Value::known(input.signature_secret.inner())),
+                Witness::Base(Value::known(signature_secret.inner())),
             ];
 
             let merkle_root = {
@@ -199,6 +200,7 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
             debug!(target: "contract::dao::client::vote", "input_proof Proof::create()");
             let input_proof = Proof::create(burn_pk, &[circuit], &public_inputs, &mut OsRng)?;
             proofs.push(input_proof);
+            signature_secrets.push(signature_secret);
 
             let input = DaoVoteParamsInput {
                 vote_commit,
@@ -327,6 +329,6 @@ impl<T: StorageAdapter<Value = pallas::Base>> DaoVoteCall<'_, T> {
         let params =
             DaoVoteParams { token_commit, proposal_bulla, yes_vote_commit, note: enc_note, inputs };
 
-        Ok((params, proofs))
+        Ok((params, proofs, signature_secrets))
     }
 }

+ 10 - 14
src/contract/test-harness/src/dao_propose.rs

@@ -130,7 +130,6 @@ impl TestHarness {
             blind: Blind::random(&mut OsRng),
         };
 
-        let signature_secret = SecretKey::random(&mut OsRng);
         let dao_bulla = dao.to_bulla();
 
         let call = DaoProposeCall {
@@ -144,10 +143,9 @@ impl TestHarness {
                 .witness(*wallet.dao_leafs.get(&dao_bulla).unwrap(), 0)
                 .unwrap(),
             dao_merkle_root: wallet.dao_merkle_tree.root(0).unwrap(),
-            signature_secret,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             dao_proposer_secret_key,
             dao_propose_burn_zkbin,
             dao_propose_burn_pk,
@@ -166,8 +164,8 @@ impl TestHarness {
         let mut fee_signature_secrets = None;
         if self.verify_fees {
             let mut tx = tx_builder.build()?;
-            let sigs = tx.create_sigs(&[signature_secret])?;
-            tx.signatures = vec![sigs];
+            let sigs = tx.create_sigs(&signature_secrets)?;
+            tx.signatures.push(sigs);
 
             let (fee_call, fee_proofs, fee_secrets, _spent_fee_coins, fee_call_params) =
                 self.append_fee_call(proposer, tx, block_height, &[]).await?;
@@ -180,8 +178,8 @@ impl TestHarness {
 
         // Now build the actual transaction and sign it with necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
         if let Some(fee_signature_secrets) = fee_signature_secrets {
             let sigs = tx.create_sigs(&fee_signature_secrets)?;
             tx.signatures.push(sigs);
@@ -250,7 +248,6 @@ impl TestHarness {
             blind: Blind::random(&mut OsRng),
         };
 
-        let signature_secret = SecretKey::random(&mut OsRng);
         let dao_bulla = dao.to_bulla();
 
         let call = DaoProposeCall {
@@ -264,10 +261,9 @@ impl TestHarness {
                 .witness(*wallet.dao_leafs.get(&dao_bulla).unwrap(), 0)
                 .unwrap(),
             dao_merkle_root: wallet.dao_merkle_tree.root(0).unwrap(),
-            signature_secret,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             dao_proposer_secret_key,
             dao_propose_burn_zkbin,
             dao_propose_burn_pk,
@@ -286,8 +282,8 @@ impl TestHarness {
         let mut fee_signature_secrets = None;
         if self.verify_fees {
             let mut tx = tx_builder.build()?;
-            let sigs = tx.create_sigs(&[signature_secret])?;
-            tx.signatures = vec![sigs];
+            let sigs = tx.create_sigs(&signature_secrets)?;
+            tx.signatures.push(sigs);
 
             let (fee_call, fee_proofs, fee_secrets, _spent_fee_coins, fee_call_params) =
                 self.append_fee_call(proposer, tx, block_height, &[]).await?;
@@ -300,8 +296,8 @@ impl TestHarness {
 
         // Now build the actual transaction and sign it with necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
         if let Some(fee_signature_secrets) = fee_signature_secrets {
             let sigs = tx.create_sigs(&fee_signature_secrets)?;
             tx.signatures.push(sigs);

+ 6 - 10
src/contract/test-harness/src/dao_vote.rs

@@ -31,11 +31,10 @@ use darkfi_money_contract::{
     model::MoneyFeeParamsV1,
 };
 use darkfi_sdk::{
-    crypto::{contract_id::DAO_CONTRACT_ID, MerkleNode, SecretKey},
+    crypto::{contract_id::DAO_CONTRACT_ID, MerkleNode},
     ContractCall,
 };
 use darkfi_serial::AsyncEncodable;
-use rand::rngs::OsRng;
 use tracing::debug;
 
 use super::{Holder, TestHarness};
@@ -68,14 +67,11 @@ impl TestHarness {
             .unwrap()
             .clone();
 
-        let signature_secret = SecretKey::random(&mut OsRng);
-
         let input = DaoVoteInput {
             secret: wallet.keypair.secret,
             note: vote_owncoin.note.clone(),
             leaf_position: vote_owncoin.leaf_position,
             merkle_path: snapshot_money_merkle_tree.witness(vote_owncoin.leaf_position, 0).unwrap(),
-            signature_secret,
         };
 
         let block_target = wallet.validator.consensus.module.read().await.target;
@@ -89,7 +85,7 @@ impl TestHarness {
             current_blockwindow,
         };
 
-        let (params, proofs) = call.make(
+        let (params, proofs, signature_secrets) = call.make(
             dao_vote_burn_zkbin,
             dao_vote_burn_pk,
             dao_vote_main_zkbin,
@@ -107,8 +103,8 @@ impl TestHarness {
         let mut fee_signature_secrets = None;
         if self.verify_fees {
             let mut tx = tx_builder.build()?;
-            let sigs = tx.create_sigs(&[signature_secret])?;
-            tx.signatures = vec![sigs];
+            let sigs = tx.create_sigs(&signature_secrets)?;
+            tx.signatures.push(sigs);
 
             let (fee_call, fee_proofs, fee_secrets, _spent_fee_coins, fee_call_params) =
                 self.append_fee_call(voter, tx, block_height, &[]).await?;
@@ -121,8 +117,8 @@ impl TestHarness {
 
         // Now build the actual transaction and sign it with necessary keys.
         let mut tx = tx_builder.build()?;
-        let sigs = tx.create_sigs(&[signature_secret])?;
-        tx.signatures = vec![sigs];
+        let sigs = tx.create_sigs(&signature_secrets)?;
+        tx.signatures.push(sigs);
         if let Some(fee_signature_secrets) = fee_signature_secrets {
             let sigs = tx.create_sigs(&fee_signature_secrets)?;
             tx.signatures.push(sigs);