parazyd 4 лет назад
Родитель
Сommit
cde8b6d7e2
9 измененных файлов с 294 добавлено и 418 удалено
  1. 21 14
      src/bin/cashierd.rs
  2. 1 1
      src/bin/tx2.rs
  3. 3 0
      src/circuit/mod.rs
  4. 80 368
      src/client.rs
  5. 0 2
      src/crypto/coin.rs
  6. 10 0
      src/crypto/nullifier.rs
  7. 8 0
      src/crypto/schnorr.rs
  8. 126 3
      src/state.rs
  9. 45 30
      src/wallet/walletdb.rs

+ 21 - 14
src/bin/cashierd.rs

@@ -5,21 +5,24 @@ use async_std::sync::{Arc, Mutex};
 use async_trait::async_trait;
 use clap::clap_app;
 use easy_parallel::Parallel;
-use log::debug;
+use incrementalmerkletree::bridgetree::BridgeTree;
+use log::{debug, info};
 use pasta_curves::pallas;
 use serde_json::{json, Value};
 
 use drk::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
+    circuit::{MintContract, SpendContract},
     cli::{CashierdConfig, Config},
-    client::{Client, State},
-    crypto::{mint_proof::MintProofKeys, schnorr, spend_proof::SpendProofKeys},
+    client::Client,
+    crypto::{merkle_node::MerkleNode, proof::VerifyingKey, schnorr},
     rpc::{
         jsonrpc::{error as jsonerr, response as jsonresp, ErrorCode::*, JsonRequest, JsonResult},
         rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
     },
     serial::{deserialize, serialize},
     service::{bridge, bridge::Bridge},
+    state::State,
     types::DrkTokenId,
     util::{expand_path, generate_id, join_config_path, parse::truncate, NetworkName},
     wallet::{cashierdb::TokenKey, CashierDb, WalletDb},
@@ -342,13 +345,13 @@ impl Cashierd {
                 cashier_public = addr.public;
             } else {
                 let cashier_secret = schnorr::SecretKey::random();
-                cashier_public = cashier_secret.public_key();
+                cashier_public = cashier_secret.public_key().inner();
 
                 self.cashier_wallet
                     .put_withdraw_keys(
                         &address,
                         &cashier_public,
-                        &cashier_secret,
+                        &cashier_secret.inner(),
                         &network,
                         &token_id,
                         mint_address.into(),
@@ -669,15 +672,19 @@ async fn start(
 
     let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
 
-    let mint_proof_keys = MintProofKeys::initialize();
-    let spend_proof_keys = SpendProofKeys::initialize();
+    /*
+    let mint_pk = ProvingKey::build(11, MintContract::default());
+    let spend_pk = ProvingKey::build(11, SpendContract::default());
+    */
+    info!("Building verifying key for the mint contract...");
+    let mint_vk = VerifyingKey::build(11, MintContract::default());
+    info!("Building verifying key for the spend contract...");
+    let spend_vk = VerifyingKey::build(11, SpendContract::default());
 
     let client = Client::new(
         rocks.clone(),
         (config.gateway_protocol_url.parse()?, config.gateway_publisher_url.parse()?),
         client_wallet.clone(),
-        mint_proof_keys,
-        spend_proof_keys,
     )
     .await?;
 
@@ -694,13 +701,13 @@ async fn start(
         tree: BridgeTree::<MerkleNode, 32>::new(100),
         merkle_roots,
         nullifiers,
-        mint_vk: mint_proof_keys.vk,
-        spend_vk: spend_proof_keys.vk,
+        mint_vk,
+        spend_vk,
         public_keys: cashier_public_keys,
     }));
 
     if get_address_flag {
-        println!("Public Key: {}", cashier_public_str);
+        info!("Public Key: {}", cashier_public_str);
         return Ok(())
     };
 
@@ -750,7 +757,7 @@ async fn main() -> Result<()> {
             config.client_wallet_password.clone(),
         )?;
 
-        client_wallet.remove_own_coins()?;
+        client_wallet.remove_own_coins().await?;
 
         let wallet = CashierDb::new(
             expand_path(&config.cashier_wallet_path)?.as_path(),
@@ -764,7 +771,7 @@ async fn main() -> Result<()> {
             std::fs::remove_dir_all(path)?;
         }
 
-        println!("Wallet got updated successfully.");
+        info!("Wallet got updated successfully.");
 
         return Ok(())
     }

+ 1 - 1
src/bin/tx2.rs

@@ -99,7 +99,7 @@ impl MemoryState {
 
 fn main() -> Result<()> {
     let cashier_signature_secret = schnorr::SecretKey::random();
-    let cashier_signature_public = cashier_secret.public_key();
+    let cashier_signature_public = cashier_signature_secret.public_key();
 
     let keypair = Keypair::random(&mut OsRng);
 

+ 3 - 0
src/circuit/mod.rs

@@ -1,2 +1,5 @@
 pub mod mint_contract;
 pub mod spend_contract;
+
+pub use mint_contract::MintContract;
+pub use spend_contract::SpendContract;

+ 80 - 368
src/client.rs

@@ -1,26 +1,24 @@
 use async_std::sync::{Arc, Mutex};
-use incrementalmerkletree::bridgetree::BridgeTree;
-use log::{debug, info};
+use incrementalmerkletree::Tree;
+use log::{debug, info, warn};
 use pasta_curves::pallas;
+use smol::Executor;
 use url::Url;
 
 use crate::{
     blockchain::{rocks::columns, Rocks, RocksColumn, Slab},
-    crypto::{
-        coin::Coin, merkle_node::MerkleNode, mint_proof::MintProofKeys, nullifier::Nullifier,
-        proof::VerifyingKey, schnorr, spend_proof::SpendProofKeys,
-    },
-    serial::{serialize, Encodable},
+    crypto::{coin::Coin, merkle_node::MerkleNode, schnorr, util::mod_r_p},
+    serial::{serialize, Decodable, Encodable},
     service::GatewayClient,
-    state::{state_transition, ProgramState},
+    state::{state_transition, State},
     tx,
-    wallet::{Keypair, WalletPtr},
+    wallet::{CashierDbPtr, Keypair, WalletPtr},
     Result,
 };
 
 #[derive(Debug, Clone, thiserror::Error)]
 pub enum ClientFailed {
-    #[error("here is no enough value {0}")]
+    #[error("Here is not enough value {0}")]
     NotEnoughValue(u64),
     #[error("Invalid Address  {0}")]
     InvalidAddress(String),
@@ -46,12 +44,24 @@ pub enum ClientFailed {
     VerifyError(String),
 }
 
+pub type ClientResult<T> = std::result::Result<T, ClientFailed>;
+
+impl From<super::error::Error> for ClientFailed {
+    fn from(err: super::error::Error) -> ClientFailed {
+        ClientFailed::ClientError(err.to_string())
+    }
+}
+
+impl From<crate::state::VerifyFailed> for ClientFailed {
+    fn from(err: crate::state::VerifyFailed) -> ClientFailed {
+        ClientFailed::VerifyError(err.to_string())
+    }
+}
+
 pub struct Client {
-    main_keypair: Keypair,
+    pub main_keypair: Keypair,
     gateway: GatewayClient,
     wallet: WalletPtr,
-    mint_proof_keys: MintProofKeys,
-    spend_proof_keys: SpendProofKeys,
 }
 
 impl Client {
@@ -59,70 +69,69 @@ impl Client {
         rocks: Arc<Rocks>,
         gateway_addrs: (Url, Url),
         wallet: WalletPtr,
-        mint_proof_keys: MintProofKeys,
-        spend_proof_keys: SpendProofKeys,
     ) -> Result<Self> {
-        wallet.init_db()?;
+        wallet.init_db().await?;
 
         // Generate a new keypair if we don't have any.
-        if wallet.get_keypairs()?.is_empty() {
-            wallet.key_gen()?;
+        if wallet.get_keypairs().await?.is_empty() {
+            wallet.key_gen().await?;
         }
 
-        // TODO: Think about multiple keypairs.
-        let main_keypair = wallet.get_keypairs()?[0].clone();
+        // TODO: Think about multiple keypairs
+        let main_keypair = wallet.get_keypairs().await?[0].clone();
         info!("Main keypair: {}", bs58::encode(&serialize(&main_keypair.public)).into_string());
 
-        let slabstore = RocksColumn::<columns::Slabs>::new(rocks);
-
         debug!("Creating GatewayClient");
+        let slabstore = RocksColumn::<columns::Slabs>::new(rocks);
         let gateway = GatewayClient::new(gateway_addrs.0, gateway_addrs.1, slabstore)?;
 
-        let client = Client { main_keypair, gateway, wallet, mint_proof_keys, spend_proof_keys };
+        let client = Client { main_keypair, gateway, wallet };
         Ok(client)
     }
 
     pub async fn start(&mut self) -> Result<()> {
-        self.gateway.start().await?;
-        Ok(())
+        self.gateway.start().await
     }
 
     async fn build_slab_from_tx(
         &mut self,
-        pub_key: pallas::Point,
+        pubkey: pallas::Point,
         value: u64,
         token_id: pallas::Base,
         clear_input: bool,
         state: Arc<Mutex<State>>,
     ) -> ClientResult<Vec<Coin>> {
-        debug!(target: "CLIENT", "Start build slab from tx");
-
+        debug!("Start build slab from tx");
         let mut clear_inputs: Vec<tx::TransactionBuilderClearInputInfo> = vec![];
         let mut inputs: Vec<tx::TransactionBuilderInputInfo> = vec![];
         let mut outputs: Vec<tx::TransactionBuilderOutputInfo> = vec![];
         let mut coins: Vec<Coin> = vec![];
 
         if clear_input {
-            let signature_secret = self.main_keypair.private;
+            // TODO: FIXME:
+            let base_secret = self.main_keypair.private;
+            let signature_secret = schnorr::SecretKey(mod_r_p(base_secret));
             let input = tx::TransactionBuilderClearInputInfo { value, token_id, signature_secret };
             clear_inputs.push(input);
         } else {
-            debug!(target: "CLIENT", "Start build inputs");
-
-            let mut inputs_value: u64 = 0;
-
-            let own_coins = self.wallet.get_own_coins()?;
+            debug!("Start build inputs");
+            let mut inputs_value = 0_u64;
+            let state_m = state.lock().await;
+            let own_coins = self.wallet.get_own_coins().await?;
 
             for own_coin in own_coins.iter() {
                 if inputs_value >= value {
                     break
                 }
 
-                let witness = &own_coin.witness;
-                let merkle_path = witness.path().unwrap();
+                let node = MerkleNode(own_coin.coin.inner());
+                let (leaf_position, merkle_path) = state_m.tree.authentication_path(&node).unwrap();
+                // TODO: What is this counting? Is it everything or does it know to separate
+                // different tokens?
                 inputs_value += own_coin.note.value;
 
                 let input = tx::TransactionBuilderInputInfo {
+                    leaf_position,
                     merkle_path,
                     secret: own_coin.secret,
                     note: own_coin.note.clone(),
@@ -146,157 +155,90 @@ impl Client {
                 });
             }
 
-            debug!(target: "CLIENT", "End build inputs");
+            debug!("End build inputs");
         }
 
-        outputs.push(tx::TransactionBuilderOutputInfo { value, token_id, public: pub_key });
+        outputs.push(tx::TransactionBuilderOutputInfo { value, token_id, public: pubkey });
 
         let builder = tx::TransactionBuilder { clear_inputs, inputs, outputs };
-
         let tx: tx::Transaction;
-
         let mut tx_data = vec![];
-        {
-            tx = builder.build()?;
-            tx.encode(&mut tx_data).expect("encode tx");
-        }
+        tx = builder.build()?;
+        tx.encode(&mut tx_data).expect("encode tx");
 
         let slab = Slab::new(tx_data);
+        debug!("End build slab from tx");
 
-        debug!(target: "CLIENT", "End build slab from tx");
-
-        // check if it's valid before send it to gateway
+        // Check if it's valid before sending to gateway
         let state = &*state.lock().await;
-
         state_transition(state, tx)?;
 
         self.gateway.put_slab(slab).await?;
-
         Ok(coins)
     }
 
     pub async fn send(
         &mut self,
-        pub_key: pallas::Point,
+        pubkey: pallas::Point,
         amount: u64,
         token_id: pallas::Base,
         clear_input: bool,
         state: Arc<Mutex<State>>,
     ) -> ClientResult<()> {
-        debug!(target: "CLIENT", "Start send {}", amount);
+        // TODO: TOKEN debug
+        debug!("Start send {}", amount);
 
         if amount == 0 {
-            return Err(ClientFailed::InvalidAmount(amount as u64))
+            return Err(ClientFailed::InvalidAmount(0))
         }
 
-        let coins = self.build_slab_from_tx(pub_key, amount, token_id, clear_input, state).await?;
-
+        let coins = self.build_slab_from_tx(pubkey, amount, token_id, clear_input, state).await?;
         for coin in coins.iter() {
-            self.wallet.confirm_spend_coin(coin)?;
+            self.wallet.confirm_spend_coin(coin).await?;
         }
 
-        debug!(target: "CLIENT", "End send {}", amount);
-
+        debug!("End send {}", amount);
         Ok(())
     }
 
-    pub async fn transfer(
-        &mut self,
-        token_id: pallas::Base,
-        pub_key: pallas::Point,
-        amount: u64,
+    async fn update_state(
+        secret_keys: Vec<pallas::Base>,
+        slab: &Slab,
         state: Arc<Mutex<State>>,
-    ) -> ClientResult<()> {
-        debug!(target: "CLIENT", "Start transfer {}", amount);
-
-        let token_id_exists = self.wallet.token_id_exists(&token_id)?;
-
-        if token_id_exists {
-            self.send(pub_key, amount, token_id, false, state).await?;
-        } else {
-            return Err(ClientFailed::NotEnoughValue(amount))
-        }
-
-        debug!(target: "CLIENT", "End transfer {}", amount);
+        wallet: WalletPtr,
+        notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
+    ) -> Result<()> {
+        debug!("Build tx from slab and update the state");
+        let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
 
+        let st = &*state.lock().await;
+        let update = state_transition(st, tx)?;
+        let mut st = state.lock().await;
+        st.apply(update, secret_keys, notify, wallet).await?;
         Ok(())
     }
-}
-
-pub struct State {
-    // The entire merkle tree state
-    pub tree: BridgeTree<MerkleNode, 32>,
-    // List of all previous and the current merkle roots
-    // This is the hashed value of all the children.
-    pub merkle_roots: RocksColumn<columns::MerkleRoots>,
-    // Nullifiers prevent double spending
-    pub nullifiers: RocksColumn<columns::Nullifiers>,
-    // Mint verifying key used by ZK
-    pub mint_vk: VerifyingKey,
-    // Spend verifying key used by ZK
-    pub spend_vk: VerifyingKey,
-    // List of cashier public keys
-    pub public_keys: Vec<pallas::Point>,
-}
-
-impl ProgramState for State {
-    fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool {
-        debug!(target: "CLIENT STATE", "Check if it is valid cashier public key");
-        self.public_keys.contains(public)
-    }
-
-    fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
-        debug!(target: "CLIENT STATE", "Check if it is valid merkle");
-
-        if let Ok(mr) = self.merkle_roots.key_exist(*merkle_root) {
-            return mr
-        }
-        false
-    }
-
-    fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
-        debug!(target: "CLIENT STATE", "Check if nullifier exists");
-        if let Ok(nl) = self.nullifiers.key_exist(nullifier.to_bytes()) {
-            return nl
-        }
-        false
-    }
-
-    fn mint_vk(&self) -> &VerifyingKey {
-        &self.mint_vk
-    }
-
-    fn spend_vk(&self) -> &VerifyingKey {
-        &self.spend_vk
-    }
-}
-
-/*
-impl Client {
 
     pub async fn connect_to_subscriber_from_cashier(
         &self,
         state: Arc<Mutex<State>>,
         cashier_wallet: CashierDbPtr,
-        notify: async_channel::Sender<(jubjub::SubgroupPoint, u64)>,
+        notify: async_channel::Sender<(pallas::Point, u64)>,
         executor: Arc<Executor<'_>>,
     ) -> Result<()> {
-        // start subscribing
-        debug!(target: "CLIENT", "Start subscriber for cashier");
-        let gateway_slabs_sub: GatewaySlabsSubscriber =
-            self.gateway.start_subscriber(executor.clone()).await?;
+        debug!("Start subscriber for cashier");
+        let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
 
         let secret_key = self.main_keypair.private;
         let wallet = self.wallet.clone();
 
+        //let task: smol::Task<Result<()>> = executor.spawn(async move {
         let task: smol::Task<Result<()>> = executor.spawn(async move {
             loop {
                 let slab = gateway_slabs_sub.recv().await?;
+                debug!("Received new slab");
 
-                debug!(target: "CLIENT", "Received new slab");
-
-                let mut secret_keys: Vec<jubjub::Fr> = vec![secret_key];
-                let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys()?;
+                let mut secret_keys: Vec<pallas::Base> = vec![secret_key];
+                let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys().await?;
                 secret_keys.append(&mut withdraw_keys);
 
                 let update_state = Self::update_state(
@@ -306,246 +248,16 @@ impl Client {
                     wallet.clone(),
                     Some(notify.clone()),
                 )
-                    .await;
+                .await;
 
                 if let Err(e) = update_state {
-                    warn!("Update state: {}", e.to_string());
-                    continue;
+                    warn!("Update state: {}", e);
+                    continue
                 }
             }
         });
 
         task.detach();
-
         Ok(())
     }
-
-    pub async fn connect_to_subscriber(
-        &self,
-        state: Arc<Mutex<State>>,
-        executor: Arc<Executor<'_>>,
-    ) -> Result<()> {
-        // start subscribing
-        debug!(target: "CLIENT", "Start subscriber");
-        let gateway_slabs_sub: GatewaySlabsSubscriber =
-            self.gateway.start_subscriber(executor.clone()).await?;
-
-        let secret_key = self.main_keypair.private;
-        let wallet = self.wallet.clone();
-
-        let task: smol::Task<Result<()>> = executor.spawn(async move {
-            loop {
-                let slab = gateway_slabs_sub.recv().await?;
-
-                debug!(target: "CLIENT", "Received new slab");
-
-                let update_state = Self::update_state(
-                    vec![secret_key],
-                    &slab,
-                    state.clone(),
-                    wallet.clone(),
-                    None,
-                )
-                    .await;
-
-                if let Err(e) = update_state {
-                    warn!("Update state: {}", e.to_string());
-                    continue;
-                }
-            }
-        });
-
-        task.detach();
-
-        Ok(())
-    }
-
-    async fn update_state(
-        secret_keys: Vec<jubjub::Fr>,
-        slab: &Slab,
-        state: Arc<Mutex<State>>,
-        wallet: WalletPtr,
-        notify: Option<async_channel::Sender<(jubjub::SubgroupPoint, u64)>>,
-    ) -> Result<()> {
-        debug!(target: "CLIENT", "Build tx from slab and update the state");
-
-        let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
-
-
-        let update: StateUpdate;
-
-        {
-            let state = &*state.lock().await;
-            update = state_transition(state, tx)?;
-        }
-
-        let mut state = state.lock().await;
-
-        state
-            .apply(update, secret_keys.clone(), notify, wallet)
-            .await?;
-
-        Ok(())
-    }
-
-    pub fn init_db(&self) -> Result<()> {
-        self.wallet.init_db()
-    }
-
-    pub fn get_own_coins(&self) -> Result<Vec<OwnCoin>> {
-        self.wallet.get_own_coins()
-    }
-
-    pub fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
-        self.wallet.confirm_spend_coin(coin)
-    }
-
-    pub fn key_gen(&self) -> Result<()> {
-        self.wallet.key_gen()
-    }
-
-    pub fn get_balances(&self) -> Result<Balances> {
-        self.wallet.get_balances()
-    }
-
-    pub fn token_id_exists(&self, token_id: &jubjub::Fr) -> Result<bool> {
-        self.wallet.token_id_exists(token_id)
-    }
-
-    pub fn get_token_id(&self) -> Result<Vec<jubjub::Fr>> {
-        self.wallet.get_token_id()
-    }
-}
-
-pub struct State {
-    // The entire merkle tree state
-    pub tree: CommitmentTree<MerkleNode>,
-    // List of all previous and the current merkle roots
-    // This is the hashed value of all the children.
-    pub merkle_roots: RocksColumn<columns::MerkleRoots>,
-    // Nullifiers prevent double spending
-    pub nullifiers: RocksColumn<columns::Nullifiers>,
-    // Mint verifying key used by ZK
-    pub mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
-    // Spend verifying key used by ZK
-    pub spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
-    // List of cashier public keys
-    pub public_keys: Vec<jubjub::SubgroupPoint>,
-}
-
-impl State {
-    pub async fn apply(
-        &mut self,
-        update: StateUpdate,
-        secret_keys: Vec<jubjub::Fr>,
-        notify: Option<async_channel::Sender<(jubjub::SubgroupPoint, u64)>>,
-        wallet: WalletPtr,
-    ) -> Result<()> {
-        // Extend our list of nullifiers with the ones from the update
-
-        debug!(target: "CLIENT STATE", "Extend nullifiers");
-        for nullifier in update.nullifiers {
-            self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
-        }
-
-        debug!(target: "CLIENT STATE", "Update merkle tree and witness ");
-        // Update merkle tree and witnesses
-        for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.iter()) {
-            // Add the new coins to the merkle tree
-            let node = MerkleNode::from_coin(&coin);
-            self.tree.append(node).expect("Append to merkle tree");
-
-            debug!(target: "CLIENT STATE", "Keep track of all merkle roots");
-
-            // Keep track of all merkle roots that have existed
-            self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
-
-            debug!(target: "CLIENT STATE", "Update witness");
-
-            // Also update all the coin witnesses
-            let mut updated_witnesses = wallet.get_witnesses()?;
-
-            updated_witnesses.iter_mut().for_each(|(_, witness)| {
-                witness.append(node).expect("Append to witness");
-            });
-
-            wallet.update_witnesses(updated_witnesses)?;
-
-            debug!(target: "CLIENT STATE", "iterate over secret_keys to decrypt note");
-
-            for secret in secret_keys.iter() {
-                if let Some(note) = Self::try_decrypt_note(enc_note, *secret) {
-                    // We need to keep track of the witness for this coin.
-                    // This allows us to prove inclusion of the coin in the merkle tree with ZK.
-                    // Just as we update the merkle tree with every new coin, so we do the same with
-                    // the witness.
-
-                    // Derive the current witness from the current tree.
-                    // This is done right after we add our coin to the tree (but before any other
-                    // coins are added)
-
-                    // Make a new witness for this coin
-                    let witness = IncrementalWitness::from_tree(&self.tree);
-
-                    let mut nullifier = [0; 32];
-                    nullifier.copy_from_slice(
-                        Blake2sParams::new()
-                        .hash_length(32)
-                        .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
-                        .to_state()
-                        .update(&secret.to_bytes())
-                        .update(&note.serial.to_bytes())
-                        .finalize()
-                        .as_bytes(),
-                    );
-
-                    let nullifier = Nullifier::new(nullifier);
-
-                    let own_coin = OwnCoin {
-                        coin: coin.clone(),
-                        note: note.clone(),
-                        secret: *secret,
-                        witness: witness.clone(),
-                        nullifier,
-                    };
-
-                    wallet.put_own_coins(own_coin)?;
-                    let pub_key = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
-
-                    debug!(target: "CLIENT STATE", "Received a coin: amount {} ", note.value);
-
-                    debug!(target: "CLIENT STATE", "Send a notification");
-
-                    if let Some(ch) = notify.clone() {
-                        ch.send((pub_key, note.value)).await?
-                    }
-                }
-            }
-        }
-        Ok(())
-    }
-
-    fn try_decrypt_note(ciphertext: &EncryptedNote, secret: jubjub::Fr) -> Option<Note> {
-        match ciphertext.decrypt(&secret) {
-            // ... and return the decrypted note for this coin.
-            Ok(note) => Some(note),
-            // We weren't able to decrypt the note with our key.
-            Err(_) => None,
-        }
-    }
 }
-*/
-
-impl From<super::error::Error> for ClientFailed {
-    fn from(err: super::error::Error) -> ClientFailed {
-        ClientFailed::ClientError(err.to_string())
-    }
-}
-
-impl From<crate::state::VerifyFailed> for ClientFailed {
-    fn from(err: crate::state::VerifyFailed) -> ClientFailed {
-        ClientFailed::VerifyError(err.to_string())
-    }
-}
-
-pub type ClientResult<T> = std::result::Result<T, ClientFailed>;

+ 0 - 2
src/crypto/coin.rs

@@ -19,11 +19,9 @@ impl Coin {
         self.0.to_bytes()
     }
 
-    /*
     pub(crate) fn inner(&self) -> pallas::Base {
         self.0
     }
-    */
 }
 
 impl Encodable for Coin {

+ 10 - 0
src/crypto/nullifier.rs

@@ -1,5 +1,9 @@
 use std::io;
 
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
+};
 use pasta_curves::{arithmetic::FieldExt, pallas};
 
 use crate::{
@@ -11,6 +15,12 @@ use crate::{
 pub struct Nullifier(pub(crate) pallas::Base);
 
 impl Nullifier {
+    pub fn new(secret: pallas::Base, serial: pallas::Base) -> Self {
+        let nullifier = [secret, serial];
+        let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+        Nullifier(nullifier)
+    }
+
     pub fn from_bytes(bytes: &[u8; 32]) -> Self {
         pallas::Base::from_bytes(bytes).map(Nullifier).unwrap()
     }

+ 8 - 0
src/crypto/schnorr.rs

@@ -36,6 +36,10 @@ impl SecretKey {
         let public_key = OrchardFixedBases::SpendAuthG.generator() * self.0;
         PublicKey(public_key)
     }
+
+    pub fn inner(&self) -> pallas::Scalar {
+        self.0
+    }
 }
 
 #[derive(PartialEq)]
@@ -67,6 +71,10 @@ impl PublicKey {
         OrchardFixedBases::SpendAuthG.generator() * signature.response - self.0 * challenge ==
             signature.commit
     }
+
+    pub fn inner(&self) -> pallas::Point {
+        self.0
+    }
 }
 
 impl Encodable for PublicKey {

+ 126 - 3
src/state.rs

@@ -1,18 +1,30 @@
+use halo2_gadgets::ecc::FixedPoints;
+use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
 use log::debug;
+use pasta_curves::pallas;
 
 use crate::{
+    blockchain::{rocks::columns, RocksColumn},
     crypto::{
-        coin::Coin, merkle_node::MerkleNode, note::EncryptedNote, nullifier::Nullifier,
-        proof::VerifyingKey, schnorr,
+        coin::Coin,
+        constants::OrchardFixedBases,
+        merkle_node::MerkleNode,
+        note::{EncryptedNote, Note},
+        nullifier::Nullifier,
+        proof::VerifyingKey,
+        schnorr,
+        util::mod_r_p,
+        OwnCoin,
     },
     tx::Transaction,
+    wallet::WalletPtr,
+    Result,
 };
 
 pub trait ProgramState {
     fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool;
     fn is_valid_merkle(&self, merkle: &MerkleNode) -> bool;
     fn nullifier_exists(&self, nullifier: &Nullifier) -> bool;
-
     fn mint_vk(&self) -> &VerifyingKey;
     fn spend_vk(&self) -> &VerifyingKey;
 }
@@ -102,3 +114,114 @@ pub fn state_transition<S: ProgramState>(state: &S, tx: Transaction) -> VerifyRe
 
     Ok(StateUpdate { nullifiers, coins, enc_notes })
 }
+
+pub struct State {
+    /// The entire Merkle tree state
+    pub tree: BridgeTree<MerkleNode, 32>,
+    /// List of all previous and the current merkle roots.
+    /// This is the hashed value of all the children.
+    pub merkle_roots: RocksColumn<columns::MerkleRoots>,
+    /// Nullifiers prevent double-spending
+    pub nullifiers: RocksColumn<columns::Nullifiers>,
+    /// List of Cashier public keys
+    pub public_keys: Vec<pallas::Point>,
+    /// Verifying key for the Mint contract
+    pub mint_vk: VerifyingKey,
+    /// Verifying key for the Spend contract
+    pub spend_vk: VerifyingKey,
+}
+
+impl State {
+    pub async fn apply(
+        &mut self,
+        update: StateUpdate,
+        secret_keys: Vec<pallas::Base>,
+        notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
+        wallet: WalletPtr,
+    ) -> Result<()> {
+        // Extend our list of nullifiers with the ones from the update.
+        debug!("Extend nullifiers");
+        for nullifier in update.nullifiers {
+            self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
+        }
+
+        debug!("Update Merkle tree and witness");
+        for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.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.put(self.tree.root(), vec![] as Vec<u8>)?;
+
+            for secret in secret_keys.iter() {
+                if let Some(note) = State::try_decrypt_note(enc_note, *secret) {
+                    // TODO: What to do with witnesses?
+                    self.tree.witness();
+                    let nullifier = Nullifier::new(*secret, note.serial);
+
+                    let own_coin = OwnCoin {
+                        coin: coin.clone(),
+                        note: note.clone(),
+                        secret: *secret,
+                        // witness: witness.clone(),
+                        nullifier,
+                    };
+
+                    wallet.put_own_coins(own_coin).await?;
+
+                    // TODO: Place somewhere proper
+                    let pubkey = OrchardFixedBases::NullifierK.generator() * mod_r_p(*secret);
+
+                    debug!("Received a coin: amount {}", note.value);
+                    debug!("Send a notification");
+                    if let Some(ch) = notify.clone() {
+                        ch.send((pubkey, note.value)).await?;
+                    }
+                }
+            }
+        }
+
+        debug!("apply() exiting successfully");
+        Ok(())
+    }
+
+    fn try_decrypt_note(ciphertext: &EncryptedNote, secret: pallas::Base) -> Option<Note> {
+        match ciphertext.decrypt(&secret) {
+            Ok(note) => Some(note),
+            Err(_) => None,
+        }
+    }
+}
+
+impl ProgramState for State {
+    // TODO: Proper keypair type
+    fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool {
+        debug!("Check if it is a valid cashier public key");
+        self.public_keys.contains(&public.inner())
+    }
+
+    fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
+        debug!("Check if it is valid merkle");
+        if let Ok(mr) = self.merkle_roots.key_exist(merkle_root.clone()) {
+            return mr
+        }
+        false
+    }
+
+    fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
+        debug!("Check if nullifier exists");
+        if let Ok(nl) = self.nullifiers.key_exist(nullifier.to_bytes()) {
+            return nl
+        }
+        false
+    }
+
+    fn mint_vk(&self) -> &VerifyingKey {
+        &self.mint_vk
+    }
+
+    fn spend_vk(&self) -> &VerifyingKey {
+        &self.spend_vk
+    }
+}

+ 45 - 30
src/wallet/walletdb.rs

@@ -1,5 +1,6 @@
-use std::{path::Path, sync::Arc};
+use std::path::Path;
 
+use async_std::sync::{Arc, Mutex};
 use log::{debug, error, info};
 use pasta_curves::arithmetic::Field;
 use rand::rngs::OsRng;
@@ -46,7 +47,7 @@ impl Balances {
 }
 
 pub struct WalletDb {
-    pub conn: Connection,
+    pub conn: Mutex<Connection>,
 }
 
 impl WalletApi for WalletDb {}
@@ -63,25 +64,27 @@ impl WalletDb {
         conn.pragma_update(None, "key", &password)?;
         info!(target: "WALLETDB", "Opened connection at path: {:?}", path);
 
-        Ok(Arc::new(Self { conn }))
+        Ok(Arc::new(Self { conn: Mutex::new(conn) }))
     }
 
-    pub fn init_db(&self) -> Result<()> {
+    pub async fn init_db(&self) -> Result<()> {
         debug!(target: "WALLETDB", "Initialize...");
         let contents = include_str!("../../sql/schema.sql");
-        Ok(self.conn.execute_batch(contents)?)
+        let conn = self.conn.lock().await;
+        Ok(conn.execute_batch(contents)?)
     }
 
-    pub fn key_gen(&self) -> Result<()> {
+    pub async fn key_gen(&self) -> Result<()> {
         debug!(target: "WALLETDB", "Attempting to generate keys...");
-        let mut stmt = self.conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
 
         let key_check = stmt.exists(params!["0"])?;
 
         if !key_check {
             let secret = DrkSecretKey::random(&mut OsRng);
             let public = derive_public_key(secret);
-            self.put_keypair(&public, &secret)?;
+            self.put_keypair(&public, &secret).await?;
             return Ok(())
         }
 
@@ -89,12 +92,17 @@ impl WalletDb {
         Err(Error::from(ClientFailed::KeyExists))
     }
 
-    pub fn put_keypair(&self, key_public: &DrkPublicKey, key_private: &DrkSecretKey) -> Result<()> {
+    pub async fn put_keypair(
+        &self,
+        key_public: &DrkPublicKey,
+        key_private: &DrkSecretKey,
+    ) -> Result<()> {
         debug!(target: "WALLETDB", "put_keypair()");
         let key_public = serial::serialize(key_public);
         let key_private = serial::serialize(key_private);
 
-        self.conn.execute(
+        let conn = self.conn.lock().await;
+        conn.execute(
             "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
             params![key_public, key_private],
         )?;
@@ -102,9 +110,10 @@ impl WalletDb {
         Ok(())
     }
 
-    pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
+    pub async fn get_keypairs(&self) -> Result<Vec<Keypair>> {
         debug!(target: "WALLETDB", "Returning keypairs...");
-        let mut stmt = self.conn.prepare("SELECT * FROM keys")?;
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare("SELECT * FROM keys")?;
 
         // this just gets the first key. maybe we should randomize this
         let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
@@ -122,11 +131,12 @@ impl WalletDb {
         Ok(keypairs)
     }
 
-    pub fn get_own_coins(&self) -> Result<OwnCoins> {
+    pub async fn get_own_coins(&self) -> Result<OwnCoins> {
         debug!(target: "WALLETDB", "Get own coins");
         let is_spent = 0;
 
-        let mut coins = self.conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
+        let conn = self.conn.lock().await;
+        let mut coins = conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
 
         let rows = coins.query_map(&[(":is_spent", &is_spent)], |row| {
             Ok((
@@ -178,7 +188,7 @@ impl WalletDb {
         Ok(own_coins)
     }
 
-    pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
+    pub async fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
         debug!(target: "WALLETDB", "Put own coins");
         let coin = self.get_value_serialized(&own_coin.coin.to_bytes())?;
         let serial = self.get_value_serialized(&own_coin.note.serial)?;
@@ -191,7 +201,8 @@ impl WalletDb {
         let is_spent = 0;
         let nullifier = self.get_value_serialized(&own_coin.nullifier)?;
 
-        self.conn.execute(
+        let conn = self.conn.lock().await;
+        conn.execute(
             "INSERT OR REPLACE INTO coins
             (coin, serial, value, token_id, coin_blind,
             valcom_blind, witness, secret, is_spent, nullifier)
@@ -215,18 +226,20 @@ impl WalletDb {
         Ok(())
     }
 
-    pub fn remove_own_coins(&self) -> Result<()> {
+    pub async fn remove_own_coins(&self) -> Result<()> {
         debug!(target: "WALLETDB", "Remove own coins");
-        let _rows = self.conn.execute("DROP TABLE coins;", [])?;
+        let conn = self.conn.lock().await;
+        let _rows = conn.execute("DROP TABLE coins;", [])?;
         Ok(())
     }
 
-    pub fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
+    pub async fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
         debug!(target: "WALLETDB", "Confirm spend coin");
         let is_spent = 1;
         let coin = self.get_value_serialized(coin)?;
 
-        self.conn.execute(
+        let conn = self.conn.lock().await;
+        conn.execute(
             "UPDATE coins
             SET is_spent = ?1
             WHERE coin = ?2 ;",
@@ -284,11 +297,12 @@ impl WalletDb {
     }
     */
 
-    pub fn get_balances(&self) -> Result<Balances> {
+    pub async fn get_balances(&self) -> Result<Balances> {
         debug!(target: "WALLETDB", "Get token and balances...");
         let is_spent = 0;
 
-        let mut stmt = self.conn.prepare(
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare(
             "SELECT value, token_id, nullifier FROM coins  WHERE is_spent = :is_spent ;",
         )?;
 
@@ -309,12 +323,12 @@ impl WalletDb {
         Ok(balances)
     }
 
-    pub fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
+    pub async fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
         debug!(target: "WALLETDB", "Get token ID...");
         let is_spent = 0;
 
-        let mut stmt =
-            self.conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
 
         let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| row.get(0))?;
 
@@ -329,21 +343,22 @@ impl WalletDb {
         Ok(token_ids)
     }
 
-    pub fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
+    pub async fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
         debug!(target: "WALLETDB", "Check tokenID exists");
         let is_spent = 0;
         let id = self.get_value_serialized(token_id)?;
 
-        let mut stmt =
-            self.conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
 
         let id_check = stmt.exists(params![id, is_spent])?;
 
         Ok(id_check)
     }
 
-    pub fn test_wallet(&self) -> Result<()> {
-        let mut stmt = self.conn.prepare("SELECT * FROM keys")?;
+    pub async fn test_wallet(&self) -> Result<()> {
+        let conn = self.conn.lock().await;
+        let mut stmt = conn.prepare("SELECT * FROM keys")?;
         let _rows = stmt.query([])?;
         Ok(())
     }