split WalletCache into its own module

This commit is contained in:
x
2023-01-05 12:40:35 +01:00
parent f36747728d
commit a7751f4e18
4 changed files with 50 additions and 206 deletions

View File

@@ -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<MerkleNode, { MERKLE_DEPTH }>;
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<OwnCoin>)>,
/// 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<OwnCoin> {
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<Proof>)> {
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<pallas::Base> {
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<Proof>)> {
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]))
}

View File

@@ -82,7 +82,6 @@ pub struct ProposeCall {
}
impl ProposeCall {
//pub fn build(self /*, zk_bins: &ZkContractTable */) -> Result<(DaoProposeParams, Vec<Proof>)> {
pub fn make(
self,
burn_zkbin: &ZkBinary,

View File

@@ -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";

View File

@@ -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,