From a7751f4e1828fc92f8c255a80a37eb59b3aff560 Mon Sep 17 00:00:00 2001 From: x Date: Thu, 5 Jan 2023 12:40:35 +0100 Subject: [PATCH] split WalletCache into its own module --- src/contract/dao/src/dao_client/mint.rs | 178 +++------------------ src/contract/dao/src/dao_client/propose.rs | 1 - src/contract/dao/src/lib.rs | 16 +- src/contract/dao/tests/integration.rs | 61 +++---- 4 files changed, 50 insertions(+), 206 deletions(-) diff --git a/src/contract/dao/src/dao_client/mint.rs b/src/contract/dao/src/dao_client/mint.rs index ed4beb8fa..d7c30835e 100644 --- a/src/contract/dao/src/dao_client/mint.rs +++ b/src/contract/dao/src/dao_client/mint.rs @@ -22,81 +22,14 @@ use darkfi::{ Result, }; use darkfi_sdk::{ - crypto::{ - coin::Coin, constants::MERKLE_DEPTH, poseidon_hash, MerkleNode, PublicKey, SecretKey, - TokenId, - }, - incrementalmerkletree, - incrementalmerkletree::{bridgetree::BridgeTree, Tree}, + crypto::{poseidon_hash, PublicKey, TokenId}, pasta::pallas, }; use halo2_proofs::circuit::Value; use log::debug; use rand::rngs::OsRng; -use darkfi_money_contract::client::{EncryptedNote, Note}; - -use crate::dao_model::{DaoBulla, DaoMintParams}; - -pub type MerkleTree = BridgeTree; - -pub struct OwnCoin { - pub coin: Coin, - pub note: Note, - pub leaf_position: incrementalmerkletree::Position, -} - -pub struct WalletCache { - // Normally this would be a HashMap, but SecretKey is not Hash-able - // TODO: This can be HashableBase - cache: Vec<(SecretKey, Vec)>, - /// The entire Merkle tree state - pub tree: MerkleTree, -} - -impl Default for WalletCache { - fn default() -> Self { - Self { cache: Vec::new(), tree: MerkleTree::new(100) } - } -} - -impl WalletCache { - pub fn new() -> Self { - Self { cache: Vec::new(), tree: MerkleTree::new(100) } - } - - /// Must be called at the start to begin tracking received coins for this secret. - pub fn track(&mut self, secret: SecretKey) { - self.cache.push((secret, Vec::new())); - } - - /// Get all coins received by this secret key - /// track() must be called on this secret before calling this or the function will panic. - pub fn get_received(&mut self, secret: &SecretKey) -> Vec { - for (other_secret, own_coins) in self.cache.iter_mut() { - if *secret == *other_secret { - // clear own_coins vec, and return current contents - return std::mem::take(own_coins) - } - } - panic!("you forget to track() this secret!"); - } - - pub fn try_decrypt_note(&mut self, coin: Coin, ciphertext: &EncryptedNote) { - // Add the new coins to the Merkle tree - let node = MerkleNode::from(coin.inner()); - self.tree.append(&node); - - // Loop through all our secret keys... - for (secret, own_coins) in self.cache.iter_mut() { - // .. attempt to decrypt the note ... - if let Ok(note) = ciphertext.decrypt(secret) { - let leaf_position = self.tree.witness().expect("coin should be in tree"); - own_coins.push(OwnCoin { coin, note, leaf_position }); - } - } - } -} +use crate::dao_model::DaoMintParams; #[derive(Clone)] pub struct Dao { @@ -109,63 +42,30 @@ pub struct Dao { pub bulla_blind: pallas::Base, } -struct DaoMintRevealed { - pub bulla: DaoBulla, -} +pub fn make_mint_call( + dao: &Dao, + dao_mint_zkbin: &ZkBinary, + dao_mint_pk: &ProvingKey, +) -> Result<(DaoMintParams, Vec)> { + debug!(target: "dao", "Building DAO contract mint transaction"); -impl DaoMintRevealed { - pub fn compute( - dao_proposer_limit: pallas::Base, - dao_quorum: pallas::Base, - dao_approval_ratio_quot: pallas::Base, - dao_approval_ratio_base: pallas::Base, - gov_token_id: TokenId, - dao_pubkey: &PublicKey, - dao_bulla_blind: pallas::Base, - ) -> Self { - let (pub_x, pub_y) = dao_pubkey.xy(); + let dao_proposer_limit = pallas::Base::from(dao.proposer_limit); + let dao_quorum = pallas::Base::from(dao.quorum); + let dao_approval_ratio_quot = pallas::Base::from(dao.approval_ratio_quot); + let dao_approval_ratio_base = pallas::Base::from(dao.approval_ratio_base); - let dao_bulla = poseidon_hash([ - dao_proposer_limit, - dao_quorum, - dao_approval_ratio_quot, - dao_approval_ratio_base, - gov_token_id.inner(), - pub_x, - pub_y, - dao_bulla_blind, - ]); + let (pub_x, pub_y) = dao.public_key.xy(); - Self { bulla: DaoBulla::from(dao_bulla) } - } - - pub fn to_vec(&self) -> Vec { - vec![self.bulla.inner()] - } -} - -fn create_dao_mint_proof( - zkbin: &ZkBinary, - pk: &ProvingKey, - dao_proposer_limit: pallas::Base, - dao_quorum: pallas::Base, - dao_approval_ratio_quot: pallas::Base, - dao_approval_ratio_base: pallas::Base, - gov_token_id: TokenId, - dao_pubkey: &PublicKey, - dao_bulla_blind: pallas::Base, -) -> Result<(Proof, DaoMintRevealed)> { - let revealed = DaoMintRevealed::compute( + let dao_bulla = poseidon_hash([ dao_proposer_limit, dao_quorum, dao_approval_ratio_quot, dao_approval_ratio_base, - gov_token_id, - dao_pubkey, - dao_bulla_blind, - ); - - let (pub_x, pub_y) = dao_pubkey.xy(); + dao.gov_token_id.inner(), + pub_x, + pub_y, + dao.bulla_blind, + ]); // NOTE: It's important to keep these in the same order as the zkas code. let prover_witnesses = vec![ @@ -173,46 +73,18 @@ fn create_dao_mint_proof( Witness::Base(Value::known(dao_quorum)), Witness::Base(Value::known(dao_approval_ratio_quot)), Witness::Base(Value::known(dao_approval_ratio_base)), - Witness::Base(Value::known(gov_token_id.inner())), + Witness::Base(Value::known(dao.gov_token_id.inner())), Witness::Base(Value::known(pub_x)), Witness::Base(Value::known(pub_y)), - Witness::Base(Value::known(dao_bulla_blind)), + Witness::Base(Value::known(dao.bulla_blind)), ]; - let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone()); - let proof = Proof::create(pk, &[circuit], &revealed.to_vec(), &mut OsRng)?; + let public = vec![dao_bulla]; - Ok((proof, revealed)) -} + let circuit = ZkCircuit::new(prover_witnesses, dao_mint_zkbin.clone()); + let proof = Proof::create(dao_mint_pk, &[circuit], &public, &mut OsRng)?; -pub fn build_dao_mint_tx( - dao_proposer_limit: u64, - dao_quorum: u64, - dao_approval_ratio_quot: u64, - dao_approval_ratio_base: u64, - gov_token_id: TokenId, - dao_pubkey: &PublicKey, - dao_bulla_blind: pallas::Base, - _signature_secret: &SecretKey, - dao_mint_zkbin: &ZkBinary, - dao_mint_pk: &ProvingKey, -) -> Result<(DaoMintParams, Vec)> { - debug!(target: "dao", "Building DAO contract mint transaction"); - - let (proof, revealed) = create_dao_mint_proof( - dao_mint_zkbin, - dao_mint_pk, - pallas::Base::from(dao_proposer_limit), - pallas::Base::from(dao_quorum), - pallas::Base::from(dao_approval_ratio_quot), - pallas::Base::from(dao_approval_ratio_base), - gov_token_id, - dao_pubkey, - dao_bulla_blind, - )?; - - let dao_bulla = revealed.bulla; - let dao_mint_params = DaoMintParams { dao_bulla }; + let dao_mint_params = DaoMintParams { dao_bulla: dao_bulla.into() }; Ok((dao_mint_params, vec![proof])) } diff --git a/src/contract/dao/src/dao_client/propose.rs b/src/contract/dao/src/dao_client/propose.rs index 46d026c85..94351aed4 100644 --- a/src/contract/dao/src/dao_client/propose.rs +++ b/src/contract/dao/src/dao_client/propose.rs @@ -82,7 +82,6 @@ pub struct ProposeCall { } impl ProposeCall { - //pub fn build(self /*, zk_bins: &ZkContractTable */) -> Result<(DaoProposeParams, Vec)> { pub fn make( self, burn_zkbin: &ZkBinary, diff --git a/src/contract/dao/src/lib.rs b/src/contract/dao/src/lib.rs index 724d86822..2afe63c21 100644 --- a/src/contract/dao/src/lib.rs +++ b/src/contract/dao/src/lib.rs @@ -30,22 +30,14 @@ pub mod dao_client; pub mod dao_model; -//#[cfg(feature = "client")] -///// Transaction building API for clients interacting with DAO contract -//pub mod dao_propose_client; -// -//#[cfg(feature = "client")] -///// Transaction building API for clients interacting with DAO contract -//pub mod dao_vote_client; -// -//#[cfg(feature = "client")] -///// Transaction building API for clients interacting with DAO contract -//pub mod dao_exec_client; - #[cfg(feature = "client")] /// Transaction building API for clients interacting with money contract pub mod money_client; +#[cfg(feature = "client")] +/// Decrypt incoming transaction notes to track coins sent to us +pub mod wallet_cache; + // These are the zkas circuit namespaces pub const DAO_CONTRACT_ZKAS_DAO_MINT_NS: &str = "DaoMint"; pub const DAO_CONTRACT_ZKAS_DAO_EXEC_NS: &str = "DaoExec"; diff --git a/src/contract/dao/tests/integration.rs b/src/contract/dao/tests/integration.rs index aac231592..301bd2bbe 100644 --- a/src/contract/dao/tests/integration.rs +++ b/src/contract/dao/tests/integration.rs @@ -34,17 +34,15 @@ use darkfi_sdk::{ tx::ContractCall, }; use darkfi_serial::{Decodable, Encodable}; -use log::{debug, info}; +use log::debug; use rand::rngs::OsRng; use darkfi_dao_contract::{ dao_client, - dao_client::{ - exec as dao_exec_client, - mint::{build_dao_mint_tx, MerkleTree, WalletCache}, - propose as dao_propose_client, vote as dao_vote_client, - }, - money_client, note, DaoFunction, + dao_client::{exec as dao_exec_client, propose as dao_propose_client, vote as dao_vote_client}, + money_client, note, + wallet_cache::{MerkleTree, WalletCache}, + DaoFunction, }; use darkfi_money_contract::{client::EncryptedNote, state::MoneyTransferParams, MoneyFunction}; @@ -75,10 +73,15 @@ async fn integration_test() -> Result<()> { let gdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng)); // DAO parameters - let dao_proposer_limit = 110; - let dao_quorum = 110; - let dao_approval_ratio_quot = 1; - let dao_approval_ratio_base = 2; + let dao = dao_client::Dao { + proposer_limit: 110, + quorum: 110, + approval_ratio_base: 1, + approval_ratio_quot: 2, + gov_token_id: gdrk_token_id, + public_key: dao_th.dao_kp.public, + bulla_blind: pallas::Base::random(&mut OsRng), + }; // We use this to receive coins let mut cache = WalletCache::new(); @@ -90,20 +93,8 @@ async fn integration_test() -> Result<()> { // ======================================================= debug!(target: "dao", "Stage 1. Creating DAO bulla"); - let dao_bulla_blind = pallas::Base::random(&mut OsRng); - - let (params, proofs) = build_dao_mint_tx( - dao_proposer_limit, - dao_quorum, - dao_approval_ratio_quot, - dao_approval_ratio_base, - gdrk_token_id, - &dao_th.dao_kp.public, - dao_bulla_blind, - &dao_th.dao_kp.secret, - &dao_th.dao_mint_zkbin, - &dao_th.dao_mint_pk, - )?; + let (params, proofs) = + dao_client::make_mint_call(&dao, &dao_th.dao_mint_zkbin, &dao_th.dao_mint_pk)?; let mut data = vec![DaoFunction::Mint as u8]; params.encode(&mut data)?; @@ -408,16 +399,6 @@ async fn integration_test() -> Result<()> { (merkle_path, root) }; - let dao_params = dao_client::Dao { - proposer_limit: dao_proposer_limit, - quorum: dao_quorum, - approval_ratio_base: dao_approval_ratio_base, - approval_ratio_quot: dao_approval_ratio_quot, - gov_token_id: gdrk_token_id, - public_key: dao_th.dao_kp.public, - bulla_blind: dao_bulla_blind, - }; - let proposal = dao_client::Proposal { dest: receiver_keypair.public, amount: 1000, @@ -429,7 +410,7 @@ async fn integration_test() -> Result<()> { let call = dao_client::ProposeCall { inputs: vec![input], proposal, - dao: dao_params.clone(), + dao: dao.clone(), dao_leaf_position, dao_merkle_path, dao_merkle_root, @@ -539,7 +520,7 @@ async fn integration_test() -> Result<()> { }, vote_keypair: vote_keypair_1, proposal: proposal.clone(), - dao: dao_params.clone(), + dao: dao.clone(), }; let (params, proofs) = builder.build( &dao_th.dao_vote_burn_zkbin, @@ -610,7 +591,7 @@ async fn integration_test() -> Result<()> { }, vote_keypair: vote_keypair_2, proposal: proposal.clone(), - dao: dao_params.clone(), + dao: dao.clone(), }; let (params, proofs) = builder.build( &dao_th.dao_vote_burn_zkbin, @@ -678,7 +659,7 @@ async fn integration_test() -> Result<()> { }, vote_keypair: vote_keypair_3, proposal: proposal.clone(), - dao: dao_params.clone(), + dao: dao.clone(), }; let (params, proofs) = builder.build( &dao_th.dao_vote_burn_zkbin, @@ -855,7 +836,7 @@ async fn integration_test() -> Result<()> { let builder = dao_exec_client::Builder { proposal, - dao: dao_params.clone(), + dao, yes_votes_value, all_votes_value, yes_votes_blind,