make cashierdb generic and use asset_id with each keys saved

This commit is contained in:
ghassmo
2021-09-09 15:20:31 +03:00
parent 606cf7a3a8
commit afae1cc619
3 changed files with 90 additions and 92 deletions

View File

@@ -1,11 +1,12 @@
CREATE TABLE IF NOT EXISTS keypairs(
dkey_id INTEGER PRIMARY KEY NOT NULL,
btc_key_private BLOB NOT NULL,
btc_key_public BLOB NOT NULL,
txid BLOB
CREATE TABLE IF NOT EXISTS deposit_keypairs(
d_key_public INTEGER PRIMARY KEY NOT NULL,
coin_key_private BLOB NOT NULL,
coin_key_public BLOB NOT NULL,
asset_id BLOB NOT NULL
);
CREATE TABLE IF NOT EXISTS withdraw_keypairs(
btc_key_id BLOB PRIMARY KEY NOT NULL,
coin_key_id BLOB PRIMARY KEY NOT NULL,
d_key_private BLOB NOT NULL,
d_key_public BLOB NOT NULL
d_key_public BLOB NOT NULL,
asset_id BLOB NOT NULL
);

View File

@@ -16,7 +16,6 @@ use log::*;
use async_std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::path::PathBuf;
use std::str::FromStr;
#[repr(u8)]
enum CashierError {
@@ -106,11 +105,11 @@ impl CashierService {
loop {
let (pub_key, amount) = recv_queue.recv().await.expect("Receive Own Coin");
debug!(target: "CASHIER DAEMON", "Receive coin with following address and amount: {}, {}", pub_key, amount);
let btc_addr = wallet.get_btc_addr_by_address(&pub_key).expect("Get btc_key by pub_key");
let btc_addr = wallet.get_withdraw_coin_public_key_by_dkey_public(&pub_key, &serialize(&1)).expect("Get btc_key by pub_key");
if let Some(addr) = btc_addr {
// TODO send equivalent amount of btc to this address
// then delete this btc_addr from withdraw_keys records
wallet.delete_withdraw_key_record(&addr).expect("Delete withdraw key record");
wallet.delete_withdraw_key_record(&addr, &serialize(&1) ).expect("Delete withdraw key record");
}
}
@@ -173,11 +172,12 @@ impl CashierService {
0 => {
debug!(target: "CASHIER DAEMON", "Received deposit request");
// Exchange zk_pubkey for bitcoin address
let zkpub = request.get_payload();
let dpub = request.get_payload();
//TODO: check if key has already been issued
let dpub: jubjub::SubgroupPoint = deserialize(&zkpub)?;
let _check = cashier_wallet.get_btc_keys_by_dkey(&dpub);
let dpub: jubjub::SubgroupPoint = deserialize(&dpub)?;
let _check =
cashier_wallet.get_deposit_coin_keys_by_dkey_public(&dpub, &serialize(&1));
// Generate bitcoin Address
let btc_keys = BitcoinKeys::new(btc_client)?;
@@ -188,7 +188,12 @@ impl CashierService {
let _script = btc_keys.get_script();
// add pairings to db
let _result = cashier_wallet.put_exchange_keys(&dpub, btc_priv, btc_pub);
let _result = cashier_wallet.put_exchange_keys(
&dpub,
&btc_priv.to_bytes(),
&btc_pub.to_bytes(),
&serialize(&1),
);
let mut reply = Reply::from(&request, CashierError::NoError as u32, vec![]);
@@ -209,15 +214,15 @@ impl CashierService {
1 => {
debug!(target: "CASHIER DAEMON", "Received withdraw request");
let btc_address = 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 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 cashier_public: jubjub::SubgroupPoint;
if let Some(addr) = cashier_wallet.get_address_by_btc_key(&btc_address)? {
if let Some(addr) = cashier_wallet
.get_withdraw_keys_by_coin_public_key(&btc_address, &serialize(&1))?
{
cashier_public = addr.0;
} else {
let cashier_secret = jubjub::Fr::random(&mut OsRng);
@@ -228,6 +233,7 @@ impl CashierService {
&btc_address,
&cashier_public,
&cashier_secret,
&serialize(&1),
)?;
}

View File

@@ -1,16 +1,12 @@
use super::WalletApi;
use crate::client::ClientFailed;
use crate::service::btc::{BitcoinKeys, PrivKey, PubKey};
use crate::{Error, Result};
use async_std::sync::Arc;
use bitcoin::Address as BtcAddr;
use log::*;
use rusqlite::{named_params, params, Connection};
use std::path::PathBuf;
use std::str::FromStr;
pub type CashierDbPtr = Arc<CashierDb>;
@@ -51,29 +47,27 @@ impl CashierDb {
Ok(())
}
pub fn get_btc_keys_by_dkey(
// return private and public keys as a tuple
pub fn get_deposit_coin_keys_by_dkey_public(
&self,
dkey_pub: &jubjub::SubgroupPoint,
) -> Result<Vec<(PrivKey, PubKey)>> {
d_key_public: &jubjub::SubgroupPoint,
asset_id: &Vec<u8>,
) -> Result<Vec<(Vec<u8>, Vec<u8>)>> {
debug!(target: "CASHIERDB", "Check for existing dkey");
let dkey_pub = self.get_value_serialized(dkey_pub)?;
let d_key_public = self.get_value_serialized(d_key_public)?;
// open connection
let conn = Connection::open(&self.path)?;
// unlock database
conn.pragma_update(None, "key", &self.password)?;
let mut stmt = conn.prepare("SELECT * FROM keypairs where dkey_id = :dkey_id")?;
let keys_iter =
stmt.query_map::<(PrivKey, PubKey), _, _>(&[(":dkey_id", &dkey_pub)], |row| {
let s_key: Vec<u8> = row.get(1)?;
let private = BitcoinKeys::private_key_from_slice(&s_key)
.expect("get btc private key from slice");
let p_key: Vec<u8> = row.get(2)?;
let public = PubKey::from_slice(&p_key).expect("get btc public key from slice");
Ok((private, public))
})?;
let mut stmt =
conn.prepare("SELECT * FROM deposit_keypairs where d_key_public = :d_key_public AND asset_id = :asset_id")?;
let keys_iter = stmt.query_map::<(Vec<u8>, Vec<u8>), _, _>(
&[(":d_key_public", &d_key_public), (":asset_id", &asset_id)],
|row| Ok((row.get(1)?, row.get(2)?)),
)?;
let mut keys: Vec<(PrivKey, PubKey)> = vec![];
let mut keys = vec![];
for k in keys_iter {
keys.push(k?);
@@ -85,16 +79,14 @@ impl CashierDb {
// Update to take BitcoinKeys instance instead
pub fn put_exchange_keys(
&self,
dkey_pub: &jubjub::SubgroupPoint,
btc_private: &PrivKey,
btc_public: &PubKey,
//txid will be updated when exists
d_key_public: &jubjub::SubgroupPoint,
coin_private: &Vec<u8>,
coin_public: &Vec<u8>,
asset_id: &Vec<u8>,
) -> Result<()> {
debug!(target: "CASHIERDB", "Put exchange keys");
// prepare the values
let dkey_pub = self.get_value_serialized(dkey_pub)?;
let btc_private = btc_private.to_bytes();
let btc_public = btc_public.to_bytes();
let d_key_public = self.get_value_serialized(d_key_public)?;
// open connection
let conn = Connection::open(&self.path)?;
@@ -102,12 +94,13 @@ impl CashierDb {
conn.pragma_update(None, "key", &self.password)?;
conn.execute(
"INSERT INTO keypairs(dkey_id, btc_key_private, btc_key_public)
VALUES (:dkey_id, :btc_key_private, :btc_key_public)",
"INSERT INTO deposit_keypairs(d_key_public, coin_key_private, coin_key_public, asset_id)
VALUES (:d_key_public, :coin_key_private, :coin_key_public, :asset_id)",
named_params! {
":dkey_id": dkey_pub,
":btc_key_private": btc_private,
":btc_key_private": btc_public,
":d_key_public": d_key_public,
":coin_key_private": coin_private,
":coin_key_public": coin_public,
":asset_id": asset_id,
},
)?;
Ok(())
@@ -138,23 +131,21 @@ impl CashierDb {
}
// return (public key, private key)
pub fn get_address_by_btc_key(
pub fn get_withdraw_keys_by_coin_public_key(
&self,
btc_address: &BtcAddr,
coin_public_key: &Vec<u8>,
asset_id: &Vec<u8>,
) -> Result<Option<(jubjub::SubgroupPoint, jubjub::Fr)>> {
debug!(target: "CASHIERDB", "Check for existing btc address");
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 btc_address = btc_address.to_string();
let btc_address = self.get_value_serialized(&btc_address)?;
let mut stmt =
conn.prepare("SELECT * FROM withdraw_keypairs where btc_key_id = :btc_key_id")?;
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), _, _>(
&[(":btc_key_id", &btc_address)],
&[(":coin_key_id", &coin_public_key), (":asset_id", &asset_id)],
|row| {
let public: jubjub::SubgroupPoint = self
.get_value_deserialized(row.get(2)?)
@@ -175,11 +166,12 @@ impl CashierDb {
Ok(addresses.pop())
}
pub fn get_btc_addr_by_address(
pub fn get_withdraw_coin_public_key_by_dkey_public(
&self,
pub_key: &jubjub::SubgroupPoint,
) -> Result<Option<BtcAddr>> {
debug!(target: "CASHIERDB", "Get btc address by pub_key");
asset_id: &Vec<u8>,
) -> Result<Option<Vec<u8>>> {
debug!(target: "CASHIERDB", "Get coin address by pub_key");
// open connection
let conn = Connection::open(&self.path)?;
// unlock database
@@ -188,28 +180,23 @@ impl CashierDb {
let d_key_public = self.get_value_serialized(pub_key)?;
let mut stmt = conn.prepare(
"SELECT btc_key_id FROM withdraw_keypairs where d_key_public = :d_key_public",
"SELECT coin_key_id FROM withdraw_keypairs WHERE d_key_public = :d_key_public AND asset_id = :asset_id",
)?;
let addr_iter =
stmt.query_map::<BtcAddr, _, _>(&[(":d_key_public", &d_key_public)], |row| {
let btc_address: String = self
.get_value_deserialized(row.get(0)?)
.expect("deserialize btc address");
let btc_address = bitcoin::util::address::Address::from_str(&btc_address)
.expect("get btc_address from_str");
Ok(btc_address)
stmt.query_map::<Vec<u8>, _, _>(&[(":d_key_public", &d_key_public), (":asset_id", &asset_id)], |row| {
Ok(row.get(0)?)
})?;
let mut btc_addresses: Vec<BtcAddr> = vec![];
let mut coin_addresses = vec![];
for addr in addr_iter {
btc_addresses.push(addr?);
coin_addresses.push(addr?);
}
Ok(btc_addresses.pop())
Ok(coin_addresses.pop())
}
pub fn delete_withdraw_key_record(&self, btc_address: &BtcAddr) -> Result<()> {
pub fn delete_withdraw_key_record(&self, coin_address: &Vec<u8>, asset_id: &Vec<u8> ) -> Result<()> {
debug!(target: "CASHIERDB", "Delete withdraw keys");
// open connection
@@ -217,12 +204,9 @@ impl CashierDb {
// unlock database
conn.pragma_update(None, "key", &self.password)?;
let btc_address = btc_address.to_string();
let btc_address = self.get_value_serialized(&btc_address)?;
conn.execute(
"DELETE FROM withdraw_keypairs WHERE btc_key_id = ?1;",
params![btc_address],
"DELETE FROM withdraw_keypairs WHERE coin_key_id = ?1 AND asset_id = ?2;",
params![coin_address, asset_id],
)?;
Ok(())
@@ -230,15 +214,13 @@ impl CashierDb {
pub fn put_withdraw_keys(
&self,
btc_key_id: &BtcAddr,
coin_key_id: &Vec<u8>,
d_key_public: &jubjub::SubgroupPoint,
d_key_private: &jubjub::Fr,
asset_id: &Vec<u8>,
) -> Result<()> {
debug!(target: "CASHIERDB", "Put withdraw keys");
let btc_key_id = btc_key_id.to_string();
let btc_key_id = self.get_value_serialized(&btc_key_id)?;
let d_key_public = self.get_value_serialized(d_key_public)?;
let d_key_private = self.get_value_serialized(d_key_private)?;
@@ -248,12 +230,13 @@ impl CashierDb {
conn.pragma_update(None, "key", &self.password)?;
conn.execute(
"INSERT INTO withdraw_keypairs(btc_key_id, d_key_private, d_key_public)
VALUES (:btc_key_id, :d_key_private, :d_key_public)",
"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)",
named_params! {
":btc_key_id": btc_key_id,
":coin_key_id": coin_key_id,
":d_key_private": d_key_private,
":d_key_public": d_key_public,
":asset_id": asset_id,
},
)?;
Ok(())
@@ -264,8 +247,8 @@ impl CashierDb {
mod tests {
use super::*;
use crate::serial::serialize;
use crate::util::join_config_path;
use crate::service::BtcFailed;
use ff::Field;
use rand::rngs::OsRng;
@@ -273,7 +256,7 @@ mod tests {
// TODO add more tests
#[test]
pub fn test_put_withdraw_keys_and_load_them_with_btc_key() -> Result<()> {
pub fn test_put_withdraw_keys_and_load_them_with_coin_key() -> Result<()> {
let walletdb_path = join_config_path(&PathBuf::from("cashier_wallet_test.db"))?;
let wallet = CashierDb::new(&walletdb_path, "darkfi".into())?;
wallet.init_db()?;
@@ -282,14 +265,22 @@ mod tests {
let public2 = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret2;
// btc addr testnet
let btc_addr = BtcAddr::from_str(&String::from("mxVFsFW5N4mu1HPkxPttorvocvzeZ7KZyk")).map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
let coin_addr = serialize(&String::from("mxVFsFW5N4mu1HPkxPttorvocvzeZ7KZyk"));
wallet.put_withdraw_keys(&btc_addr, &public2, &secret2)?;
let asset_id = serialize(&1);
let addr = wallet.get_address_by_btc_key(&btc_addr)?;
wallet.put_withdraw_keys(&coin_addr, &public2, &secret2, &asset_id)?;
let addr = wallet.get_withdraw_keys_by_coin_public_key(&coin_addr, &asset_id)?;
assert_eq!(addr, Some((public2, secret2)));
wallet.delete_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);
wallet.destroy()?;
Ok(())