Przeglądaj źródła

daod: update demo.rs with dao submodule. change money_contract::FuncCall to money_contract::CallData. add TODOs for money_contract

lunar-mining 4 lat temu
rodzic
commit
a3bf281894

+ 121 - 0
bin/daod/src/dao_contract/mint/builder.rs

@@ -0,0 +1,121 @@
+use std::any::Any;
+
+use crate::dao_contract::state::DaoBulla;
+
+use darkfi::{
+    crypto::{keypair::PublicKey, types::DrkCircuitField, Proof},
+    zk::vm::{Witness, ZkCircuit},
+};
+use halo2_gadgets::poseidon::primitives as poseidon;
+use halo2_proofs::circuit::Value;
+use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas};
+use rand::rngs::OsRng;
+
+use crate::{demo::FuncCall, CallDataBase, ZkBinaryTable};
+
+pub struct Builder {
+    dao_proposer_limit: u64,
+    dao_quorum: u64,
+    dao_approval_ratio: u64,
+    gov_token_id: pallas::Base,
+    dao_pubkey: PublicKey,
+    dao_bulla_blind: pallas::Base,
+}
+
+impl Builder {
+    pub fn new(
+        dao_proposer_limit: u64,
+        dao_quorum: u64,
+        dao_approval_ratio: u64,
+        gov_token_id: pallas::Base,
+        dao_pubkey: PublicKey,
+        dao_bulla_blind: pallas::Base,
+    ) -> Self {
+        Self {
+            dao_proposer_limit,
+            dao_quorum,
+            dao_approval_ratio,
+            gov_token_id,
+            dao_pubkey,
+            dao_bulla_blind,
+        }
+    }
+
+    /// Consumes self, and produces the function call
+    pub fn build(self, zk_bins: &ZkBinaryTable) -> FuncCall {
+        // Dao bulla
+        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_pubkey.0.to_affine().coordinates().unwrap();
+        let dao_public_x = *dao_pubkey_coords.x();
+        let dao_public_y = *dao_pubkey_coords.x();
+
+        let messages = [
+            dao_proposer_limit,
+            dao_quorum,
+            dao_approval_ratio,
+            self.gov_token_id,
+            dao_public_x,
+            dao_public_y,
+            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
+        let zk_info = zk_bins.lookup(&"dao-mint".to_string()).unwrap();
+        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.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.0];
+        let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
+
+        let proving_key = &zk_info.proving_key;
+        let mint_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
+            .expect("DAO::mint() proving error!");
+
+        // [x] 1. move proving key to zkbins table (and k value)
+        // [x] 2. do verification of zk proofs in main code
+        // [ ] 3. implement apply(update) function
+
+        // Return call data
+        let call_data = CallData { dao_bulla };
+        FuncCall {
+            contract_id: "DAO".to_string(),
+            func_id: "DAO::mint()".to_string(),
+            call_data: Box::new(call_data),
+            proofs: vec![mint_proof],
+        }
+    }
+}
+
+pub struct CallData {
+    dao_bulla: DaoBulla,
+}
+
+impl CallDataBase for CallData {
+    fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
+        vec![vec![self.dao_bulla.0]]
+    }
+
+    fn zk_proof_addrs(&self) -> Vec<String> {
+        vec!["dao-mint".to_string()]
+    }
+
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}

+ 62 - 0
bin/daod/src/dao_contract/mint/mod.rs

@@ -0,0 +1,62 @@
+use std::any::Any;
+
+use darkfi::crypto::types::DrkCircuitField;
+
+use super::state::DaoBulla;
+use crate::demo::CallDataBase;
+
+pub mod builder;
+pub use builder::Builder;
+
+/// This is an anonymous contract function that mutates the internal DAO state.
+///
+/// Corresponds to `mint(proposer_limit, quorum, approval_ratio, dao_pubkey, dao_blind)`
+///
+/// The prover creates a `Builder`, which then constructs the `Tx` that the verifier can
+/// check using `state_transition()`.
+///
+/// # Arguments
+///
+/// * `proposer_limit` - Number of governance tokens that holder must possess in order to
+///   propose a new vote.
+/// * `quorum` - Number of minimum votes that must be met for a proposal to pass.
+/// * `approval_ratio` - Ratio of winning to total votes for a proposal to pass.
+/// * `dao_pubkey` - Public key of the DAO for permissioned access. This can also be
+///   shared publicly if you want a full decentralized DAO.
+/// * `dao_blind` - Blinding factor for the DAO bulla.
+///
+/// # Example
+///
+/// ```rust
+/// let dao_proposer_limit = 110;
+/// let dao_quorum = 110;
+/// let dao_approval_ratio = 2;
+///
+/// let builder = dao_contract::Mint::Builder(
+///     dao_proposer_limit,
+///     dao_quorum,
+///     dao_approval_ratio,
+///     gov_token_id,
+///     dao_pubkey,
+///     dao_blind
+/// );
+/// let tx = builder.build();
+/// ```
+
+pub struct CallData {
+    pub dao_bulla: DaoBulla,
+}
+
+impl CallDataBase for CallData {
+    fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
+        vec![vec![self.dao_bulla.0]]
+    }
+
+    fn zk_proof_addrs(&self) -> Vec<String> {
+        vec!["dao-mint".to_string()]
+    }
+
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}

+ 0 - 0
bin/daod/src/dao_contract/mint/partial.rs


+ 13 - 0
bin/daod/src/dao_contract/mod.rs

@@ -0,0 +1,13 @@
+#![allow(unused)]
+
+pub mod mint;
+pub mod state;
+
+pub use state::{DaoBulla, State};
+
+#[derive(Debug, Clone, thiserror::Error)]
+pub enum Error {
+    #[error("Malformed packet")]
+    MalformedPacket,
+}
+type Result<T> = std::result::Result<T, Error>;

+ 57 - 0
bin/daod/src/dao_contract/state.rs

@@ -0,0 +1,57 @@
+use pasta_curves::pallas;
+use std::any::{Any, TypeId};
+
+use crate::{
+    dao_contract::mint::CallData,
+    demo::{StateRegistry, Transaction},
+    Result,
+};
+
+#[derive(Clone)]
+pub struct DaoBulla(pub pallas::Base);
+
+/// This DAO state is for all DAOs on the network. There should only be a single instance.
+pub struct State {
+    dao_bullas: Vec<DaoBulla>,
+}
+
+impl State {
+    pub fn new() -> Box<dyn Any> {
+        Box::new(Self { dao_bullas: Vec::new() })
+    }
+
+    pub fn add_bulla(&mut self, bulla: DaoBulla) {
+        self.dao_bullas.push(bulla);
+    }
+}
+
+pub fn state_transition(
+    states: &StateRegistry,
+    func_call_index: usize,
+    parent_tx: &Transaction,
+) -> Result<Update> {
+    let func_call = &parent_tx.func_calls[func_call_index];
+    let call_data = func_call.call_data.as_any();
+
+    assert_eq!((&*call_data).type_id(), TypeId::of::<CallData>());
+    let call_data = call_data.downcast_ref::<CallData>();
+
+    // This will be inside wasm so unwrap is fine.
+    let call_data = call_data.unwrap();
+
+    // Code goes here
+
+    Ok(Update { dao_bulla: call_data.dao_bulla.clone() })
+}
+
+pub struct Update {
+    pub dao_bulla: DaoBulla,
+}
+
+pub fn apply(states: &mut StateRegistry, update: Update) {
+    // Lookup dao_contract state from registry
+    //let state = states.lookup::<super::State>(&"dao_contract".to_string()).unwrap();
+    let state = states.lookup::<State>(&"dao_contract".to_string()).unwrap();
+    // Add dao_bulla to state.dao_bullas
+    state.add_bulla(update.dao_bulla);
+}

+ 31 - 244
bin/daod/src/demo.rs

@@ -16,8 +16,6 @@ use std::{
     time::Instant,
 };
 
-use crate::money_contract;
-
 use darkfi::{
     crypto::{
         constants::MERKLE_DEPTH,
@@ -30,7 +28,7 @@ use darkfi::{
         types::DrkCircuitField,
         OwnCoin, OwnCoins, Proof,
     },
-    node::state::{state_transition, ProgramState, StateUpdate},
+    node::state::{ProgramState, StateUpdate},
     tx::builder::{
         TransactionBuilder, TransactionBuilderClearInputInfo, TransactionBuilderInputInfo,
         TransactionBuilderOutputInfo,
@@ -44,6 +42,14 @@ use darkfi::{
     zkas::decoder::ZkBinary,
 };
 
+use crate::{
+    dao_contract::{
+        mint::Builder,
+        state::{apply, state_transition, DaoBulla, State},
+    },
+    money_contract,
+};
+
 /// The state machine, held in memory.
 struct MemoryState {
     /// The entire Merkle tree state
@@ -140,237 +146,6 @@ impl ZkBinaryTable {
     }
 }
 
-mod dao_contract {
-    use pasta_curves::pallas;
-    use std::any::Any;
-
-    #[derive(Clone)]
-    pub struct DaoBulla(pub pallas::Base);
-
-    /// This DAO state is for all DAOs on the network. There should only be a single instance.
-    pub struct State {
-        dao_bullas: Vec<DaoBulla>,
-    }
-
-    impl State {
-        pub fn new() -> Box<dyn Any> {
-            Box::new(Self { dao_bullas: Vec::new() })
-        }
-
-        pub fn add_bulla(&mut self, bulla: DaoBulla) {
-            self.dao_bullas.push(bulla);
-        }
-    }
-
-    /// This is an anonymous contract function that mutates the internal DAO state.
-    ///
-    /// Corresponds to `mint(proposer_limit, quorum, approval_ratio, dao_pubkey, dao_blind)`
-    ///
-    /// The prover creates a `Builder`, which then constructs the `Tx` that the verifier can
-    /// check using `state_transition()`.
-    ///
-    /// # Arguments
-    ///
-    /// * `proposer_limit` - Number of governance tokens that holder must possess in order to
-    ///   propose a new vote.
-    /// * `quorum` - Number of minimum votes that must be met for a proposal to pass.
-    /// * `approval_ratio` - Ratio of winning to total votes for a proposal to pass.
-    /// * `dao_pubkey` - Public key of the DAO for permissioned access. This can also be
-    ///   shared publicly if you want a full decentralized DAO.
-    /// * `dao_blind` - Blinding factor for the DAO bulla.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// let dao_proposer_limit = 110;
-    /// let dao_quorum = 110;
-    /// let dao_approval_ratio = 2;
-    ///
-    /// let builder = dao_contract::Mint::Builder(
-    ///     dao_proposer_limit,
-    ///     dao_quorum,
-    ///     dao_approval_ratio,
-    ///     gov_token_id,
-    ///     dao_pubkey,
-    ///     dao_blind
-    /// );
-    /// let tx = builder.build();
-    /// ```
-    pub mod mint {
-        use darkfi::{
-            crypto::{keypair::PublicKey, proof::ProvingKey, types::DrkCircuitField, Proof},
-            zk::vm::{Witness, ZkCircuit},
-        };
-        use halo2_gadgets::poseidon::primitives as poseidon;
-        use halo2_proofs::circuit::Value;
-        use log::debug;
-        use pasta_curves::{
-            arithmetic::CurveAffine,
-            group::{ff::Field, Curve},
-            pallas,
-        };
-        use rand::rngs::OsRng;
-        use std::{
-            any::{Any, TypeId},
-            time::Instant,
-        };
-
-        use super::{
-            super::{CallDataBase, FuncCall, StateRegistry, Transaction, ZkBinaryTable},
-            DaoBulla,
-        };
-
-        pub struct Builder {
-            dao_proposer_limit: u64,
-            dao_quorum: u64,
-            dao_approval_ratio: u64,
-            gov_token_id: pallas::Base,
-            dao_pubkey: PublicKey,
-            dao_bulla_blind: pallas::Base,
-        }
-
-        impl Builder {
-            pub fn new(
-                dao_proposer_limit: u64,
-                dao_quorum: u64,
-                dao_approval_ratio: u64,
-                gov_token_id: pallas::Base,
-                dao_pubkey: PublicKey,
-                dao_bulla_blind: pallas::Base,
-            ) -> Self {
-                Self {
-                    dao_proposer_limit,
-                    dao_quorum,
-                    dao_approval_ratio,
-                    gov_token_id,
-                    dao_pubkey,
-                    dao_bulla_blind,
-                }
-            }
-
-            /// Consumes self, and produces the function call
-            pub fn build(self, zk_bins: &ZkBinaryTable) -> FuncCall {
-                // Dao bulla
-                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_pubkey.0.to_affine().coordinates().unwrap();
-                let dao_public_x = *dao_pubkey_coords.x();
-                let dao_public_y = *dao_pubkey_coords.x();
-
-                let messages = [
-                    dao_proposer_limit,
-                    dao_quorum,
-                    dao_approval_ratio,
-                    self.gov_token_id,
-                    dao_public_x,
-                    dao_public_y,
-                    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
-                let zk_info = zk_bins.lookup(&"dao-mint".to_string()).unwrap();
-                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.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.0];
-                let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
-
-                let proving_key = &zk_info.proving_key;
-                let mint_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
-                    .expect("DAO::mint() proving error!");
-
-                // [x] 1. move proving key to zkbins table (and k value)
-                // [x] 2. do verification of zk proofs in main code
-                // [ ] 3. implement apply(update) function
-
-                // Return call data
-                let call_data = CallData { dao_bulla };
-                FuncCall {
-                    contract_id: "DAO".to_string(),
-                    func_id: "DAO::mint()".to_string(),
-                    call_data: Box::new(call_data),
-                    proofs: vec![mint_proof],
-                }
-            }
-        }
-
-        pub struct CallData {
-            dao_bulla: DaoBulla,
-        }
-
-        impl CallDataBase for CallData {
-            fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
-                vec![vec![self.dao_bulla.0]]
-            }
-
-            fn zk_proof_addrs(&self) -> Vec<String> {
-                vec!["dao-mint".to_string()]
-            }
-
-            fn as_any(&self) -> &dyn Any {
-                self
-            }
-        }
-
-        #[derive(Debug, Clone, thiserror::Error)]
-        pub enum Error {
-            #[error("Malformed packet")]
-            MalformedPacket,
-        }
-        type Result<T> = std::result::Result<T, Error>;
-
-        pub fn state_transition(
-            states: &StateRegistry,
-            func_call_index: usize,
-            parent_tx: &Transaction,
-        ) -> Result<Update> {
-            let func_call = &parent_tx.func_calls[func_call_index];
-            let call_data = func_call.call_data.as_any();
-
-            assert_eq!((&*call_data).type_id(), TypeId::of::<CallData>());
-            let call_data = call_data.downcast_ref::<CallData>();
-
-            // This will be inside wasm so unwrap is fine.
-            let call_data = call_data.unwrap();
-
-            // Code goes here
-
-            Ok(Update { dao_bulla: call_data.dao_bulla.clone() })
-        }
-
-        pub struct Update {
-            dao_bulla: DaoBulla,
-        }
-
-        pub fn apply(states: &mut StateRegistry, update: Update) {
-            // Lookup dao_contract state from registry
-            let state = states.lookup::<super::State>(&"dao_contract".to_string()).unwrap();
-            // Add dao_bulla to state.dao_bullas
-            state.add_bulla(update.dao_bulla);
-        }
-    }
-}
-
 macro_rules! zip {
     ($x: expr) => ($x);
     ($x: expr, $($y: expr), +) => (
@@ -380,7 +155,7 @@ macro_rules! zip {
 }
 
 pub struct Transaction {
-    func_calls: Vec<FuncCall>,
+    pub func_calls: Vec<FuncCall>,
 }
 
 impl Transaction {
@@ -410,10 +185,10 @@ type ContractId = String;
 type FuncId = String;
 
 pub struct FuncCall {
-    contract_id: ContractId,
-    func_id: FuncId,
-    call_data: Box<dyn CallDataBase>,
-    proofs: Vec<Proof>,
+    pub contract_id: ContractId,
+    pub func_id: FuncId,
+    pub call_data: Box<dyn CallDataBase>,
+    pub proofs: Vec<Proof>,
 }
 
 pub trait CallDataBase {
@@ -443,7 +218,7 @@ impl StateRegistry {
         self.states.insert(contract_id, state);
     }
 
-    fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
+    pub fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
         self.states.get_mut(contract_id).and_then(|state| state.downcast_mut())
     }
 }
@@ -474,6 +249,17 @@ pub async fn demo() -> Result<()> {
     /////////////////////////////////////////////////
 
     /*
+    TODO: The following money_contract behaviors are still unimplemented:
+
+    [ ] money_contract/transfer/builder.rs.
+        The mint proof is currently part of its outputs and CallData::proofs is an empty vector.
+    [ ] CallDataBase
+        Not fully implemented for money_contract/mint/mod::CallData.
+    [ ] money_contract/state.rs
+        State transition function is totally unimplemented.
+
+    /////////////////////////////////////////////////
+
     // State for money contracts
     let cashier_signature_secret = SecretKey::random(&mut OsRng);
     let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
@@ -501,7 +287,8 @@ pub async fn demo() -> Result<()> {
 
     /////////////////////////////////////////////////
 
-    let dao_state = dao_contract::State::new();
+    let dao_state = State::new();
+    //let dao_state = State::new();
     states.register("dao_contract".to_string(), dao_state);
 
     // For this demo lets create 10 random preexisting DAO bullas
@@ -518,7 +305,7 @@ pub async fn demo() -> Result<()> {
     let dao_bulla_blind = pallas::Base::random(&mut OsRng);
 
     // Create DAO mint tx
-    let builder = dao_contract::mint::Builder::new(
+    let builder = Builder::new(
         dao_proposer_limit,
         dao_quorum,
         dao_approval_ratio,
@@ -536,8 +323,8 @@ pub async fn demo() -> Result<()> {
         if func_call.func_id == "DAO::mint()" {
             debug!("dao_contract::mint::state_transition()");
 
-            let update = dao_contract::mint::state_transition(&states, idx, &tx).unwrap();
-            dao_contract::mint::apply(&mut states, update);
+            let update = state_transition(&states, idx, &tx).unwrap();
+            apply(&mut states, update);
         }
     }
 

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

@@ -14,8 +14,11 @@ use darkfi::{
     Result,
 };
 
+mod dao_contract;
 mod demo;
 mod money_contract;
+pub use demo::{CallDataBase, StateRegistry, Transaction, ZkBinaryTable, ZkContractInfo};
+
 use crate::demo::demo;
 
 async fn _start() -> Result<()> {

+ 51 - 48
bin/daod/src/money_contract/mod.rs

@@ -1,3 +1,6 @@
+#![allow(unused)]
+
+pub mod state;
 pub mod transfer;
 
 /*
@@ -10,61 +13,61 @@ pub mod transfer;
 
 /////////////////////////////////////////////////
 
-   let token_id = pallas::Base::random(&mut OsRng);
+let token_id = pallas::Base::random(&mut OsRng);
 
-   let builder = TransactionBuilder {
-       clear_inputs: vec![TransactionBuilderClearInputInfo {
-           value: 110,
-           token_id,
-           signature_secret: cashier_signature_secret,
-       }],
-       inputs: vec![],
-       outputs: vec![TransactionBuilderOutputInfo {
-           value: 110,
-           token_id,
-           public: keypair.public,
-       }],
-   };
+let builder = TransactionBuilder {
+    clear_inputs: vec![TransactionBuilderClearInputInfo {
+        value: 110,
+        token_id,
+        signature_secret: cashier_signature_secret,
+    }],
+    inputs: vec![],
+    outputs: vec![TransactionBuilderOutputInfo {
+        value: 110,
+        token_id,
+        public: keypair.public,
+    }],
+};
 
-   let start = Instant::now();
-   let mint_pk = ProvingKey::build(11, &MintContract::default());
-   debug!("Mint PK: [{:?}]", start.elapsed());
-   let start = Instant::now();
-   let burn_pk = ProvingKey::build(11, &BurnContract::default());
-   debug!("Burn PK: [{:?}]", start.elapsed());
-   let tx = builder.build(&mint_pk, &burn_pk)?;
+let start = Instant::now();
+let mint_pk = ProvingKey::build(11, &MintContract::default());
+debug!("Mint PK: [{:?}]", start.elapsed());
+let start = Instant::now();
+let burn_pk = ProvingKey::build(11, &BurnContract::default());
+debug!("Burn PK: [{:?}]", start.elapsed());
+let tx = builder.build(&mint_pk, &burn_pk)?;
 
-   tx.verify(&money_state.mint_vk, &money_state.burn_vk)?;
+tx.verify(&money_state.mint_vk, &money_state.burn_vk)?;
 
-   let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret)?;
+let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret)?;
 
-   let update = state_transition(&money_state, tx)?;
-   money_state.apply(update);
+let update = state_transition(&money_state, tx)?;
+money_state.apply(update);
 
-   // Now spend
-   let owncoin = &money_state.own_coins[0];
-   let note = &owncoin.note;
-   let leaf_position = owncoin.leaf_position;
-   let root = money_state.tree.root(0).unwrap();
-   let merkle_path = money_state.tree.authentication_path(leaf_position, &root).unwrap();
+// Now spend
+let owncoin = &money_state.own_coins[0];
+let note = &owncoin.note;
+let leaf_position = owncoin.leaf_position;
+let root = money_state.tree.root(0).unwrap();
+let merkle_path = money_state.tree.authentication_path(leaf_position, &root).unwrap();
 
-   let builder = TransactionBuilder {
-       clear_inputs: vec![],
-       inputs: vec![TransactionBuilderInputInfo {
-           leaf_position,
-           merkle_path,
-           secret: keypair.secret,
-           note: note.clone(),
-       }],
-       outputs: vec![TransactionBuilderOutputInfo {
-           value: 110,
-           token_id,
-           public: keypair.public,
-       }],
-   };
+let builder = TransactionBuilder {
+    clear_inputs: vec![],
+    inputs: vec![TransactionBuilderInputInfo {
+        leaf_position,
+        merkle_path,
+        secret: keypair.secret,
+        note: note.clone(),
+    }],
+    outputs: vec![TransactionBuilderOutputInfo {
+        value: 110,
+        token_id,
+        public: keypair.public,
+    }],
+};
 
-   let tx = builder.build(&mint_pk, &burn_pk)?;
+let tx = builder.build(&mint_pk, &burn_pk)?;
 
-   let update = state_transition(&money_state, tx)?;
-   money_state.apply(update);
+let update = state_transition(&money_state, tx)?;
+money_state.apply(update);
 */

+ 73 - 0
bin/daod/src/money_contract/state.rs

@@ -0,0 +1,73 @@
+use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
+
+use darkfi::{
+    crypto::{
+        constants::MERKLE_DEPTH, keypair::PublicKey, merkle_node::MerkleNode, nullifier::Nullifier,
+        proof::VerifyingKey,
+    },
+    node::state::{ProgramState, StateUpdate},
+};
+
+/// The state machine, held in memory.
+struct State {
+    /// The entire Merkle tree state
+    tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
+    /// List of all previous and the current Merkle roots.
+    /// This is the hashed value of all the children.
+    merkle_roots: Vec<MerkleNode>,
+    /// Nullifiers prevent double spending
+    nullifiers: Vec<Nullifier>,
+    /// Verifying key for the mint zk circuit.
+    mint_vk: VerifyingKey,
+    /// Verifying key for the burn zk circuit.
+    burn_vk: VerifyingKey,
+
+    /// Public key of the cashier
+    cashier_signature_public: PublicKey,
+
+    /// Public key of the faucet
+    faucet_signature_public: PublicKey,
+}
+
+impl ProgramState for State {
+    fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool {
+        public == &self.cashier_signature_public
+    }
+
+    fn is_valid_faucet_public_key(&self, public: &PublicKey) -> bool {
+        public == &self.faucet_signature_public
+    }
+
+    fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
+        self.merkle_roots.iter().any(|m| m == merkle_root)
+    }
+
+    fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
+        self.nullifiers.iter().any(|n| n == nullifier)
+    }
+
+    fn mint_vk(&self) -> &VerifyingKey {
+        &self.mint_vk
+    }
+
+    fn burn_vk(&self) -> &VerifyingKey {
+        &self.burn_vk
+    }
+}
+
+impl State {
+    fn apply(&mut self, mut update: StateUpdate) {
+        // Extend our list of nullifiers with the ones from the update
+        self.nullifiers.append(&mut update.nullifiers);
+
+        // Update merkle tree and witnesses
+        for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.into_iter()) {
+            // Add the new coins to the Merkle tree
+            let node = MerkleNode(coin.0);
+            self.tree.append(&node);
+
+            // Keep track of all Merkle roots that have existed
+            self.merkle_roots.push(self.tree.root(0).unwrap());
+        }
+    }
+}

+ 11 - 2
bin/daod/src/money_contract/transfer/builder.rs

@@ -3,8 +3,9 @@ use rand::rngs::OsRng;
 
 use super::{
     partial::{Partial, PartialClearInput, PartialInput},
-    ClearInput, FuncCall, Input, Output,
+    CallData, ClearInput, Input, Output,
 };
+use crate::demo::FuncCall;
 
 use darkfi::{
     crypto::{
@@ -184,6 +185,14 @@ impl Builder {
             inputs.push(input);
         }
 
-        Ok(FuncCall { clear_inputs, inputs, outputs: partial_tx.outputs })
+        let call_data = CallData { clear_inputs, inputs, outputs: partial_tx.outputs };
+
+        // TODO: Proofs is an empty vector right now.
+        Ok(FuncCall {
+            contract_id: "money".to_string(),
+            func_id: "money::transfer()".to_string(),
+            call_data: Box::new(call_data),
+            proofs: vec![],
+        })
     }
 }

+ 21 - 4
bin/daod/src/money_contract/transfer/mod.rs

@@ -1,4 +1,4 @@
-use std::io;
+use std::{any::Any, io};
 
 use log::error;
 use pasta_curves::group::Group;
@@ -12,7 +12,7 @@ use darkfi::{
         proof::VerifyingKey,
         schnorr,
         schnorr::SchnorrPublic,
-        types::{DrkTokenId, DrkValueBlind, DrkValueCommit},
+        types::{DrkCircuitField, DrkTokenId, DrkValueBlind, DrkValueCommit},
         util::{pedersen_commitment_base, pedersen_commitment_u64},
         BurnRevealedValues, MintRevealedValues, Proof,
     },
@@ -20,12 +20,14 @@ use darkfi::{
     Result, VerifyFailed, VerifyResult,
 };
 
+use crate::demo::CallDataBase;
+
 pub mod builder;
 pub mod partial;
 
 /// A DarkFi transaction
 #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
-pub struct FuncCall {
+pub struct CallData {
     /// Clear inputs
     pub clear_inputs: Vec<ClearInput>,
     /// Anonymous inputs
@@ -34,6 +36,21 @@ pub struct FuncCall {
     pub outputs: Vec<Output>,
 }
 
+impl CallDataBase for CallData {
+    // TODO: Unimplemented
+    fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
+        vec![]
+    }
+
+    fn zk_proof_addrs(&self) -> Vec<String> {
+        vec!["money-transfer".to_string()]
+    }
+
+    fn as_any(&self) -> &dyn Any {
+        self
+    }
+}
+
 /// A transaction's clear input
 #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
 pub struct ClearInput {
@@ -73,7 +90,7 @@ pub struct Output {
     pub enc_note: EncryptedNote,
 }
 
-impl FuncCall {
+impl CallData {
     /// Verify the transaction
     pub fn verify(&self, mint_vk: &VerifyingKey, burn_vk: &VerifyingKey) -> VerifyResult<()> {
         //  must have minimum 1 clear or anon input, and 1 output