Răsfoiți Sursa

wallet: Port to sqlx.

Note there is still some connection bug, where the sqlcipher pragma
doesn't seem to work after a subsequent connection.
We shall investigate and solve this.
parazyd 4 ani în urmă
părinte
comite
4d39e92524
8 a modificat fișierele cu 602 adăugiri și 521 ștergeri
  1. 216 37
      Cargo.lock
  2. 6 1
      Cargo.toml
  3. 6 5
      src/client.rs
  4. 5 5
      src/error.rs
  5. 1 1
      src/service/bridge.rs
  6. 1 1
      src/state.rs
  7. 199 238
      src/wallet/cashierdb.rs
  8. 168 233
      src/wallet/walletdb.rs

+ 216 - 37
Cargo.lock

@@ -212,6 +212,18 @@ dependencies = [
  "event-listener",
 ]
 
+[[package]]
+name = "async-native-tls"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33"
+dependencies = [
+ "async-std",
+ "native-tls",
+ "thiserror",
+ "url",
+]
+
 [[package]]
 name = "async-native-tls"
 version = "0.4.0"
@@ -263,6 +275,7 @@ dependencies = [
  "async-global-executor",
  "async-io",
  "async-lock",
+ "async-process",
  "crossbeam-utils 0.8.5",
  "futures-channel",
  "futures-core",
@@ -323,6 +336,15 @@ dependencies = [
  "pin-project-lite",
 ]
 
+[[package]]
+name = "atoi"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "atomic-waker"
 version = "1.0.0"
@@ -1078,6 +1100,21 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "crc"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403"
+
 [[package]]
 name = "crc32fast"
 version = "1.2.2"
@@ -1097,7 +1134,7 @@ dependencies = [
  "crossbeam-channel 0.4.4",
  "crossbeam-deque 0.7.4",
  "crossbeam-epoch 0.8.2",
- "crossbeam-queue",
+ "crossbeam-queue 0.2.3",
  "crossbeam-utils 0.7.2",
 ]
 
@@ -1182,6 +1219,16 @@ dependencies = [
  "maybe-uninit",
 ]
 
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-utils 0.8.5",
+]
+
 [[package]]
 name = "crossbeam-utils"
 version = "0.7.2"
@@ -1326,7 +1373,7 @@ dependencies = [
  "arrayvec 0.7.2",
  "async-channel",
  "async-executor",
- "async-native-tls",
+ "async-native-tls 0.4.0",
  "async-std",
  "async-trait",
  "async-tungstenite",
@@ -1350,6 +1397,7 @@ dependencies = [
  "incrementalmerkletree",
  "keccak-hasher",
  "lazy_static",
+ "libsqlite3-sys",
  "log",
  "native-tls",
  "num-bigint",
@@ -1359,7 +1407,6 @@ dependencies = [
  "rand 0.8.4",
  "ripemd160",
  "rocksdb",
- "rusqlite",
  "secp256k1",
  "serde",
  "serde_json",
@@ -1372,6 +1419,7 @@ dependencies = [
  "solana-sdk",
  "spl-associated-token-account",
  "spl-token",
+ "sqlx",
  "subtle",
  "thiserror",
  "toml",
@@ -1605,6 +1653,12 @@ dependencies = [
  "syn 0.15.44",
 ]
 
+[[package]]
+name = "dotenv"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+
 [[package]]
 name = "dtoa"
 version = "0.4.8"
@@ -1793,18 +1847,6 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 
-[[package]]
-name = "fallible-iterator"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
-
-[[package]]
-name = "fallible-streaming-iterator"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
-
 [[package]]
 name = "fastrand"
 version = "1.5.0"
@@ -2002,6 +2044,17 @@ dependencies = [
  "futures-util",
 ]
 
+[[package]]
+name = "futures-intrusive"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e"
+dependencies = [
+ "futures-core",
+ "lock_api 0.4.5",
+ "parking_lot 0.11.2",
+]
+
 [[package]]
 name = "futures-io"
 version = "0.3.18"
@@ -2274,6 +2327,15 @@ dependencies = [
  "hashbrown 0.11.2",
 ]
 
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -2525,6 +2587,15 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "0.4.8"
@@ -2712,9 +2783,8 @@ dependencies = [
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.23.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2"
+version = "0.22.2"
+source = "git+https://github.com/rusqlite/rusqlite?rev=b612c6d7278f4243c2c66d30cc84d4f9eaae6e71#b612c6d7278f4243c2c66d30cc84d4f9eaae6e71"
 dependencies = [
  "cc",
  "pkg-config",
@@ -3892,21 +3962,6 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "rusqlite"
-version = "0.26.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a82b0b91fad72160c56bf8da7a549b25d7c31109f52cc1437eac4c0ad2550a7"
-dependencies = [
- "bitflags",
- "fallible-iterator",
- "fallible-streaming-iterator",
- "hashlink",
- "libsqlite3-sys",
- "memchr",
- "smallvec",
-]
-
 [[package]]
 name = "rust-argon2"
 version = "0.8.3"
@@ -4680,7 +4735,7 @@ dependencies = [
  "bytemuck",
  "curve25519-dalek 2.1.3",
  "hex",
- "itertools",
+ "itertools 0.9.0",
  "lazy_static",
  "libsecp256k1",
  "log",
@@ -4749,7 +4804,7 @@ dependencies = [
  "dir-diff",
  "flate2",
  "fnv",
- "itertools",
+ "itertools 0.9.0",
  "lazy_static",
  "libc",
  "libloading 0.6.7",
@@ -4808,7 +4863,7 @@ dependencies = [
  "generic-array 0.14.4",
  "hex",
  "hmac 0.10.1",
- "itertools",
+ "itertools 0.9.0",
  "lazy_static",
  "libsecp256k1",
  "log",
@@ -4985,6 +5040,98 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "sqlformat"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4"
+dependencies = [
+ "itertools 0.10.1",
+ "nom",
+ "unicode_categories",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43"
+dependencies = [
+ "sqlx-core",
+ "sqlx-macros",
+]
+
+[[package]]
+name = "sqlx-core"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1"
+dependencies = [
+ "ahash 0.7.6",
+ "atoi",
+ "bitflags",
+ "byteorder",
+ "bytes 1.1.0",
+ "crc",
+ "crossbeam-channel 0.5.1",
+ "crossbeam-queue 0.3.2",
+ "crossbeam-utils 0.8.5",
+ "either",
+ "futures-channel",
+ "futures-core",
+ "futures-intrusive",
+ "futures-util",
+ "hashlink",
+ "hex",
+ "indexmap",
+ "itoa",
+ "libc",
+ "libsqlite3-sys",
+ "log",
+ "memchr",
+ "once_cell",
+ "parking_lot 0.11.2",
+ "percent-encoding",
+ "sha2",
+ "smallvec",
+ "sqlformat",
+ "sqlx-rt",
+ "stringprep",
+ "thiserror",
+ "url",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-macros"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5"
+dependencies = [
+ "dotenv",
+ "either",
+ "heck",
+ "once_cell",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "sha2",
+ "sqlx-core",
+ "sqlx-rt",
+ "syn 1.0.82",
+ "url",
+]
+
+[[package]]
+name = "sqlx-rt"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d1bd069de53442e7a320f525a6d4deb8bb0621ac7a55f7eccbc2b58b57f43d0"
+dependencies = [
+ "async-native-tls 0.3.3",
+ "async-std",
+ "native-tls",
+]
+
 [[package]]
 name = "stable_deref_trait"
 version = "1.2.0"
@@ -4997,6 +5144,16 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
+[[package]]
+name = "stringprep"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
 [[package]]
 name = "strsim"
 version = "0.8.0"
@@ -5405,6 +5562,12 @@ dependencies = [
  "tinyvec",
 ]
 
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
 [[package]]
 name = "unicode-width"
 version = "0.1.9"
@@ -5423,6 +5586,12 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
+[[package]]
+name = "unicode_categories"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+
 [[package]]
 name = "untrusted"
 version = "0.7.1"
@@ -5661,6 +5830,16 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "whoami"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8"
+dependencies = [
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "winapi"
 version = "0.2.8"
@@ -5832,6 +6011,6 @@ checksum = "a1e6e8778706838f43f771d80d37787cb2fe06dafe89dd3aebaf6721b9eaec81"
 dependencies = [
  "cc",
  "glob",
- "itertools",
+ "itertools 0.9.0",
  "libc",
 ]

+ 6 - 1
Cargo.toml

@@ -81,7 +81,8 @@ async-tungstenite = "0.16.0"
 tungstenite = "0.16.0"
 
 # Used for wallet management.
-rusqlite = {version = "0.26.1", features = ["bundled-sqlcipher"]}
+sqlx = {version = "0.5.9", features = ["runtime-async-std-native-tls", "sqlite"]}
+libsqlite3-sys = {version = "0.22.0", features = ["bundled-sqlcipher"]}
 
 # Used for gatewayd network transport.
 zeromq = {version = "0.3.0", default-features = false, features = ["async-std-runtime", "all-transport"]}
@@ -105,3 +106,7 @@ spl-token = {version = "3.2.0", features = ["no-entrypoint"], optional = true}
 btc = ["bdk", "bitcoin", "secp256k1"]
 eth = ["keccak-hasher", "hash-db"]
 sol = ["solana-sdk", "solana-client", "spl-token", "spl-associated-token-account"]
+
+[patch.crates-io.libsqlite3-sys]
+git = "https://github.com/rusqlite/rusqlite"
+rev = "b612c6d7278f4243c2c66d30cc84d4f9eaae6e71"

+ 6 - 5
src/client.rs

@@ -109,7 +109,7 @@ impl Client {
 
         if clear_input {
             // TODO: FIXME:
-            let base_secret = self.main_keypair.private;
+            let base_secret = self.main_keypair.secret;
             let signature_secret = schnorr::SecretKey(mod_r_p(base_secret));
             let input = tx::TransactionBuilderClearInputInfo { value, token_id, signature_secret };
             clear_inputs.push(input);
@@ -138,7 +138,7 @@ impl Client {
                 };
 
                 inputs.push(input);
-                coins.push(own_coin.coin.clone());
+                coins.push(own_coin.coin);
             }
 
             if inputs_value < value {
@@ -209,7 +209,7 @@ impl Client {
         state: Arc<Mutex<State>>,
     ) -> ClientResult<()> {
         debug!("Start transfer {}", amount);
-        let token_id_exists = self.wallet.token_id_exists(&token_id).await?;
+        let token_id_exists = self.wallet.token_id_exists(token_id).await?;
 
         if token_id_exists {
             self.send(pubkey, amount, token_id, false, state).await?;
@@ -248,7 +248,7 @@ impl Client {
         debug!("Start subscriber for cashier");
         let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
 
-        let secret_key = self.main_keypair.private;
+        let secret_key = self.main_keypair.secret;
         let wallet = self.wallet.clone();
 
         //let task: smol::Task<Result<()>> = executor.spawn(async move {
@@ -289,7 +289,8 @@ impl Client {
         debug!("Start subscriber for darkfid");
         let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
 
-        let secret_key = self.main_keypair.private;
+        let secret_key = self.main_keypair.secret;
+
         let wallet = self.wallet.clone();
 
         let task: smol::Task<Result<()>> = executor.spawn(async move {

+ 5 - 5
src/error.rs

@@ -101,8 +101,8 @@ pub enum Error {
     /// Database/Sql errors
     #[error("Rocksdb error: `{0}`")]
     RocksdbError(String),
-    #[error("Rusqlite error: `{0}`")]
-    RusqliteError(String),
+    #[error("sqlx error: `{0}`")]
+    SqlxError(String),
     #[error("SlabsStore Error: `{0}`")]
     SlabsStore(String),
 
@@ -161,9 +161,9 @@ impl From<rocksdb::Error> for Error {
     }
 }
 
-impl From<rusqlite::Error> for Error {
-    fn from(err: rusqlite::Error) -> Error {
-        Error::RusqliteError(err.to_string())
+impl From<sqlx::error::Error> for Error {
+    fn from(err: sqlx::error::Error) -> Error {
+        Error::SqlxError(err.to_string())
     }
 }
 

+ 1 - 1
src/service/bridge.rs

@@ -166,7 +166,7 @@ impl Bridge {
                 Some(token_key) => {
                     let pub_key = client
                         .subscribe_with_keypair(
-                            token_key.private_key,
+                            token_key.secret_key,
                             token_key.public_key,
                             drk_pub_key,
                             mint_address,

+ 1 - 1
src/state.rs

@@ -161,7 +161,7 @@ impl State {
                     let nullifier = Nullifier::new(*secret, note.serial);
 
                     let own_coin = OwnCoin {
-                        coin: coin.clone(),
+                        coin,
                         note: note.clone(),
                         secret: *secret,
                         // witness: witness.clone(),

+ 199 - 238
src/wallet/cashierdb.rs

@@ -1,24 +1,22 @@
-use std::path::Path;
+use std::{path::Path, str::FromStr};
 
-use async_std::sync::{Arc, Mutex};
+use async_std::sync::Arc;
 use log::{debug, error, info};
 use pasta_curves::pallas;
-use rusqlite::{named_params, params, Connection};
+use sqlx::{
+    sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions},
+    Row, SqlitePool,
+};
 
 use super::{Keypair, WalletApi};
 use crate::{client::ClientFailed, types::*, util::NetworkName, Error, Result};
 
 pub type CashierDbPtr = Arc<CashierDb>;
 
-pub struct CashierDb {
-    pub conn: Mutex<Connection>,
-    pub initialized: Mutex<bool>,
-}
-
 #[derive(Debug, Clone)]
 pub struct TokenKey {
     pub public_key: Vec<u8>,
-    pub private_key: Vec<u8>,
+    pub secret_key: Vec<u8>,
 }
 
 pub struct WithdrawToken {
@@ -35,87 +33,97 @@ pub struct DepositToken {
     pub mint_address: String,
 }
 
+pub struct CashierDb {
+    pub conn: SqlitePool,
+}
+
 impl WalletApi for CashierDb {}
 
 impl CashierDb {
-    pub fn new(path: &Path, password: String) -> Result<CashierDbPtr> {
-        debug!(target: "CASHIERDB", "new() Constructor called");
+    pub async fn new(path: &Path, password: String) -> Result<CashierDbPtr> {
+        debug!("new() Constructor called");
         if password.trim().is_empty() {
-            error!(target: "CASHIERDB", "Password is empty. You must set a password to use the wallet.");
+            error!("Password is empty. You must set a password to use the wallet.");
             return Err(Error::from(ClientFailed::EmptyPassword))
         }
 
-        let conn = Connection::open(path)?;
-        conn.pragma_update(None, "key", &password)?;
-        info!(target: "CASHIERDB", "Opened connection at path: {:?}", path);
+        let p = format!("sqlite://{}", path.to_str().unwrap());
+
+        let connect_opts = SqliteConnectOptions::from_str(&p)?
+            .pragma("key", password)
+            .create_if_missing(true)
+            .journal_mode(SqliteJournalMode::Off);
 
-        Ok(Arc::new(Self { conn: Mutex::new(conn), initialized: Mutex::new(false) }))
+        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<()> {
-        if !*self.initialized.lock().await {
-            let contents = include_str!("../../sql/cashier.sql");
-            let conn = self.conn.lock().await;
-            conn.execute_batch(contents)?;
-            *self.initialized.lock().await = true;
-            return Ok(())
-        }
-
-        error!(target: "WALLETDB", "Wallet already initialized.");
-        Err(Error::from(ClientFailed::WalletInitialized))
+        let main_kps = include_str!("../../sql/cashier_main_keypairs.sql");
+        let deposit_kps = include_str!("../../sql/cashier_deposit_keypairs.sql");
+        let withdraw_kps = include_str!("../../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 put_main_keys(&self, token_key: &TokenKey, network: &NetworkName) -> Result<()> {
-        debug!(target: "CASHIERDB", "Put main keys");
+        debug!("Writing main keys into the database");
         let network = self.get_value_serialized(network)?;
 
-        let conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "INSERT INTO main_keypairs
-            (token_key_private, token_key_public, network)
+            (token_key_secret, token_key_public, network)
             VALUES
-            (:token_key_private, :token_key_public, :network)",
-            named_params! {
-                ":token_key_private": token_key.private_key,
-                ":token_key_public": token_key.public_key,
-                ":network": &network,
-            },
-        )?;
+            (?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!(target: "CASHIERDB", "Get main keys");
+        debug!("Returning main keypairs");
         let network = self.get_value_serialized(network)?;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT token_key_private, token_key_public
-            FROM main_keypairs
-            WHERE network = :network ;",
-        )?;
+        let mut conn = self.conn.acquire().await?;
 
-        let keys_iter = stmt
-            .query_map::<(Vec<u8>, Vec<u8>), _, _>(&[(":network", &network)], |row| {
-                Ok((row.get(0)?, row.get(1)?))
-            })?;
+        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 k in keys_iter {
-            let k = k?;
-            keys.push(TokenKey { private_key: k.0, public_key: k.1 });
+        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!(target: "CASHIERDB", "Remove withdraw and deposit keys");
-        let conn = self.conn.lock().await;
-        conn.execute("DROP TABLE deposit_keypairs;", [])?;
-        conn.execute("DROP TABLE withdraw_keypairs;", [])?;
+        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(())
     }
 
@@ -123,36 +131,36 @@ impl CashierDb {
         &self,
         token_key_public: &[u8],
         d_key_public: &pallas::Point,
-        d_key_private: &pallas::Scalar,
+        d_key_secret: &pallas::Scalar,
         network: &NetworkName,
         token_id: &DrkTokenId,
         mint_address: String,
     ) -> Result<()> {
-        debug!(target: "CASHIERDB", "Put withdraw keys");
-
-        let d_key_public = self.get_value_serialized(d_key_public)?;
-        let d_key_private = self.get_value_serialized(d_key_private)?;
+        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 conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "INSERT INTO withdraw_keypairs
-            (token_key_public, d_key_private, d_key_public, network,  token_id, mint_address, confirm)
+            (token_key_public, d_key_secret, d_key_public,
+             network, token_id, mint_address, confirm)
             VALUES
-            (:token_key_public, :d_key_private, :d_key_public,:network, :token_id, :mint_address, :confirm);",
-            named_params! {
-                ":token_key_public": token_key_public,
-                ":d_key_private": d_key_private,
-                ":d_key_public": d_key_public,
-                ":network": network,
-                ":token_id": token_id,
-                ":mint_address": mint_address,
-                ":confirm": confirm,
-            },
-        )?;
+            (?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(())
     }
@@ -160,100 +168,93 @@ impl CashierDb {
     pub async fn put_deposit_keys(
         &self,
         d_key_public: &DrkPublicKey,
-        token_key_private: &[u8],
+        token_key_secret: &[u8],
         token_key_public: &[u8],
         network: &NetworkName,
         token_id: &DrkTokenId,
         mint_address: String,
     ) -> Result<()> {
-        debug!(target: "CASHIERDB", "Put exchange keys");
-
+        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 conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "INSERT INTO deposit_keypairs
-            (d_key_public, token_key_private, token_key_public, network, token_id, mint_address, confirm)
+            (d_key_public, token_key_secret, token_key_public,
+             network, token_id, mint_address, confirm)
             VALUES
-            (:d_key_public, :token_key_private, :token_key_public, :network, :token_id, :mint_address, :confirm)",
-            named_params! {
-                ":d_key_public": &d_key_public,
-                ":token_key_private": token_key_private,
-                ":token_key_public": token_key_public,
-                ":network": &network,
-                ":token_id": &token_id,
-                ":mint_address": &mint_address,
-                ":confirm": &confirm,
-            },
-        )?;
+            (?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<DrkSecretKey>> {
-        debug!(target: "CASHIERDB", "Get withdraw private keys");
+        debug!("Getting withdraw private keys");
         let confirm = self.get_value_serialized(&false)?;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT d_key_private
-                FROM withdraw_keypairs
-                WHERE confirm = :confirm",
-        )?;
-
-        let keys = stmt.query_map(&[(":confirm", &confirm)], |row| Ok(row.get(0)))?;
-
-        let mut private_keys: Vec<DrkSecretKey> = vec![];
-
-        for k in keys {
-            let private_key: DrkSecretKey = self.get_value_deserialized(k??)?;
-            private_keys.push(private_key);
+        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 = self.get_value_deserialized(row.get("d_key_secret"))?;
+            secret_keys.push(key);
         }
 
-        Ok(private_keys)
+        Ok(secret_keys)
     }
 
     pub async fn get_withdraw_token_public_key_by_dkey_public(
         &self,
-        pub_key: &DrkPublicKey,
+        pubkey: &DrkPublicKey,
     ) -> Result<Option<WithdrawToken>> {
-        debug!(target: "CASHIERDB", "Get token address by pub_key");
-        let d_key_public = self.get_value_serialized(pub_key)?;
+        debug!("Get token address by pubkey");
+        let d_key_public = self.get_value_serialized(pubkey)?;
         let confirm = self.get_value_serialized(&false)?;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
+        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 = :d_key_public AND confirm = :confirm;",
-        )?;
-
-        let addr_iter = stmt
-            .query_map(&[(":d_key_public", &d_key_public), (":confirm", &confirm)], |row| {
-                Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
-            })?;
-
-        let mut token_addresses = vec![];
-
-        for addr in addr_iter {
-            let addr = addr?;
-            let token_public_key = addr.0;
-            let network: NetworkName = self.get_value_deserialized(addr.1)?;
-            let token_id: DrkTokenId = self.get_value_deserialized(addr.2)?;
-            let mint_address: String = self.get_value_deserialized(addr.3)?;
-            token_addresses.push(WithdrawToken {
-                token_public_key,
-                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_addresses.pop())
+        Ok(token_addrs.pop())
     }
 
     pub async fn get_deposit_token_keys_by_dkey_public(
@@ -261,71 +262,30 @@ impl CashierDb {
         d_key_public: &DrkPublicKey,
         network: &NetworkName,
     ) -> Result<Vec<TokenKey>> {
-        debug!(target: "CASHIERDB", "Check for existing dkey");
+        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 conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT token_key_private, token_key_public
-            FROM deposit_keypairs
-            WHERE d_key_public = :d_key_public
-            AND network = :network
-            AND confirm = :confirm ;",
-        )?;
-
-        let keys_iter = stmt.query_map::<(Vec<u8>, Vec<u8>), _, _>(
-            &[(":d_key_public", &d_key_public), (":network", &network), (":confirm", &confirm)],
-            |row| Ok((row.get(0)?, row.get(1)?)),
-        )?;
+        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 k in keys_iter {
-            let k = k?;
-            keys.push(TokenKey { private_key: k.0, public_key: k.1 });
-        }
-
-        Ok(keys)
-    }
-
-    pub async fn get_deposit_token_keys_by_network(
-        &self,
-        network: &NetworkName,
-    ) -> Result<Vec<DepositToken>> {
-        debug!(target: "CASHIERDB", "Check for existing dkey");
-        let network = self.get_value_serialized(network)?;
-        let confirm = self.get_value_serialized(&false)?;
-
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT d_key_public, token_key_private, token_key_public, token_id, mint_address
-            FROM deposit_keypairs
-            WHERE network = :network
-            AND confirm = :confirm ;",
-        )?;
-
-        let keys_iter = stmt
-            .query_map(&[(":network", &network), (":confirm", &confirm)], |row| {
-                Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
-            })?;
-
-        let mut keys = vec![];
-
-        for key in keys_iter {
-            let key = key?;
-            let drk_public_key: DrkPublicKey = self.get_value_deserialized(key.0)?;
-            let private_key = key.1;
-            let public_key = key.2;
-            let token_id: DrkTokenId = self.get_value_deserialized(key.3)?;
-            let mint_address: String = self.get_value_deserialized(key.4)?;
-            keys.push(DepositToken {
-                drk_public_key,
-                token_key: TokenKey { private_key, public_key },
-                token_id,
-                mint_address,
-            });
+        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)
@@ -336,35 +296,28 @@ impl CashierDb {
         token_key_public: &[u8],
         network: &NetworkName,
     ) -> Result<Option<Keypair>> {
-        debug!(target: "CASHIERDB", "Check for existing token address");
+        debug!("Checking for existing token address");
         let confirm = self.get_value_serialized(&false)?;
         let network = self.get_value_serialized(network)?;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT d_key_private, d_key_public FROM withdraw_keypairs
-                WHERE token_key_public = :token_key_public
-                AND network = :network
-                AND confirm = :confirm;",
-        )?;
-
-        let keypair_iter = stmt.query_map(
-            &[
-                (":token_key_public", &token_key_public),
-                (":network", &network.as_ref()),
-                (":confirm", &confirm.as_ref()),
-            ],
-            |row| Ok((row.get(0)?, row.get(1)?)),
-        )?;
-
-        let mut keypairs: Vec<Keypair> = vec![];
-
-        for kp in keypair_iter {
-            let kp = kp?;
-            let public: DrkPublicKey = self.get_value_deserialized(kp.1)?;
-            let private: DrkSecretKey = self.get_value_deserialized(kp.0)?;
-            let keypair = Keypair { public, private };
-            keypairs.push(keypair);
+        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())
@@ -375,18 +328,22 @@ impl CashierDb {
         token_address: &[u8],
         network: &NetworkName,
     ) -> Result<()> {
-        debug!(target: "CASHIERDB", "Confirm withdraw keys");
+        debug!("Confirm withdraw keys");
         let network = self.get_value_serialized(network)?;
         let confirm = self.get_value_serialized(&true)?;
 
-        let conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "UPDATE withdraw_keypairs
-            SET confirm = ?1
-            WHERE token_key_public = ?2
-            AND network = ?3;",
-            params![confirm, token_address, network],
-        )?;
+             SET confirm = ?1
+             WHERE token_key_public = ?2
+             AND network = ?3;",
+        )
+        .bind(confirm)
+        .bind(token_address)
+        .bind(network)
+        .execute(&mut conn)
+        .await?;
 
         Ok(())
     }
@@ -396,19 +353,23 @@ impl CashierDb {
         d_key_public: &DrkPublicKey,
         network: &NetworkName,
     ) -> Result<()> {
-        debug!(target: "CASHIERDB", "Confirm withdraw keys");
+        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 conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "UPDATE deposit_keypairs
-            SET confirm = ?1
-            WHERE d_key_public = ?2
-            AND network = ?3;",
-            params![confirm, d_key_public, network],
-        )?;
+             SET confirm = ?1
+             WHERE d_key_public = ?2
+             AND network = ?3;",
+        )
+        .bind(confirm)
+        .bind(d_key_public)
+        .bind(network)
+        .execute(&mut conn)
+        .await?;
 
         Ok(())
     }

+ 168 - 233
src/wallet/walletdb.rs

@@ -1,365 +1,300 @@
-use std::path::Path;
+use std::{path::Path, str::FromStr};
 
-use async_std::sync::{Arc, Mutex};
+use async_std::sync::Arc;
+use halo2::arithmetic::Field;
+use halo2_gadgets::ecc::FixedPoints;
 use log::{debug, error, info};
-use pasta_curves::arithmetic::Field;
+use pasta_curves::pallas;
 use rand::rngs::OsRng;
-use rusqlite::{named_params, params, Connection};
+use sqlx::{
+    sqlite::{SqliteConnectOptions, SqliteJournalMode},
+    Row, SqlitePool,
+};
 
-use super::WalletApi;
 use crate::{
     client::ClientFailed,
-    crypto::{coin::Coin, note::Note, nullifier::Nullifier, OwnCoin, OwnCoins},
-    serial,
-    types::*,
+    crypto::{
+        coin::Coin, constants::OrchardFixedBases, note::Note, nullifier::Nullifier, util::mod_r_p,
+        OwnCoin, OwnCoins,
+    },
+    serial::serialize,
+    wallet::WalletApi,
     Error, Result,
 };
 
 pub type WalletPtr = Arc<WalletDb>;
 
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug)]
 pub struct Keypair {
-    pub public: DrkPublicKey,
-    pub private: DrkSecretKey,
+    pub public: pallas::Point,
+    pub secret: pallas::Base,
 }
 
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug)]
 pub struct Balance {
-    pub token_id: DrkTokenId,
+    pub token_id: pallas::Base,
     pub value: u64,
     pub nullifier: Nullifier,
 }
 
-#[derive(Debug, Clone)]
+#[derive(Clone, Debug)]
 pub struct Balances {
     pub list: Vec<Balance>,
 }
-impl Balances {
-    pub fn add(&mut self, balance: &Balance) {
-        if let Some(mut saved_balance) =
-            self.list.iter_mut().find(|b| b.token_id == balance.token_id)
-        {
-            saved_balance.value += balance.value;
-        } else {
-            self.list.push(balance.clone());
-        }
-    }
-}
 
 pub struct WalletDb {
-    pub conn: Mutex<Connection>,
+    pub conn: SqlitePool,
 }
 
 impl WalletApi for WalletDb {}
 
 impl WalletDb {
-    pub fn new(path: &Path, password: String) -> Result<WalletPtr> {
-        debug!(target: "WALLETDB", "new() Constructor called");
+    pub async fn new(path: &Path, password: String) -> Result<WalletPtr> {
+        debug!("new() Constructor called");
         if password.trim().is_empty() {
-            error!(target: "WALLETDB", "Password is empty. You must set a password to use the wallet.");
+            error!("Password is empty. You must set a password to use the wallet.");
             return Err(Error::from(ClientFailed::EmptyPassword))
         }
 
-        let conn = Connection::open(path)?;
-        conn.pragma_update(None, "key", &password)?;
-        info!(target: "WALLETDB", "Opened connection at path: {:?}", path);
+        let p = format!("sqlite://{}", path.to_str().unwrap());
 
-        Ok(Arc::new(Self { conn: Mutex::new(conn) }))
+        let connect_opts = SqliteConnectOptions::from_str(&p)?
+            .pragma("key", password)
+            .create_if_missing(true)
+            .journal_mode(SqliteJournalMode::Off);
+
+        let conn = SqlitePool::connect_with(connect_opts).await?;
+
+        info!("Opened connection at path sqlite://{:?}", path);
+        Ok(Arc::new(WalletDb { conn }))
     }
 
     pub async fn init_db(&self) -> Result<()> {
-        debug!(target: "WALLETDB", "Initialize...");
-        let contents = include_str!("../../sql/schema.sql");
-        let conn = self.conn.lock().await;
-        Ok(conn.execute_batch(contents)?)
+        debug!("Initializing wallet database");
+        let keys = include_str!("../../sql/keys.sql");
+        let coins = include_str!("../../sql/coins.sql");
+        let mut conn = self.conn.acquire().await?;
+        debug!("Initializing keys table");
+        sqlx::query(keys).execute(&mut conn).await?;
+        debug!("Initializing coins table");
+        sqlx::query(coins).execute(&mut conn).await?;
+        Ok(())
     }
 
     pub async fn key_gen(&self) -> Result<()> {
-        debug!(target: "WALLETDB", "Attempting to generate keys...");
-        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).await?;
-            return Ok(())
+        debug!("Attempting to generate keypairs");
+        let mut conn = self.conn.acquire().await?;
+
+        // TODO: Think about multiple keys
+        match sqlx::query("SELECT * FROM keys WHERE key_id > ?").fetch_one(&mut conn).await {
+            Ok(_) => {
+                error!("Keys already exist");
+                Err(Error::from(ClientFailed::KeyExists))
+            }
+            Err(_) => {
+                let secret = pallas::Base::random(&mut OsRng);
+                let public = OrchardFixedBases::NullifierK.generator() * mod_r_p(secret);
+                self.put_keypair(&public, &secret).await?;
+                Ok(())
+            }
         }
-
-        error!(target: "WALLETDB", "Keys already exist.");
-        Err(Error::from(ClientFailed::KeyExists))
     }
 
-    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);
-
-        let conn = self.conn.lock().await;
-        conn.execute(
-            "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
-            params![key_public, key_private],
-        )?;
+    pub async fn put_keypair(&self, public: &pallas::Point, secret: &pallas::Base) -> Result<()> {
+        debug!("Writing keypair into the wallet database");
+        let p = serialize(public);
+        let s = serialize(secret);
+
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query("INSERT INTO keys(public, secret) VALUES (?1, ?2)")
+            .bind(p)
+            .bind(s)
+            .execute(&mut conn)
+            .await?;
 
         Ok(())
     }
 
     pub async fn get_keypairs(&self) -> Result<Vec<Keypair>> {
-        debug!(target: "WALLETDB", "Returning keypairs...");
-        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)?)))?;
-        let mut keypairs = Vec::new();
-
-        for key in key_iter {
-            let key = key?;
-            let public = key.0;
-            let private = key.1;
-            let public: DrkPublicKey = self.get_value_deserialized(public)?;
-            let private: DrkSecretKey = self.get_value_deserialized(private)?;
-            keypairs.push(Keypair { public, private });
-        }
+        debug!("Returning keypairs");
+        let mut conn = self.conn.acquire().await?;
 
-        Ok(keypairs)
+        // TODO: Think about multiple keys
+        let row = sqlx::query("SELECT * FROM keys").fetch_one(&mut conn).await?;
+        let public: pallas::Point = self.get_value_deserialized(row.get("public"))?;
+        let secret: pallas::Base = self.get_value_deserialized(row.get("secret"))?;
+
+        Ok(vec![Keypair { public, secret }])
     }
 
     pub async fn get_own_coins(&self) -> Result<OwnCoins> {
-        debug!(target: "WALLETDB", "Get own coins");
+        debug!("Finding own coins");
         let is_spent = 0;
 
-        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((
-                row.get(0)?,
-                row.get(1)?,
-                row.get(2)?,
-                row.get(3)?,
-                row.get(4)?,
-                row.get(5)?,
-                // TODO: row.get(6)?,
-                row.get(7)?,
-                row.get(9)?,
-            ))
-        })?;
-
-        let mut own_coins = Vec::new();
+        let mut conn = self.conn.acquire().await?;
+        let rows = sqlx::query("SELECT * FROM coins WHERE is_spent = ?1;")
+            .bind(is_spent)
+            .fetch_all(&mut conn)
+            .await?;
 
+        let mut own_coins = vec![];
         for row in rows {
-            let row = row?;
-            let coin = self.get_value_deserialized(row.0)?;
+            let coin = self.get_value_deserialized(row.get("coin"))?;
 
-            // note
-            let serial = self.get_value_deserialized(row.1)?;
-            let coin_blind = self.get_value_deserialized(row.2)?;
-            let value_blind = self.get_value_deserialized(row.3)?;
-            let value: u64 = row.4;
-            let token_id = self.get_value_deserialized(row.5)?;
+            // Note
+            let serial = self.get_value_deserialized(row.get("serial"))?;
+            let coin_blind = self.get_value_deserialized(row.get("coin_blind"))?;
+            let value_blind = self.get_value_deserialized(row.get("valcom_blind"))?;
+            // TODO: FIXME:
+            let value_bytes: Vec<u8> = row.get("value");
+            let value = u64::from_le_bytes(value_bytes.try_into().unwrap());
+            let token_id = self.get_value_deserialized(row.get("token_id"))?;
 
             let note = Note { serial, value, token_id, coin_blind, value_blind };
 
             // TODO:
-            // let witness = self.get_value_deserialized(row.6)?;
-            // let secret: DrkSecretKey = self.get_value_deserialized(row.7)?;
-            // let nullifier: Nullifier = self.get_value_deserialized(row.8)?;
-            let secret: DrkSecretKey = self.get_value_deserialized(row.6)?;
-            let nullifier: Nullifier = self.get_value_deserialized(row.7)?;
+            // let witness = deserialized(row.6)
+            let secret = self.get_value_deserialized(row.get("secret"))?;
+            let nullifier = self.get_value_deserialized(row.get("nullifier"))?;
 
             let oc = OwnCoin {
                 coin,
                 note,
                 secret,
-                // TODO: witness,
+                // witness,
                 nullifier,
             };
 
-            own_coins.push(oc)
+            own_coins.push(oc);
         }
 
         Ok(own_coins)
     }
 
     pub async fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
-        debug!(target: "WALLETDB", "Put own coins");
+        debug!("Putting own coin into wallet database");
         let coin = self.get_value_serialized(&own_coin.coin.to_bytes())?;
         let serial = self.get_value_serialized(&own_coin.note.serial)?;
         let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
         let value_blind = self.get_value_serialized(&own_coin.note.value_blind)?;
-        let value: u64 = own_coin.note.value;
+        let value = own_coin.note.value.to_le_bytes();
         let token_id = self.get_value_serialized(&own_coin.note.token_id)?;
-        // TODO: let witness = self.get_value_serialized(&own_coin.witness)?;
+        // TODO: let witness
         let secret = self.get_value_serialized(&own_coin.secret)?;
         let is_spent = 0;
         let nullifier = self.get_value_serialized(&own_coin.nullifier)?;
 
-        let conn = self.conn.lock().await;
-        conn.execute(
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query(
             "INSERT OR REPLACE INTO coins
             (coin, serial, value, token_id, coin_blind,
-            valcom_blind, witness, secret, is_spent, nullifier)
+             valcom_blind, secret, is_spent, nullifier)
             VALUES
-            (:coin, :serial, :value, :token_id, :coin_blind,
-             :valcom_blind, :witness, :secret, :is_spent, :nullifier);",
-            named_params! {
-                ":coin": coin,
-                ":serial": serial,
-                ":value": value,
-                ":token_id": token_id,
-                ":coin_blind": coin_blind,
-                ":valcom_blind": value_blind,
-                // TODO: ":witness": witness,
-                ":secret": secret,
-                ":is_spent": is_spent,
-                ":nullifier": nullifier,
-            },
-        )?;
+             (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9);",
+        )
+        .bind(coin)
+        .bind(serial)
+        .bind(value.to_vec())
+        .bind(token_id)
+        .bind(coin_blind)
+        .bind(value_blind)
+        .bind(secret)
+        .bind(is_spent)
+        .bind(nullifier)
+        .execute(&mut conn)
+        .await?;
 
         Ok(())
     }
 
     pub async fn remove_own_coins(&self) -> Result<()> {
-        debug!(target: "WALLETDB", "Remove own coins");
-        let conn = self.conn.lock().await;
-        let _rows = conn.execute("DROP TABLE coins;", [])?;
+        debug!("Removing own coins from wallet database");
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query("DROP TABLE coins;").execute(&mut conn).await?;
         Ok(())
     }
 
     pub async fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
-        debug!(target: "WALLETDB", "Confirm spend coin");
+        debug!("Confirm spend coin");
         let is_spent = 1;
         let coin = self.get_value_serialized(coin)?;
 
-        let conn = self.conn.lock().await;
-        conn.execute(
-            "UPDATE coins
-            SET is_spent = ?1
-            WHERE coin = ?2 ;",
-            params![is_spent, coin],
-        )?;
+        let mut conn = self.conn.acquire().await?;
+        sqlx::query("UPDATE coins SET is_spent = ?1 WHERE coin = ?2;")
+            .bind(is_spent)
+            .bind(coin)
+            .execute(&mut conn)
+            .await?;
 
         Ok(())
     }
 
-    /* TODO:
-    pub fn get_witnesses(&self) -> Result<HashMap<Vec<u8>, IncrementalWitness<MerkleNode>>> {
-        let conn = Connection::open(&self.path)?;
-        conn.pragma_update(None, "key", &self.password)?;
-
-        let is_spent = 0;
-
-        let mut witnesses =
-            conn.prepare("SELECT coin, witness FROM coins WHERE is_spent = :is_spent;")?;
-
-        let rows = witnesses.query_map(&[(":is_spent", &is_spent)], |row| {
-            Ok((row.get(0)?, row.get(1)?))
-        })?;
-
-        let mut witnesses = HashMap::new();
-        for i in rows {
-            let i = i?;
-            let coin: Vec<u8> = i.0;
-            let witness: IncrementalWitness<MerkleNode> = self.get_value_deserialized(i.1)?;
-            witnesses.insert(coin, witness);
-        }
-
-        Ok(witnesses)
-    }
-
-    pub fn update_witnesses(
-        &self,
-        witnesses: HashMap<Vec<u8>, IncrementalWitness<MerkleNode>>,
-    ) -> Result<()> {
-        debug!(target: "WALLETDB", "Updating witness");
-
-        let conn = Connection::open(&self.path)?;
-        conn.pragma_update(None, "key", &self.password)?;
-
-        for (coin, witness) in witnesses.iter() {
-            let witness = self.get_value_serialized(witness)?;
-            let is_spent = 0;
-
-            conn.execute(
-                "UPDATE coins SET witness = ?1  WHERE coin = ?2 AND is_spent = ?3",
-                params![witness, coin, is_spent],
-            )?;
-        }
-
-        Ok(())
-    }
-    */
-
     pub async fn get_balances(&self) -> Result<Balances> {
-        debug!(target: "WALLETDB", "Get token and balances...");
+        debug!("Getting tokens and balances");
         let is_spent = 0;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare(
-            "SELECT value, token_id, nullifier FROM coins  WHERE is_spent = :is_spent ;",
-        )?;
-
-        let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| {
-            Ok((row.get(0)?, row.get(1)?, row.get(2)?))
-        })?;
-
-        let mut balances = Balances { list: Vec::new() };
+        let mut conn = self.conn.acquire().await?;
+        let rows = sqlx::query("SELECT value, token_id, nullifier FROM coins WHERE is_spent = ?1;")
+            .bind(is_spent)
+            .fetch_all(&mut conn)
+            .await?;
 
+        let mut list = vec![];
         for row in rows {
-            let row = row?;
-            let value: u64 = row.0;
-            let token_id: DrkTokenId = self.get_value_deserialized(row.1)?;
-            let nullifier: Nullifier = self.get_value_deserialized(row.2)?;
-            balances.add(&Balance { token_id, value, nullifier });
+            // TODO: FIXME:
+            let value_bytes: Vec<u8> = row.get("value");
+            let value = u64::from_le_bytes(value_bytes.try_into().unwrap());
+            let token_id = self.get_value_deserialized(row.get("token_id"))?;
+            let nullifier = self.get_value_deserialized(row.get("nullifier"))?;
+            list.push(Balance { token_id, value, nullifier });
         }
 
-        Ok(balances)
+        if list.is_empty() {
+            debug!("Did not find any unspent coins");
+        }
+
+        Ok(Balances { list })
     }
 
-    pub async fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
-        debug!(target: "WALLETDB", "Get token ID...");
+    pub async fn get_token_id(&self) -> Result<Vec<pallas::Base>> {
+        debug!("Getting token ID");
         let is_spent = 0;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
+        let mut conn = self.conn.acquire().await?;
+        let rows = sqlx::query("SELECT token_id FROM coins WHERE is_spent = ?1;")
+            .bind(is_spent)
+            .fetch_all(&mut conn)
+            .await?;
 
-        let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| row.get(0))?;
-
-        let mut token_ids = Vec::new();
+        let mut token_ids = vec![];
         for row in rows {
-            let row = row?;
-            let token_id = self.get_value_deserialized(row).unwrap();
-
+            let token_id = self.get_value_deserialized(row.get("token_id"))?;
             token_ids.push(token_id);
         }
 
         Ok(token_ids)
     }
 
-    pub async fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
-        debug!(target: "WALLETDB", "Check tokenID exists");
+    pub async fn token_id_exists(&self, token_id: pallas::Base) -> Result<bool> {
+        debug!("Checking if token ID exists");
         let is_spent = 0;
-        let id = self.get_value_serialized(token_id)?;
+        let id = self.get_value_serialized(&token_id)?;
 
-        let conn = self.conn.lock().await;
-        let mut stmt = conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
+        let mut conn = self.conn.acquire().await?;
 
-        let id_check = stmt.exists(params![id, is_spent])?;
+        let id_check = sqlx::query("SELECT * FROM coins WHERE token_id = ?1 AND is_spent = ?2;")
+            .bind(id)
+            .bind(is_spent)
+            .fetch_optional(&mut conn)
+            .await?;
 
-        Ok(id_check)
+        Ok(id_check.is_some())
     }
 
     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([])?;
+        debug!("Testing wallet");
+        let mut conn = self.conn.acquire().await?;
+        let _row = sqlx::query("SELECT * FROM keys").fetch_one(&mut conn).await?;
         Ok(())
     }
 }