| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- use std::{fs::create_dir_all, path::Path, str::FromStr, time::Duration};
- use async_std::sync::Arc;
- use incrementalmerkletree::bridgetree::BridgeTree;
- use log::{debug, error, info, LevelFilter};
- use sqlx::{
- sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions},
- ConnectOptions, Row, SqlitePool,
- };
- use super::wallet_api::WalletApi;
- use super::WalletError;
- use crate::{
- crypto::{
- keypair::{Keypair, PublicKey, SecretKey},
- merkle_node::MerkleNode,
- types::DrkTokenId,
- },
- util::NetworkName,
- Result,
- };
- pub type CashierDbPtr = Arc<CashierDb>;
- #[derive(Debug, Clone)]
- pub struct TokenKey {
- pub public_key: Vec<u8>,
- pub secret_key: Vec<u8>,
- }
- pub struct WithdrawToken {
- pub token_public_key: Vec<u8>,
- pub network: NetworkName,
- pub token_id: DrkTokenId,
- pub mint_address: String,
- }
- pub struct DepositToken {
- pub drk_public_key: PublicKey,
- pub token_key: TokenKey,
- pub token_id: DrkTokenId,
- pub mint_address: String,
- }
- pub struct CashierDb {
- pub conn: SqlitePool,
- }
- impl WalletApi for CashierDb {}
- impl CashierDb {
- pub async fn new(path: &str, password: &str) -> Result<CashierDbPtr> {
- debug!("new() Constructor called");
- if password.trim().is_empty() {
- error!("Password is empty. You must set a password to use the wallet.");
- return Err(WalletError::EmptyPassword.into())
- }
- if path != "sqlite::memory:" {
- let p = Path::new(path.strip_prefix("sqlite://").unwrap());
- if let Some(dirname) = p.parent() {
- info!("Creating path to database: {}", dirname.display());
- create_dir_all(&dirname)?;
- }
- }
- let mut connect_opts = SqliteConnectOptions::from_str(path)?
- .pragma("key", password.to_string())
- .create_if_missing(true)
- .journal_mode(SqliteJournalMode::Off);
- connect_opts.log_statements(LevelFilter::Trace);
- connect_opts.log_slow_statements(LevelFilter::Trace, Duration::from_micros(10));
- let conn = SqlitePoolOptions::new().connect_with(connect_opts).await?;
- info!("Opened connection at path: {:?}", path);
- Ok(Arc::new(CashierDb { conn }))
- }
- pub async fn init_db(&self) -> Result<()> {
- let main_kps = include_str!("../../script/sql/cashier_main_keypairs.sql");
- let deposit_kps = include_str!("../../script/sql/cashier_deposit_keypairs.sql");
- let withdraw_kps = include_str!("../../script/sql/cashier_withdraw_keypairs.sql");
- let mut conn = self.conn.acquire().await?;
- debug!("Initializing main keypairs table");
- sqlx::query(main_kps).execute(&mut conn).await?;
- debug!("Initializing deposit keypairs table");
- sqlx::query(deposit_kps).execute(&mut conn).await?;
- debug!("Initializing withdraw keypairs table");
- sqlx::query(withdraw_kps).execute(&mut conn).await?;
- Ok(())
- }
- pub async fn tree_gen(&self) -> Result<()> {
- debug!("Attempting to generate merkle tree");
- let mut conn = self.conn.acquire().await?;
- match sqlx::query("SELECT * FROM tree").fetch_one(&mut conn).await {
- Ok(_) => {
- error!("Merkle tree already exists");
- Err(WalletError::TreeExists.into())
- }
- Err(_) => {
- let tree = BridgeTree::<MerkleNode, 32>::new(100);
- self.put_tree(&tree).await?;
- Ok(())
- }
- }
- }
- pub async fn get_tree(&self) -> Result<BridgeTree<MerkleNode, 32>> {
- debug!("Getting merkle tree");
- let mut conn = self.conn.acquire().await?;
- let row = sqlx::query("SELECT tree FROM tree").fetch_one(&mut conn).await?;
- let tree: BridgeTree<MerkleNode, 32> = bincode::deserialize(row.get("tree"))?;
- Ok(tree)
- }
- pub async fn put_tree(&self, tree: &BridgeTree<MerkleNode, 32>) -> Result<()> {
- debug!("Attempting to write merkle tree");
- let mut conn = self.conn.acquire().await?;
- let tree_bytes = bincode::serialize(tree)?;
- sqlx::query("INSERT INTO tree(tree) VALUES (?1)")
- .bind(tree_bytes)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn put_main_keys(&self, token_key: &TokenKey, network: &NetworkName) -> Result<()> {
- debug!("Writing main keys into the database");
- let network = self.get_value_serialized(network)?;
- let mut conn = self.conn.acquire().await?;
- sqlx::query(
- "INSERT INTO main_keypairs
- (token_key_secret, token_key_public, network)
- VALUES
- (?1, ?2, ?3);",
- )
- .bind(token_key.secret_key.clone())
- .bind(token_key.public_key.clone())
- .bind(network)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn get_main_keys(&self, network: &NetworkName) -> Result<Vec<TokenKey>> {
- debug!("Returning main keypairs");
- let network = self.get_value_serialized(network)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT token_key_secret, token_key_public
- FROM main_keypairs WHERE network = ?1;",
- )
- .bind(network)
- .fetch_all(&mut conn)
- .await?;
- let mut keys = vec![];
- for row in rows {
- let secret_key = row.get("token_key_secret");
- let public_key = row.get("token_key_public");
- keys.push(TokenKey { secret_key, public_key })
- }
- Ok(keys)
- }
- pub async fn remove_withdraw_and_deposit_keys(&self) -> Result<()> {
- debug!("Removing withdraw and deposit keys");
- let mut conn = self.conn.acquire().await?;
- sqlx::query("DROP TABLE deposit_keypairs;").execute(&mut conn).await?;
- sqlx::query("DROP TABLE withdraw_keypairs;").execute(&mut conn).await?;
- Ok(())
- }
- pub async fn put_withdraw_keys(
- &self,
- token_key_public: &[u8],
- d_key_public: &PublicKey,
- d_key_secret: &SecretKey,
- network: &NetworkName,
- token_id: &DrkTokenId,
- mint_address: String,
- ) -> Result<()> {
- debug!("Writing withdraw keys to database");
- let public = self.get_value_serialized(d_key_public)?;
- let secret = self.get_value_serialized(d_key_secret)?;
- let network = self.get_value_serialized(network)?;
- let token_id = self.get_value_serialized(token_id)?;
- let confirm = self.get_value_serialized(&false)?;
- let mint_address = self.get_value_serialized(&mint_address)?;
- let mut conn = self.conn.acquire().await?;
- sqlx::query(
- "INSERT INTO withdraw_keypairs
- (token_key_public, d_key_secret, d_key_public,
- network, token_id, mint_address, confirm)
- VALUES
- (?1, ?2, ?3, ?4, ?5, ?6, ?7);",
- )
- .bind(token_key_public)
- .bind(secret)
- .bind(public)
- .bind(network)
- .bind(token_id)
- .bind(mint_address)
- .bind(confirm)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn put_deposit_keys(
- &self,
- d_key_public: &PublicKey,
- token_key_secret: &[u8],
- token_key_public: &[u8],
- network: &NetworkName,
- token_id: &DrkTokenId,
- mint_address: String,
- ) -> Result<()> {
- debug!("Writing deposit keys to database");
- let d_key_public = self.get_value_serialized(d_key_public)?;
- let token_id = self.get_value_serialized(token_id)?;
- let network = self.get_value_serialized(network)?;
- let confirm = self.get_value_serialized(&false)?;
- let mint_address = self.get_value_serialized(&mint_address)?;
- let mut conn = self.conn.acquire().await?;
- sqlx::query(
- "INSERT INTO deposit_keypairs
- (d_key_public, token_key_secret, token_key_public,
- network, token_id, mint_address, confirm)
- VALUES
- (?1, ?2, ?3, ?4, ?5, ?6, ?7);",
- )
- .bind(d_key_public)
- .bind(token_key_secret)
- .bind(token_key_public)
- .bind(network)
- .bind(token_id)
- .bind(mint_address)
- .bind(confirm)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn get_withdraw_private_keys(&self) -> Result<Vec<SecretKey>> {
- debug!("Getting withdraw private keys");
- let confirm = self.get_value_serialized(&false)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT d_key_secret FROM withdraw_keypairs
- WHERE confirm = ?1",
- )
- .bind(confirm)
- .fetch_all(&mut conn)
- .await?;
- let mut secret_keys = vec![];
- for row in rows {
- let key: SecretKey = self.get_value_deserialized(row.get("d_key_secret"))?;
- secret_keys.push(key);
- }
- Ok(secret_keys)
- }
- pub async fn get_withdraw_token_public_key_by_dkey_public(
- &self,
- pubkey: &PublicKey,
- ) -> Result<Option<WithdrawToken>> {
- debug!("Get token address by pubkey");
- let d_key_public = self.get_value_serialized(pubkey)?;
- let confirm = self.get_value_serialized(&false)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT token_key_public, network, token_id, mint_address
- FROM withdraw_keypairs
- WHERE d_key_public = ?1
- AND confirm = ?2;",
- )
- .bind(d_key_public)
- .bind(confirm)
- .fetch_all(&mut conn)
- .await?;
- let mut token_addrs = vec![];
- for row in rows {
- let token_public_key = row.get("token_key_public");
- let network = self.get_value_deserialized(row.get("network"))?;
- let token_id = self.get_value_deserialized(row.get("token_id"))?;
- let mint_address = self.get_value_deserialized(row.get("mint_address"))?;
- token_addrs.push(WithdrawToken { token_public_key, network, token_id, mint_address });
- }
- Ok(token_addrs.pop())
- }
- pub async fn get_deposit_token_keys_by_dkey_public(
- &self,
- d_key_public: &PublicKey,
- network: &NetworkName,
- ) -> Result<Vec<TokenKey>> {
- debug!("Checking for existing dkey");
- let d_key_public = self.get_value_serialized(d_key_public)?;
- let network = self.get_value_serialized(network)?;
- let confirm = self.get_value_serialized(&false)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT token_key_secret, token_key_public
- FROM deposit_keypairs
- WHERE d_key_public = ?1
- AND network = ?2
- AND confirm = ?3;",
- )
- .bind(d_key_public)
- .bind(network)
- .bind(confirm)
- .fetch_all(&mut conn)
- .await?;
- let mut keys = vec![];
- for row in rows {
- let secret_key = row.get("token_key_secret");
- let public_key = row.get("token_key_public");
- keys.push(TokenKey { secret_key, public_key });
- }
- Ok(keys)
- }
- pub async fn get_withdraw_keys_by_token_public_key(
- &self,
- token_key_public: &[u8],
- network: &NetworkName,
- ) -> Result<Option<Keypair>> {
- debug!("Checking for existing token address");
- let confirm = self.get_value_serialized(&false)?;
- let network = self.get_value_serialized(network)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT d_key_secret, d_key_public FROM withdraw_keypairs
- WHERE token_key_public = ?1
- AND network = ?2
- AND confirm = ?3;",
- )
- .bind(token_key_public)
- .bind(network)
- .bind(confirm)
- .fetch_all(&mut conn)
- .await?;
- let mut keypairs = vec![];
- for row in rows {
- let public = self.get_value_deserialized(row.get("d_key_public"))?;
- let secret = self.get_value_deserialized(row.get("d_key_secret"))?;
- keypairs.push(Keypair { public, secret });
- }
- Ok(keypairs.pop())
- }
- pub async fn confirm_withdraw_key_record(
- &self,
- token_address: &[u8],
- network: &NetworkName,
- ) -> Result<()> {
- debug!("Confirm withdraw keys");
- let network = self.get_value_serialized(network)?;
- let confirm = self.get_value_serialized(&true)?;
- let mut conn = self.conn.acquire().await?;
- sqlx::query(
- "UPDATE withdraw_keypairs
- SET confirm = ?1
- WHERE token_key_public = ?2
- AND network = ?3;",
- )
- .bind(confirm)
- .bind(token_address)
- .bind(network)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn confirm_deposit_key_record(
- &self,
- d_key_public: &PublicKey,
- network: &NetworkName,
- ) -> Result<()> {
- debug!("Confirm deposit keys");
- let network = self.get_value_serialized(network)?;
- let confirm = self.get_value_serialized(&true)?;
- let d_key_public = self.get_value_serialized(d_key_public)?;
- let mut conn = self.conn.acquire().await?;
- sqlx::query(
- "UPDATE deposit_keypairs
- SET confirm = ?1
- WHERE d_key_public = ?2
- AND network = ?3;",
- )
- .bind(confirm)
- .bind(d_key_public)
- .bind(network)
- .execute(&mut conn)
- .await?;
- Ok(())
- }
- pub async fn get_deposit_token_keys_by_network(
- &self,
- network: &NetworkName,
- ) -> Result<Vec<DepositToken>> {
- debug!("Checking for existing dkey");
- let network = self.get_value_serialized(network)?;
- let confirm = self.get_value_serialized(&false)?;
- let mut conn = self.conn.acquire().await?;
- let rows = sqlx::query(
- "SELECT d_key_public, token_key_secret, token_key_public, token_id, mint_address
- FROM deposit_keypairs
- WHERE network = ?1
- AND confirm = ?2;",
- )
- .bind(network)
- .bind(confirm)
- .fetch_all(&mut conn)
- .await?;
- let mut keys = vec![];
- for row in rows {
- let drk_public_key = self.get_value_deserialized(row.get("d_key_public"))?;
- let secret_key = row.get("token_key_secret");
- let public_key = row.get("token_key_public");
- let token_id = self.get_value_deserialized(row.get("token_id"))?;
- let mint_address = self.get_value_deserialized(row.get("mint_address"))?;
- keys.push(DepositToken {
- drk_public_key,
- token_key: TokenKey { secret_key, public_key },
- token_id,
- mint_address,
- });
- }
- Ok(keys)
- }
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- use crate::util::serial::serialize;
- use group::ff::Field;
- use rand::rngs::OsRng;
- const WPASS: &str = "darkfi";
- #[async_std::test]
- async fn test_cashierdb() -> Result<()> {
- let wallet = CashierDb::new("sqlite::memory:", WPASS).await?;
- // init_db()
- wallet.init_db().await?;
- // BTC testnet address
- let token_addr_secret = serialize(&String::from("2222222222222222222222222222222222"));
- let token_addr_public = serialize(&String::from("mxVFsFW5N4mu1HPkxPttorvocvzeZ7KZyk"));
- let keypair = Keypair::random(&mut OsRng);
- let token_id = DrkTokenId::random(&mut OsRng);
- let network = NetworkName::Bitcoin;
- // put_main_keys()
- wallet
- .put_main_keys(
- &TokenKey {
- secret_key: token_addr_secret.clone(),
- public_key: token_addr_public.clone(),
- },
- &network,
- )
- .await?;
- // get_main_keys()
- let keys = wallet.get_main_keys(&network).await?;
- assert_eq!(keys.len(), 1);
- assert_eq!(keys[0].secret_key, token_addr_secret);
- assert_eq!(keys[0].public_key, token_addr_public);
- // put_deposit_keys()
- wallet
- .put_deposit_keys(
- &keypair.public,
- &token_addr_secret,
- &token_addr_public,
- &network,
- &token_id,
- String::new(),
- )
- .await?;
- // get_deposit_token_keys_by_dkey_public()
- let keys = wallet.get_deposit_token_keys_by_dkey_public(&keypair.public, &network).await?;
- assert_eq!(keys.len(), 1);
- assert_eq!(keys[0].secret_key, token_addr_secret);
- assert_eq!(keys[0].public_key, token_addr_public);
- // get_deposit_token_keys_by_network()
- let resumed_keys = wallet.get_deposit_token_keys_by_network(&network).await?;
- assert_eq!(resumed_keys[0].drk_public_key, keypair.public);
- assert_eq!(resumed_keys[0].token_key.secret_key, token_addr_secret);
- assert_eq!(resumed_keys[0].token_key.public_key, token_addr_public);
- assert_eq!(resumed_keys[0].token_id, token_id);
- // confirm_deposit_key_record()
- wallet.confirm_deposit_key_record(&keypair.public, &network).await?;
- let keys = wallet.get_deposit_token_keys_by_dkey_public(&keypair.public, &network).await?;
- assert_eq!(keys.len(), 0);
- // put_withdraw_keys()
- wallet
- .put_withdraw_keys(
- &token_addr_public,
- &keypair.public,
- &keypair.secret,
- &network,
- &token_id,
- String::new(),
- )
- .await?;
- // get_withdraw_keys_by_token_public_key()
- let addr =
- wallet.get_withdraw_keys_by_token_public_key(&token_addr_public, &network).await?;
- assert!(addr.is_some());
- // confirm_withdraw_key_record()
- wallet.confirm_withdraw_key_record(&token_addr_public, &network).await?;
- let addr =
- wallet.get_withdraw_keys_by_token_public_key(&token_addr_public, &network).await?;
- assert!(addr.is_none());
- Ok(())
- }
- }
|