Procházet zdrojové kódy

Merge branch 'master' of github.com:darkrenaissance/darkfi

lunar-mining před 4 roky
rodič
revize
743366b673

+ 1 - 1
Cargo.lock

@@ -1345,12 +1345,12 @@ dependencies = [
  "bls12_381",
  "bs58 0.4.0",
  "bytes 1.1.0",
+ "cfg-if 1.0.0",
  "clap",
  "crypto_api_chachapoly",
  "ctrlc",
  "dirs 3.0.2",
  "easy-parallel",
- "ed25519-dalek",
  "electrum-client",
  "failure",
  "failure_derive",

+ 2 - 2
Cargo.toml

@@ -50,6 +50,7 @@ ctrlc = "3.1.7"
 serde_json = "1.0.61"
 owning_ref = "0.4.1"
 signal-hook = "0.3.8"
+cfg-if = "1.0.0"
 
 smol = "1.2.4"
 futures = "0.3.5"
@@ -86,7 +87,6 @@ solana-sdk = {version = "1.7.11", optional = true}
 solana-client = {version = "1.7.11", optional = true}
 tokio-tungstenite = {version = "0.15.0", optional = true} 
 tokio = {version = "1.11.0", features = ["full"], optional = true}
-ed25519-dalek = {version = "1.0.1", optional = true}
 
 ## Cashier Bitcoin Dependencies
 bitcoin = {version = "0.27.0", optional = true }
@@ -99,7 +99,7 @@ features = ["bundled", "sqlcipher"]
 
 [features]
 default = ["bitcoin", "secp256k1", "electrum-client"]
-sol = ["solana-sdk", "solana-client", "tokio-tungstenite", "tokio", "ed25519-dalek" ]
+sol = ["solana-sdk", "solana-client", "tokio-tungstenite", "tokio" ]
 
 [[bin]]
 name = "gatewayd"

+ 5 - 8
README.md

@@ -9,8 +9,8 @@
 ```
 connect_url = "127.0.0.1:3333"
 publisher_url = "127.0.0.1:4444"
-database_path = "gatewayd.db"
-log_path = "/tmp/gatewayd.log"
+log_path = "/tmp/gatewayd.log"	
+
 ```
 
 **cashierd.toml**
@@ -18,14 +18,11 @@ log_path = "/tmp/gatewayd.log"
 ```
 accept_url = "127.0.0.1:7777"
 rpc_url = "http://127.0.0.1:8000"
-client_database_path = "cashier_client_database.db"
-btc_endpoint = "tcp://electrum.blockstream.info:50001"
 gateway_url = "127.0.0.1:3333"
 log_path = "/tmp/cashierd.log"
-cashierdb_path = "~/.config/darkfi/cashier.db"
-client_walletdb_path = "~/.config/darkfi/cashier_client_walletdb.db"
 password = "TEST_PASSWORD"
 client_password = "TEST_PASSWORD"
+
 ```
 
 **darkfid.toml**
@@ -35,10 +32,9 @@ connect_url = "127.0.0.1:3333"
 subscriber_url = "127.0.0.1:4444"
 cashier_url = "127.0.0.1:7777"
 rpc_url = "127.0.0.1:8000"
-database_path = "~/.config/darkfi/database_client.db"
-walletdb_path = "~/.config/darkfi/walletdb.db"
 log_path = "/tmp/darkfid_service_daemon.log"
 password = "TEST_PASSWORD"
+
 ```
 
 **drk.toml**
@@ -46,6 +42,7 @@ password = "TEST_PASSWORD"
 ```
 rpc_url = "http://127.0.0.1:8000"
 log_path = "/tmp/drk_cli.log"
+
 ```
 
 3. Configure the password field on all TOML files.

+ 0 - 8
example/config/cashierd.toml

@@ -1,14 +1,6 @@
 accept_url = "127.0.0.1:7777"
 rpc_url = "http://127.0.0.1:8000"
-client_database_path = "cashier_client_database.db"
-
 gateway_url = "127.0.0.1:3333"
 log_path = "/tmp/cashierd.log"
-cashierdb_path = "~/.config/darkfi/cashier.db"
-client_walletdb_path = "~/.config/darkfi/cashier_client_walletdb.db"
 password = "TEST_PASSWORD"
 client_password = "TEST_PASSWORD"
-
-btc_testnet = true
-btc_mainnet_endpoint = "tcp://electrum.blockstream.info:50001"
-btc_testnet_endpoint = "tcp://electrum.blockstream.info:60002"

+ 0 - 2
example/config/darkfid.toml

@@ -2,7 +2,5 @@ connect_url = "127.0.0.1:3333"
 subscriber_url = "127.0.0.1:4444"
 cashier_url = "127.0.0.1:7777"
 rpc_url = "127.0.0.1:8000"
-database_path = "~/.config/darkfi/database_client.db"
-walletdb_path = "~/.config/darkfi/walletdb.db"
 log_path = "/tmp/darkfid_service_daemon.log"
 password = "TEST_PASSWORD"

+ 1 - 2
example/config/gatewayd.toml

@@ -1,4 +1,3 @@
 connect_url = "127.0.0.1:3333"
 publisher_url = "127.0.0.1:4444"
-database_path = "gatewayd.db"
-log_path = "/tmp/gatewayd.log"
+log_path = "/tmp/gatewayd.log"	

+ 2 - 1
sql/cashier.sql

@@ -17,5 +17,6 @@ CREATE TABLE IF NOT EXISTS withdraw_keypairs(
     coin_key_id BLOB PRIMARY KEY NOT NULL,
 	d_key_private BLOB NOT NULL,
     d_key_public BLOB NOT NULL,
-	asset_id BLOB NOT NULL
+	asset_id BLOB NOT NULL,
+	confirm BLOB NOT NULL
 );

+ 6 - 11
src/bin/cashierd.rs

@@ -43,23 +43,18 @@ async fn start(executor: Arc<Executor<'_>>, config: Arc<CashierdConfig>) -> Resu
 
     let gateway_addr: SocketAddr = config.gateway_url.parse()?;
 
-    let btc_endpoint: (bool, String) = if config.btc_testnet {
-        ( true, config.btc_testnet_endpoint.clone() )
-    }
-    else {
-        ( false, config.btc_mainnet_endpoint.clone() )
-    };
+    let database_path = join_config_path(&PathBuf::from("cashier_client_database.db"))?;
 
-    let database_path = config.client_database_path.clone();
-    let database_path = join_config_path(&PathBuf::from(database_path))?;
+    let cashierdb = join_config_path(&PathBuf::from("cashier.db"))?;
+    let client_wallet = join_config_path(&PathBuf::from("cashier_client_walletdb.db"))?;
 
     let wallet = CashierDb::new(
-        &PathBuf::from(&config.cashierdb_path),
+        &cashierdb.clone(),
         config.password.clone(),
     )?;
 
     let client_wallet = WalletDb::new(
-        &PathBuf::from(&config.client_walletdb_path),
+        &client_wallet.clone(),
         config.client_password.clone(),
     )?;
 
@@ -82,7 +77,7 @@ async fn start(executor: Arc<Executor<'_>>, config: Arc<CashierdConfig>) -> Resu
     let asset_id = deserialize(&asset.id)?;
 
     // TODO: pass vector of assets into cashier.start()
-    cashier.start(ex.clone(), btc_endpoint, asset_id).await?;
+    cashier.start(ex.clone(), asset_id).await?;
 
     Ok(())
 }

+ 3 - 5
src/bin/darkfid.rs

@@ -17,12 +17,10 @@ async fn start(executor: Arc<Executor<'_>>, config: Arc<DarkfidConfig>) -> Resul
     let connect_addr: SocketAddr = config.connect_url.parse()?;
     let sub_addr: SocketAddr = config.subscriber_url.parse()?;
     let cashier_addr: SocketAddr = config.cashier_url.parse()?;
-    let database_path = config.database_path.clone();
-    let walletdb_path = config.walletdb_path.clone();
     let rpc_url: std::net::SocketAddr = config.rpc_url.parse()?;
 
-    let database_path = join_config_path(&PathBuf::from(database_path))?;
-    let walletdb_path = join_config_path(&PathBuf::from(walletdb_path))?;
+    let database_path = join_config_path(&PathBuf::from("database_client.db"))?;
+    let walletdb_path = join_config_path(&PathBuf::from("walletdb.db"))?;
 
     let rocks = Rocks::new(&database_path)?;
 
@@ -31,7 +29,7 @@ async fn start(executor: Arc<Executor<'_>>, config: Arc<DarkfidConfig>) -> Resul
     let mint_params_path = join_config_path(&PathBuf::from("mint.params"))?;
     let spend_params_path = join_config_path(&PathBuf::from("spend.params"))?;
 
-    if let Err(_) = wallet.get_private_keys() {
+    if let Err(_) = wallet.get_keypairs() {
         wallet.init_db()?;
         wallet.key_gen()?;
     }

+ 2 - 3
src/bin/gatewayd.rs

@@ -15,8 +15,7 @@ use easy_parallel::Parallel;
 async fn start(executor: Arc<Executor<'_>>, config: Arc<&GatewaydConfig>) -> Result<()> {
     let accept_addr: SocketAddr = config.accept_url.parse()?;
     let pub_addr: SocketAddr = config.publisher_url.parse()?;
-    let database_path = config.database_path.clone();
-    let database_path = join_config_path(&PathBuf::from(database_path))?;
+    let database_path = join_config_path(&PathBuf::from("gatewayd.db"))?;
 
     let rocks = Rocks::new(&database_path)?;
     let rocks_slabstore_column = RocksColumn::<columns::Slabs>::new(rocks);
@@ -31,7 +30,7 @@ fn main() -> Result<()> {
     let ex = Arc::new(Executor::new());
     let (signal, shutdown) = async_channel::unbounded::<()>();
 
-    let path = join_config_path(&PathBuf::from("gatewayd.toml")).unwrap();
+    let path = join_config_path(&PathBuf::from("gatewayd.toml"))?;
 
     let config: GatewaydConfig = Config::<GatewaydConfig>::load(path)?;
 

+ 0 - 28
src/cli/cli_config.rs

@@ -31,7 +31,6 @@ impl<T: Serialize + DeserializeOwned> Config<T> {
 #[derive(Serialize, Deserialize, Debug)]
 pub struct DrkConfig {
     pub rpc_url: String,
-
     pub log_path: String,
 }
 
@@ -49,12 +48,6 @@ pub struct DarkfidConfig {
     #[serde(rename = "rpc_url")]
     pub rpc_url: String,
 
-    #[serde(rename = "database_path")]
-    pub database_path: String,
-
-    #[serde(rename = "walletdb_path")]
-    pub walletdb_path: String,
-
     #[serde(rename = "log_path")]
     pub log_path: String,
 
@@ -70,9 +63,6 @@ pub struct GatewaydConfig {
     #[serde(rename = "publisher_url")]
     pub publisher_url: String,
 
-    #[serde(rename = "database_path")]
-    pub database_path: String,
-
     #[serde(rename = "log_path")]
     pub log_path: String,
 }
@@ -85,33 +75,15 @@ pub struct CashierdConfig {
     #[serde(rename = "rpc_url")]
     pub rpc_url: String,
 
-    #[serde(rename = "client_database_path")]
-    pub client_database_path: String,
-
     #[serde(rename = "gateway_url")]
     pub gateway_url: String,
 
     #[serde(rename = "log_path")]
     pub log_path: String,
 
-    #[serde(rename = "cashierdb_path")]
-    pub cashierdb_path: String,
-
-    #[serde(rename = "client_walletdb_path")]
-    pub client_walletdb_path: String,
-
     #[serde(rename = "password")]
     pub password: String,
 
     #[serde(rename = "client_password")]
     pub client_password: String,
-
-    #[serde(rename = "btc_testnet")]
-    pub btc_testnet: bool,
-
-    #[serde(rename = "btc_mainnet_endpoint")]
-    pub btc_mainnet_endpoint: String,
-
-    #[serde(rename = "btc_testnet_endpoint")]
-    pub btc_testnet_endpoint: String,
 }

+ 17 - 3
src/client/client.rs

@@ -171,7 +171,7 @@ impl Client {
         let mut outputs: Vec<tx::TransactionBuilderOutputInfo> = vec![];
 
         if clear_input {
-            let cashier_secret = self.state.wallet.get_private_keys()?[0];
+            let cashier_secret = self.state.wallet.get_keypairs()?[0].private;
             let input = tx::TransactionBuilderClearInputInfo {
                 value: amount,
                 asset_id,
@@ -272,7 +272,13 @@ impl Client {
             let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
             let mut client = client.lock().await;
             let update = state_transition(&client.state, tx)?;
-            let mut secret_keys = client.state.wallet.get_private_keys()?;
+            let mut secret_keys: Vec<jubjub::Fr> = client
+                .state
+                .wallet
+                .get_keypairs()?
+                .iter()
+                .map(|k| k.private)
+                .collect();
             let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys()?;
             secret_keys.append(&mut withdraw_keys);
             client
@@ -309,7 +315,15 @@ impl Client {
             let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
             let mut client = client.lock().await;
             let update = state_transition(&client.state, tx)?;
-            let secret_keys = client.state.wallet.get_private_keys()?;
+
+            let secret_keys: Vec<jubjub::Fr> = client
+                .state
+                .wallet
+                .get_keypairs()?
+                .iter()
+                .map(|k| k.private)
+                .collect();
+
             client
                 .state
                 .apply(update, secret_keys.clone(), notify.clone())

+ 2 - 4
src/client/mod.rs

@@ -12,8 +12,7 @@ pub enum ClientFailed {
     UnableToGetDepositAddress,
     UnableToGetWithdrawAddress,
     DoNotHaveCashierPublicKey,
-    DoNotHavePublicKey,
-    DoNotHavePrivateKey,
+    DoNotHaveKeypair,
     EmptyPassword,
     ClientError(String),
 }
@@ -37,8 +36,7 @@ impl fmt::Display for ClientFailed {
                 f.write_str("Unable to get withdraw address")
             }
             ClientFailed::DoNotHaveCashierPublicKey => f.write_str("Don't have cashier public key"),
-            ClientFailed::DoNotHavePublicKey => f.write_str("Don't have public key"),
-            ClientFailed::DoNotHavePrivateKey => f.write_str("Don't have private key"),
+            ClientFailed::DoNotHaveKeypair => f.write_str("Don't have keypair"),
             ClientFailed::EmptyPassword => f.write_str("Password is empty. Cannot create database"),
             ClientFailed::ClientError(i) => {
                 write!(f, "ClientError: {}", i)

+ 2 - 2
src/rpc/adapter/client_adapter.rs

@@ -67,7 +67,7 @@ impl RpcClientAdapter {
     }
 
     async fn get_key_process(client: Arc<Mutex<Client>>) -> Result<String> {
-        let key_public = client.lock().await.state.wallet.get_public_keys()?[0];
+        let key_public = client.lock().await.state.wallet.get_keypairs()?[0].public;
         let bs58_address = bs58::encode(serialize(&key_public)).into_string();
         Ok(bs58_address)
     }
@@ -150,7 +150,7 @@ impl RpcClientAdapter {
         T: Decodable + ToString,
     {
         let asset_id: jubjub::Fr = deserialize(&asset_id)?;
-        let deposit_addr = client.lock().await.state.wallet.get_public_keys()?[0];
+        let deposit_addr = client.lock().await.state.wallet.get_keypairs()?[0].public;
         let coin_public = cashier_client
             .lock()
             .await

+ 13 - 19
src/service/cashier.rs

@@ -42,8 +42,6 @@ impl CashierService {
         gateway_addrs: (SocketAddr, SocketAddr),
         params_paths: (PathBuf, PathBuf),
     ) -> Result<CashierService> {
-        // Pull address from config later
-
         let rocks = Rocks::new(&cashier_database_path)?;
 
         let client = Client::new(rocks, gateway_addrs, params_paths, client_wallet.clone())?;
@@ -59,7 +57,6 @@ impl CashierService {
     pub async fn start(
         &mut self,
         executor: Arc<Executor<'_>>,
-        btc_endpoint: (bool, String),
         // TODO: make this a vector of assets
         asset_id: jubjub::Fr,
     ) -> Result<()> {
@@ -76,13 +73,16 @@ impl CashierService {
 
         let bridge = bridge::Bridge::new();
 
-        #[cfg(feature = "default")]
-        let btc_client = super::btc::BtcClient::new(btc_endpoint)?;
-        #[cfg(feature = "default")]
-        bridge
-            .clone()
-            .add_clients(asset_id, Arc::new(btc_client))
-            .await;
+        cfg_if::cfg_if! {
+            if #[cfg(feature = "default")]{
+                // TODO: the endpoint should be generic according to asset_id
+                let btc_endpoint: (bool, String) = 
+                    (true, String::from("ssl://blockstream.info:993"));
+
+                let btc_client = super::btc::BtcClient::new(btc_endpoint)?;
+                bridge.clone().add_clients(asset_id, Arc::new(btc_client)).await;
+            }
+        }
 
         let handle_request_task = executor.spawn(Self::handle_request_loop(
             send.clone(),
@@ -129,10 +129,9 @@ impl CashierService {
                     if res.error == 0 {
                         match res.payload {
                             bridge::BridgeResponsePayload::SendResponse => {
-                                // then delete this coin addr from withdraw_keys records
                                 // TODO Send the received coins to the main address
-                                wallet.delete_withdraw_key_record(&addr, &serialize(&1) )
-                                    .expect("Delete withdraw key record");
+                                wallet.confirm_withdraw_key_record(&addr, &serialize(&1) )
+                                    .expect("Confirm withdraw key record");
                             }
                             _ => {}
                         }
@@ -212,7 +211,6 @@ impl CashierService {
                 let (asset_id, dpub): (jubjub::Fr, jubjub::SubgroupPoint) =
                     deserialize(&request.get_payload())?;
 
-                //TODO: check if key has already been issued
                 let _check =
                     cashier_wallet.get_deposit_coin_keys_by_dkey_public(&dpub, &serialize(&1));
 
@@ -252,10 +250,6 @@ impl CashierService {
                 debug!(target: "CASHIER DAEMON", "Received withdraw request");
                 let (asset_id, coin_address): (jubjub::Fr, Vec<u8>) =
                     deserialize(&request.get_payload())?;
-                //let btc_address: String = deserialize(&btc_address)?;
-                //let btc_address = bitcoin::util::address::Address::from_str(&btc_address)
-                //   .map_err(|err| crate::Error::from(super::BtcFailed::from(err)))?;
-                //
 
                 let asset_id = serialize(&asset_id);
 
@@ -264,7 +258,7 @@ impl CashierService {
                 if let Some(addr) =
                     cashier_wallet.get_withdraw_keys_by_coin_public_key(&coin_address, &asset_id)?
                 {
-                    cashier_public = addr.0;
+                    cashier_public = addr.public;
                 } else {
                     let cashier_secret = jubjub::Fr::random(&mut OsRng);
                     cashier_public =

+ 35 - 32
src/service/sol.rs

@@ -7,7 +7,6 @@ use super::bridge::CoinClient;
 use async_trait::async_trait;
 
 use async_executor::Executor;
-use ed25519_dalek::SecretKey;
 use futures::{SinkExt, StreamExt};
 use log::*;
 use rand::rngs::OsRng;
@@ -41,8 +40,8 @@ struct SubscribeParams {
 pub struct SolClient {
     keypair: Keypair,
 
-    // subscription hashmap with pubkey and balance
-    subscriptions: Arc<Mutex<HashMap<String, u64>>>,
+    // subscription hashmap using pubkey as an index
+    subscriptions: Arc<Mutex<HashMap<String, (Vec<u8>, u64)>>>,
 
     // notify when get new update
     notify_channel: (
@@ -129,13 +128,17 @@ impl SolClient {
                     // TODO remove unwrap
                     let new_bal = n.params["result"]["value"]["lamports"].as_u64().unwrap();
                     let owner_pubkey = n.params["result"]["value"]["owner"].as_str().unwrap();
-                    let old_balance = self.subscriptions.lock().await[owner_pubkey];
+                    let (keypair, old_balance) =
+                        self.subscriptions.lock().await[owner_pubkey].clone();
 
                     if new_bal > old_balance {
                         let sub_id = n.params["subscription"].as_u64().unwrap();
                         let received_balance = new_bal - old_balance;
 
-                        // TODO Send the received coins to the main address
+                        let keypair: Keypair = deserialize(&keypair).expect("deserialize keypair");
+
+                        self.send_to_main_account(keypair)
+                            .expect("Send to main account");
 
                         self.notify_channel
                             .0
@@ -144,7 +147,7 @@ impl SolClient {
                                 received_balance,
                             ))
                             .await
-                            .expect(" send notify msg");
+                            .expect("send notify msg");
 
                         SolClient::unsubscribe(self.watch_channel.0.clone(), sub_id)
                             .await
@@ -168,6 +171,26 @@ impl SolClient {
         Ok(())
     }
 
+    fn send_to_main_account(&self, keypair: Keypair) -> Result<()> {
+        let rpc = RpcClient::new(RPC_SERVER.to_string());
+
+        let amount = rpc.get_balance(&keypair.pubkey()).unwrap();
+
+        let instruction =
+            system_instruction::transfer(&keypair.pubkey(), &self.keypair.pubkey(), amount);
+
+        let mut tx = Transaction::new_with_payer(&[instruction], Some(&keypair.pubkey()));
+        let bhq = BlockhashQuery::default();
+        match bhq.get_blockhash_and_fee_calculator(&rpc, rpc.commitment()) {
+            Err(_) => panic!("Couldn't connect to RPC"),
+            Ok(v) => tx.sign(&[&keypair], v.0),
+        }
+        let _signature = rpc
+            .send_and_confirm_transaction(&tx)
+            .expect("send transaction");
+        Ok(())
+    }
+
     async fn unsubscribe(
         watch_channel_sender: async_channel::Sender<jsonrpc::JsonRequest>,
         sub_id: u64,
@@ -198,16 +221,16 @@ impl CoinClient for SolClient {
         let rpc = RpcClient::new(RPC_SERVER.to_string());
         let balance = rpc.get_balance(&keypair.pubkey()).unwrap();
 
-        self.subscriptions
-            .lock()
-            .await
-            .insert(keypair.pubkey().to_string(), balance);
+        self.subscriptions.lock().await.insert(
+            keypair.pubkey().to_string(),
+            (serialize(&keypair), balance),
+        );
 
         self.watch_channel.0.send(sub_msg).await?;
 
         let pubkey = serialize(&keypair.pubkey());
-        let private_key = serialize(keypair.secret());
-        Ok((pubkey, private_key))
+        let keypair = serialize(&keypair);
+        Ok((pubkey, keypair))
     }
 
     async fn send(&self, address: Vec<u8>, amount: u64) -> Result<()> {
@@ -269,26 +292,6 @@ impl Decodable for Pubkey {
     }
 }
 
-impl Encodable for SecretKey {
-    fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
-        let key = self.to_bytes();
-        let len = key.encode(s)?;
-        Ok(len)
-    }
-}
-
-impl Decodable for SecretKey {
-    fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
-        let key: Vec<u8> = Decodable::decode(&mut d)?;
-        let key = SecretKey::from_bytes(key.as_slice()).map_err(|_| {
-            crate::Error::from(SolFailed::DecodeAndEncodeError(
-                "load secret key from slice".into(),
-            ))
-        })?;
-        Ok(key)
-    }
-}
-
 #[derive(Debug)]
 pub enum SolFailed {
     NotEnoughValue(u64),

+ 42 - 21
src/wallet/cashierdb.rs

@@ -1,4 +1,4 @@
-use super::WalletApi;
+use super::{Keypair, WalletApi};
 use crate::client::ClientFailed;
 use crate::{Error, Result};
 
@@ -138,8 +138,11 @@ impl CashierDb {
         // unlock database
         conn.pragma_update(None, "key", &self.password)?;
 
-        let mut stmt = conn.prepare("SELECT d_key_private FROM withdraw_keypairs")?;
-        let keys = stmt.query_map([], |row| {
+        let confirm = self.get_value_serialized(&false)?;
+
+        let mut stmt =
+            conn.prepare("SELECT d_key_private FROM withdraw_keypairs WHERE confirm = :confirm")?;
+        let keys = stmt.query_map(&[(":confirm", &confirm)], |row| {
             let private_key: jubjub::Fr = self
                 .get_value_deserialized(row.get(0)?)
                 .expect("deserialize private key");
@@ -155,22 +158,29 @@ impl CashierDb {
         Ok(private_keys)
     }
 
-    // return (public key, private key)
     pub fn get_withdraw_keys_by_coin_public_key(
         &self,
         coin_public_key: &Vec<u8>,
         asset_id: &Vec<u8>,
-    ) -> Result<Option<(jubjub::SubgroupPoint, jubjub::Fr)>> {
+    ) -> Result<Option<Keypair>> {
         debug!(target: "CASHIERDB", "Check for existing coin address");
         // open connection
         let conn = Connection::open(&self.path)?;
         // unlock database
         conn.pragma_update(None, "key", &self.password)?;
 
+        let confirm = self.get_value_serialized(&false)?;
+
         let mut stmt =
-            conn.prepare("SELECT * FROM withdraw_keypairs WHERE coin_key_id = :coin_key_id AND asset_id = :asset_id")?;
-        let addr_iter = stmt.query_map::<(jubjub::SubgroupPoint, jubjub::Fr), _, _>(
-            &[(":coin_key_id", &coin_public_key), (":asset_id", &asset_id)],
+            conn.prepare(
+                "SELECT * FROM withdraw_keypairs WHERE coin_key_id = :coin_key_id AND asset_id = :asset_id AND confirm = :confirm;")?;
+
+        let addr_iter = stmt.query_map::<Keypair, _, _>(
+            &[
+                (":coin_key_id", &coin_public_key),
+                (":asset_id", &asset_id),
+                (":confirm", &&confirm),
+            ],
             |row| {
                 let public: jubjub::SubgroupPoint = self
                     .get_value_deserialized(row.get(2)?)
@@ -178,11 +188,11 @@ impl CashierDb {
                 let private: jubjub::Fr = self
                     .get_value_deserialized(row.get(1)?)
                     .expect("get  private key deserialize");
-                Ok((public, private))
+                Ok(Keypair { public, private })
             },
         )?;
 
-        let mut addresses: Vec<(jubjub::SubgroupPoint, jubjub::Fr)> = vec![];
+        let mut addresses: Vec<Keypair> = vec![];
 
         for addr in addr_iter {
             addresses.push(addr?);
@@ -204,11 +214,17 @@ impl CashierDb {
 
         let d_key_public = self.get_value_serialized(pub_key)?;
 
+        let confirm = self.get_value_serialized(&false)?;
+
         let mut stmt = conn.prepare(
-            "SELECT coin_key_id FROM withdraw_keypairs WHERE d_key_public = :d_key_public AND asset_id = :asset_id",
+            "SELECT coin_key_id FROM withdraw_keypairs WHERE d_key_public = :d_key_public AND asset_id = :asset_id AND confirm = :confirm;",
         )?;
         let addr_iter = stmt.query_map::<Vec<u8>, _, _>(
-            &[(":d_key_public", &d_key_public), (":asset_id", &asset_id)],
+            &[
+                (":d_key_public", &d_key_public),
+                (":asset_id", &asset_id),
+                (":confirm", &&confirm),
+            ],
             |row| Ok(row.get(0)?),
         )?;
 
@@ -221,21 +237,23 @@ impl CashierDb {
         Ok(coin_addresses.pop())
     }
 
-    pub fn delete_withdraw_key_record(
+    pub fn confirm_withdraw_key_record(
         &self,
         coin_address: &Vec<u8>,
         asset_id: &Vec<u8>,
     ) -> Result<()> {
-        debug!(target: "CASHIERDB", "Delete withdraw keys");
+        debug!(target: "CASHIERDB", "Confirm withdraw keys");
 
         // open connection
         let conn = Connection::open(&self.path)?;
         // unlock database
         conn.pragma_update(None, "key", &self.password)?;
 
+        let confirm = self.get_value_serialized(&true)?;
+
         conn.execute(
-            "DELETE FROM withdraw_keypairs WHERE coin_key_id = ?1 AND asset_id = ?2;",
-            params![coin_address, asset_id],
+            "UPDATE withdraw_keypairs SET confirm = ?1  WHERE coin_key_id = ?2 AND asset_id = ?3;",
+            params![confirm, coin_address, asset_id],
         )?;
 
         Ok(())
@@ -258,14 +276,17 @@ impl CashierDb {
         // unlock database
         conn.pragma_update(None, "key", &self.password)?;
 
+        let confirm = self.get_value_serialized(&false)?;
+
         conn.execute(
-            "INSERT INTO withdraw_keypairs(coin_key_id, d_key_private, d_key_public, asset_id)
-            VALUES (:coin_key_id, :d_key_private, :d_key_public, :asset_id)",
+            "INSERT INTO withdraw_keypairs(coin_key_id, d_key_private, d_key_public, asset_id, confirm)
+            VALUES (:coin_key_id, :d_key_private, :d_key_public, :asset_id, :confirm)",
             named_params! {
                 ":coin_key_id": coin_key_id,
                 ":d_key_private": d_key_private,
                 ":d_key_public": d_key_public,
                 ":asset_id": asset_id,
+                ":confirm": confirm,
             },
         )?;
         Ok(())
@@ -302,13 +323,13 @@ mod tests {
 
         let addr = wallet.get_withdraw_keys_by_coin_public_key(&coin_addr, &asset_id)?;
 
-        assert_eq!(addr, Some((public2, secret2)));
+        assert_eq!(addr.is_some(), true);
 
-        wallet.delete_withdraw_key_record(&coin_addr, &asset_id)?;
+        wallet.confirm_withdraw_key_record(&coin_addr, &asset_id)?;
 
         let addr = wallet.get_withdraw_keys_by_coin_public_key(&coin_addr, &asset_id)?;
 
-        assert_eq!(addr, None);
+        assert_eq!(addr.is_none(), true);
 
         wallet.destroy()?;
 

+ 1 - 1
src/wallet/mod.rs

@@ -4,4 +4,4 @@ pub mod walletdb;
 
 pub use cashierdb::{CashierDb, CashierDbPtr};
 pub use wallet_api::WalletApi;
-pub use walletdb::{WalletDb, WalletPtr};
+pub use walletdb::{WalletDb, WalletPtr, Keypair};

+ 22 - 69
src/wallet/walletdb.rs

@@ -4,7 +4,6 @@ use crate::crypto::{
     merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoin, OwnCoins,
 };
 use crate::serial;
-use crate::serial::{deserialize, serialize, Decodable, Encodable};
 use crate::{Error, Result};
 
 use async_std::sync::Arc;
@@ -17,6 +16,12 @@ use std::path::PathBuf;
 
 pub type WalletPtr = Arc<WalletDb>;
 
+#[derive(Debug, Clone)]
+pub struct Keypair {
+    pub public: jubjub::SubgroupPoint,
+    pub private: jubjub::Fr,
+}
+
 pub struct WalletDb {
     pub path: PathBuf,
     pub password: String,
@@ -73,45 +78,31 @@ impl WalletDb {
         )?;
         Ok(())
     }
-    pub fn get_public_keys(&self) -> Result<Vec<jubjub::SubgroupPoint>> {
+    pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
         debug!(target: "WALLETDB", "Returning keys...");
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
-        let mut stmt = conn.prepare("SELECT key_public FROM keys")?;
+        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| row.get(0))?;
-        let mut pub_keys = Vec::new();
+        let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
+        let mut keypairs = Vec::new();
         for key in key_iter {
+            let key = key?;
+            let public = key.0;
+            let private = key.1;
             let public: jubjub::SubgroupPoint =
-                self.get_value_deserialized::<jubjub::SubgroupPoint>(key?)?;
-            pub_keys.push(public);
+                self.get_value_deserialized::<jubjub::SubgroupPoint>(public)?;
+            let private: jubjub::Fr = self.get_value_deserialized::<jubjub::Fr>(private)?;
+            keypairs.push(Keypair { public, private });
         }
 
-        if pub_keys.is_empty() {
-            return Err(Error::from(ClientFailed::DoNotHavePublicKey));
+        if keypairs.is_empty() {
+            return Err(Error::from(ClientFailed::DoNotHaveKeypair));
         }
 
-        Ok(pub_keys)
+        Ok(keypairs)
     }
 
-    pub fn get_private_keys(&self) -> Result<Vec<jubjub::Fr>> {
-        debug!(target: "WALLETDB", "Returning keys...");
-        let conn = Connection::open(&self.path)?;
-        conn.pragma_update(None, "key", &self.password)?;
-        let mut stmt = conn.prepare("SELECT key_private FROM keys")?;
-        let key_iter = stmt.query_map([], |row| row.get(0))?;
-        let mut keys = Vec::new();
-        for key in key_iter {
-            let private: jubjub::Fr = self.get_value_deserialized(key?)?;
-            keys.push(private);
-        }
-
-        if keys.is_empty() {
-            return Err(Error::from(ClientFailed::DoNotHavePrivateKey));
-        }
-
-        Ok(keys)
-    }
     pub fn get_own_coins(&self) -> Result<OwnCoins> {
         // open connection
         let conn = Connection::open(&self.path)?;
@@ -290,43 +281,6 @@ impl WalletDb {
         let _rows = stmt.query([])?;
         Ok(())
     }
-
-    fn get_tables_name(&self) -> Result<Vec<String>> {
-        let conn = Connection::open(&self.path)?;
-        conn.pragma_update(None, "key", &self.password)?;
-        let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table'")?;
-        let table_iter = stmt.query_map::<String, _, _>([], |row| row.get(0))?;
-
-        let mut tables = Vec::new();
-
-        for table in table_iter {
-            tables.push(table?);
-        }
-
-        Ok(tables)
-    }
-
-    pub fn destroy(&self) -> Result<()> {
-        let conn = Connection::open(&self.path)?;
-        conn.pragma_update(None, "key", &self.password)?;
-
-        for table in self.get_tables_name()?.iter() {
-            let drop_stmt = format!("DROP TABLE IF EXISTS {}", table);
-            let drop_stmt = drop_stmt.as_str();
-            conn.execute(drop_stmt, [])?;
-        }
-
-        Ok(())
-    }
-    pub fn get_value_serialized<T: Encodable>(&self, data: &T) -> Result<Vec<u8>> {
-        let v = serialize(data);
-        Ok(v)
-    }
-
-    pub fn get_value_deserialized<D: Decodable>(&self, key: Vec<u8>) -> Result<D> {
-        let v: D = deserialize(&key)?;
-        Ok(v)
-    }
 }
 
 #[cfg(test)]
@@ -350,11 +304,10 @@ mod tests {
 
         wallet.put_keypair(key_public, key_private)?;
 
-        let public2 = wallet.get_public_keys()?;
-        let secret2 = wallet.get_private_keys()?;
+        let keypair = wallet.get_keypairs()?[0].clone();
 
-        assert_eq!(public, public2[0]);
-        assert_eq!(secret, secret2[0]);
+        assert_eq!(public, keypair.public);
+        assert_eq!(secret, keypair.private);
 
         wallet.destroy()?;
 

+ 1 - 0
todo.md

@@ -93,6 +93,7 @@ Open research questions.
 ## dev
 
 - [ ] make bitreich halo2 impl
+- [ ] doc on circuit design
 
 # halo2