Bläddra i källkod

partial implement dao-propose

narodnik 4 år sedan
förälder
incheckning
295d880e60

+ 1 - 1
bin/daod/Makefile

@@ -2,7 +2,7 @@ ZK_SRC_FILES := $(wildcard proof/*.zk)
 ZK_BIN_FILES := $(patsubst proof/%.zk, proof/%.zk.bin, $(ZK_SRC_FILES))
 
 daod: $(ZK_BIN_FILES)
-	cargo run
+	cargo run --release
 
 proof/%.zk.bin: proof/%.zk
 	zkas $<

+ 3 - 5
bin/daod/src/dao_contract/mint/wallet.rs

@@ -14,6 +14,7 @@ use rand::rngs::OsRng;
 use crate::{
     dao_contract::mint::validate::CallData,
     demo::{CallDataBase, FuncCall, ZkContractInfo, ZkContractTable},
+    util::poseidon_hash,
 };
 
 pub struct Builder {
@@ -55,7 +56,7 @@ impl Builder {
         let dao_public_x = *dao_pubkey_coords.x();
         let dao_public_y = *dao_pubkey_coords.x();
 
-        let messages = [
+        let dao_bulla = poseidon_hash::<8>([
             dao_proposer_limit,
             dao_quorum,
             dao_approval_ratio,
@@ -65,10 +66,7 @@ impl Builder {
             self.dao_bulla_blind,
             // @tmp-workaround
             self.dao_bulla_blind,
-        ];
-        let dao_bulla =
-            poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<8>, 3, 2>::init()
-                .hash(messages);
+        ]);
         let dao_bulla = DaoBulla(dao_bulla);
 
         // Now create the mint proof

+ 11 - 3
bin/daod/src/dao_contract/propose/validate.rs

@@ -3,6 +3,11 @@ use crate::{
     demo::{CallDataBase, StateRegistry, Transaction},
 };
 use darkfi::crypto::types::DrkCircuitField;
+use pasta_curves::{
+    arithmetic::CurveAffine,
+    group::{ff::Field, Curve},
+    pallas,
+};
 use std::any::{Any, TypeId};
 
 #[derive(Debug, Clone, thiserror::Error)]
@@ -12,15 +17,18 @@ pub enum Error {
 }
 type Result<T> = std::result::Result<T, Error>;
 
-pub struct CallData {}
+pub struct CallData {
+    // TODO: remove this! only tmp
+    pub dao_bulla: pallas::Base,
+}
 
 impl CallDataBase for CallData {
     fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
-        vec![]
+        vec![vec![self.dao_bulla]]
     }
 
     fn zk_proof_addrs(&self) -> Vec<String> {
-        vec![]
+        vec!["dao-propose-main".to_string()]
     }
 
     fn as_any(&self) -> &dyn Any {

+ 56 - 9
bin/daod/src/dao_contract/propose/wallet.rs

@@ -1,8 +1,10 @@
+use halo2_proofs::circuit::Value;
 use pasta_curves::{
     arithmetic::CurveAffine,
     group::{ff::Field, Curve},
     pallas,
 };
+use rand::rngs::OsRng;
 
 use darkfi::{
     crypto::{
@@ -26,13 +28,14 @@ use crate::{
     dao_contract::propose::validate::CallData,
     demo::{CallDataBase, FuncCall, ZkContractInfo, ZkContractTable},
     money_contract,
+    util::poseidon_hash,
 };
 
 pub struct Input {
-    //pub leaf_position: incrementalmerkletree::Position,
-    //pub merkle_path: Vec<MerkleNode>,
     pub secret: SecretKey,
     pub note: money_contract::transfer::wallet::Note,
+    pub leaf_position: incrementalmerkletree::Position,
+    pub merkle_path: Vec<MerkleNode>,
 }
 
 pub struct Proposal {
@@ -44,12 +47,12 @@ pub struct Proposal {
 }
 
 pub struct DaoParams {
-    pub dao_proposer_limit: u64,
-    pub dao_quorum: u64,
-    pub dao_approval_ratio: u64,
+    pub proposer_limit: u64,
+    pub quorum: u64,
+    pub approval_ratio: u64,
     pub gov_token_id: pallas::Base,
-    pub dao_public_key: PublicKey,
-    pub dao_bulla_blind: pallas::Base,
+    pub public_key: PublicKey,
+    pub bulla_blind: pallas::Base,
 }
 
 pub struct Builder {
@@ -60,12 +63,56 @@ pub struct Builder {
 
 impl Builder {
     pub fn build(self, zk_bins: &ZkContractTable) -> FuncCall {
-        let call_data = CallData {};
+        let dao_proposer_limit = pallas::Base::from(self.dao.proposer_limit);
+        let dao_quorum = pallas::Base::from(self.dao.quorum);
+        let dao_approval_ratio = pallas::Base::from(self.dao.approval_ratio);
+
+        let dao_pubkey_coords = self.dao.public_key.0.to_affine().coordinates().unwrap();
+        let dao_public_x = *dao_pubkey_coords.x();
+        let dao_public_y = *dao_pubkey_coords.x();
+
+        let dao_bulla = poseidon_hash::<8>([
+            dao_proposer_limit,
+            dao_quorum,
+            dao_approval_ratio,
+            self.dao.gov_token_id,
+            dao_public_x,
+            dao_public_y,
+            self.dao.bulla_blind,
+            // @tmp-workaround
+            self.dao.bulla_blind,
+        ]);
+
+        let zk_info = zk_bins.lookup(&"dao-propose-main".to_string()).unwrap();
+        let zk_info = if let ZkContractInfo::Binary(info) = zk_info {
+            info
+        } else {
+            panic!("Not binary info")
+        };
+        let zk_bin = zk_info.bincode.clone();
+        let prover_witnesses = vec![
+            Witness::Base(Value::known(dao_proposer_limit)),
+            Witness::Base(Value::known(dao_quorum)),
+            Witness::Base(Value::known(dao_approval_ratio)),
+            Witness::Base(Value::known(self.dao.gov_token_id)),
+            Witness::Base(Value::known(dao_public_x)),
+            Witness::Base(Value::known(dao_public_y)),
+            Witness::Base(Value::known(self.dao.bulla_blind)),
+        ];
+        let public_inputs = vec![dao_bulla];
+        let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
+
+        let proving_key = &zk_info.proving_key;
+        let main_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
+            .expect("DAO::propose() proving error!");
+
+        let call_data = CallData { dao_bulla };
+
         FuncCall {
             contract_id: "DAO".to_string(),
             func_id: "DAO::propose()".to_string(),
             call_data: Box::new(call_data),
-            proofs: vec![],
+            proofs: vec![main_proof],
         }
     }
 }

+ 47 - 17
bin/daod/src/demo.rs

@@ -42,7 +42,7 @@ use darkfi::{
     zkas::decoder::ZkBinary,
 };
 
-use crate::{dao_contract, money_contract};
+use crate::{dao_contract, money_contract, util::poseidon_hash};
 
 // TODO: reenable unused vars warning and fix it
 // TODO: strategize and cleanup Result/Error usage
@@ -210,10 +210,12 @@ pub async fn demo() -> Result<()> {
 
     // Initialize ZK binary table
     let mut zk_bins = ZkContractTable::new();
+    debug!(target: "demo", "Loading dao-mint.zk");
     let zk_dao_mint_bincode = include_bytes!("../proof/dao-mint.zk.bin");
     let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
     zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
 
+    debug!(target: "demo", "Loading money-transfer contracts");
     {
         let start = Instant::now();
         let mint_pk = ProvingKey::build(11, &MintContract::default());
@@ -231,6 +233,10 @@ pub async fn demo() -> Result<()> {
         zk_bins.add_native("money-transfer-mint".to_string(), mint_pk, mint_vk);
         zk_bins.add_native("money-transfer-burn".to_string(), burn_pk, burn_vk);
     }
+    debug!(target: "demo", "Loading dao-propose-main.zk");
+    let zk_dao_propose_main_bincode = include_bytes!("../proof/dao-propose-main.zk.bin");
+    let zk_dao_propose_main_bin = ZkBinary::decode(zk_dao_propose_main_bincode)?;
+    zk_bins.add_contract("dao-propose-main".to_string(), zk_dao_propose_main_bin, 13);
 
     // State for money contracts
     let cashier_signature_secret = SecretKey::random(&mut OsRng);
@@ -257,7 +263,7 @@ pub async fn demo() -> Result<()> {
     /////////////////////////////////////////////////////
     ////// Create the DAO bulla
     /////////////////////////////////////////////////////
-    debug!(target: "demo", "1. Creating DAO bulla");
+    debug!(target: "demo", "Stage 1. Creating DAO bulla");
 
     //// Wallet
 
@@ -309,7 +315,7 @@ pub async fn demo() -> Result<()> {
     //// Mint the initial supply of treasury token
     //// and send it all to the DAO directly
     ///////////////////////////////////////////////////
-    debug!(target: "demo", "2. Minting treasury token");
+    debug!(target: "demo", "Stage 2. Minting treasury token");
 
     let state = states.lookup_mut::<money_contract::State>(&"Money".to_string()).unwrap();
     state.wallet_cache.track(dao_keypair.secret);
@@ -360,7 +366,7 @@ pub async fn demo() -> Result<()> {
             debug!("money_contract::transfer::state_transition()");
 
             let update = money_contract::transfer::validate::state_transition(&states, idx, &tx)
-                .expect("money_contract::state_transition() failed!");
+                .expect("money_contract::transfer::validate::state_transition() failed!");
             money_contract::transfer::validate::apply(&mut states, update);
         }
     }
@@ -404,7 +410,7 @@ pub async fn demo() -> Result<()> {
     //// Mint the governance token
     //// Send it to three hodlers
     ///////////////////////////////////////////////////
-    debug!(target: "demo", "3. Minting governance token");
+    debug!(target: "demo", "Stage 3. Minting governance token");
 
     //// Wallet
 
@@ -478,7 +484,7 @@ pub async fn demo() -> Result<()> {
             debug!("money_contract::transfer::state_transition()");
 
             let update = money_contract::transfer::validate::state_transition(&states, idx, &tx)
-                .expect("money_contract::state_transition() failed!");
+                .expect("money_contract::transfer::validate::state_transition() failed!");
             money_contract::transfer::validate::apply(&mut states, update);
         }
     }
@@ -540,7 +546,7 @@ pub async fn demo() -> Result<()> {
     // In order to make a valid vote, first the proposer must
     // meet a criteria for a minimum number of gov tokens
     ///////////////////////////////////////////////////
-    debug!(target: "demo", "4. Propose the vote");
+    debug!(target: "demo", "Stage 4. Propose the vote");
 
     //// Wallet
 
@@ -548,11 +554,22 @@ pub async fn demo() -> Result<()> {
 
     let user_keypair = Keypair::random(&mut OsRng);
 
+    let (leaf_position, merkle_path) = {
+        let state = states.lookup::<money_contract::State>(&"Money".to_string()).unwrap();
+        let tree = &state.tree;
+        let leaf_position = gov_recv[0].leaf_position.clone();
+        let root = tree.root(0).unwrap();
+        let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
+        (leaf_position, merkle_path)
+    };
+
     // TODO: is it possible for an invalid transfer() to be constructed on exec()?
     //       need to look into this
     let input = dao_contract::propose::wallet::Input {
         secret: gov_keypair_1.secret,
         note: gov_recv[0].note.clone(),
+        leaf_position,
+        merkle_path,
     };
 
     let builder = dao_contract::propose::wallet::Builder {
@@ -565,21 +582,34 @@ pub async fn demo() -> Result<()> {
             blind: pallas::Base::random(&mut OsRng),
         },
         dao: dao_contract::propose::wallet::DaoParams {
-            dao_proposer_limit,
-            dao_quorum,
-            dao_approval_ratio,
+            proposer_limit: dao_proposer_limit,
+            quorum: dao_quorum,
+            approval_ratio: dao_approval_ratio,
             gov_token_id: gdrk_token_id,
-            dao_public_key: dao_keypair.public,
-            dao_bulla_blind,
+            public_key: dao_keypair.public,
+            bulla_blind: dao_bulla_blind,
         },
     };
 
     let func_call = builder.build(&zk_bins);
 
-    Ok(())
-}
+    let tx = Transaction { func_calls: vec![func_call] };
+
+    //// Validator
+
+    for (idx, func_call) in tx.func_calls.iter().enumerate() {
+        if func_call.func_id == "DAO::propose()" {
+            debug!(target: "demo", "dao_contract::propose::state_transition()");
 
-fn poseidon_hash<const N: usize>(messages: [pallas::Base; N]) -> pallas::Base {
-    poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<N>, 3, 2>::init()
-        .hash(messages)
+            let update = dao_contract::propose::validate::state_transition(&states, idx, &tx)
+                .expect("dao_contract::propose::validate::state_transition() failed!");
+            dao_contract::propose::validate::apply(&mut states, update);
+        }
+    }
+
+    tx.zk_verify(&zk_bins);
+
+    //// Wallet
+
+    Ok(())
 }

+ 1 - 0
bin/daod/src/main.rs

@@ -18,6 +18,7 @@ mod dao_contract;
 mod demo;
 mod money_contract;
 mod note;
+mod util;
 use crate::demo::demo;
 
 async fn _start() -> Result<()> {