Sfoglia il codice sorgente

drk: replaced rustqlite with turso as the sqlite database backend

skoupidi 1 mese fa
parent
commit
7ce522c0d7

+ 1 - 6
bin/drk/Cargo.toml

@@ -35,6 +35,7 @@ rodio = {version = "0.21.1", default-features = false, features = ["playback", "
 sled-overlay = "0.1.20"
 toml = "0.9.8"
 tracing = "0.1.44"
+turso = "0.6.1"
 url = "2.5.8"
 
 # Daemon
@@ -50,11 +51,5 @@ serde = {version = "1.0.228", features = ["derive"]}
 structopt = "0.3.26"
 structopt-toml = "0.5.1"
 
-[target.'cfg(not(target_os = "android"))'.dependencies]
-rusqlite = {version = "0.37.0", features = ["sqlcipher"]}
-
-[target.'cfg(target_os = "android")'.dependencies]
-rusqlite = {version = "0.37.0", features = ["bundled-sqlcipher-vendored-openssl"]}
-
 [lints]
 workspace = true

+ 76 - 65
bin/drk/src/dao.rs

@@ -21,7 +21,6 @@ use std::{collections::HashMap, fmt, str::FromStr};
 use lazy_static::lazy_static;
 use num_bigint::BigUint;
 use rand::rngs::OsRng;
-use rusqlite::types::Value;
 
 use darkfi::{
     tx::{ContractCallLeaf, Transaction, TransactionBuilder},
@@ -81,7 +80,9 @@ use crate::{
     convert_named_params,
     error::{WalletDbError, WalletDbResult},
     money::BALANCE_BASE10_DECIMALS,
+    params,
     rpc::ScanCache,
+    walletdb::Value,
     Drk,
 };
 
@@ -922,7 +923,7 @@ impl Drk {
     pub async fn initialize_dao(&self) -> WalletDbResult<()> {
         // Initialize DAO wallet schema
         let wallet_schema = include_str!("../dao.sql");
-        self.wallet.exec_batch_sql(wallet_schema)?;
+        self.wallet.exec_batch_sql(wallet_schema).await?;
 
         Ok(())
     }
@@ -1004,7 +1005,7 @@ impl Drk {
 
     /// Fetch all known DAOs from the wallet.
     pub async fn get_daos(&self) -> Result<Vec<DaoRecord>> {
-        let rows = match self.wallet.query_multiple(&DAO_DAOS_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&DAO_DAOS_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!("[get_daos] DAOs retrieval failed: {e}")))
@@ -1159,7 +1160,7 @@ impl Drk {
             &DAO_PROPOSALS_TABLE,
             &[],
             convert_named_params! {(DAO_PROPOSALS_COL_DAO_BULLA, serialize_async(&dao.bulla()).await)},
-        ) {
+        ).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -1399,7 +1400,8 @@ impl Drk {
         // Execute the query
         if let Err(e) = self
             .wallet
-            .exec_sql(&query, rusqlite::params![Some(*exec_height), Some(serialize(tx_hash)), key])
+            .exec_sql(&query, params![Some(*exec_height), Some(serialize(tx_hash)), key])
+            .await
         {
             return Err(Error::DatabaseError(format!(
                 "[apply_dao_exec_data] Update DAO proposal failed: {e}"
@@ -1486,16 +1488,16 @@ impl Drk {
         );
 
         // Create its params
-        let params = rusqlite::params![
+        let params = params![
             serialize(leaf_position),
             Some(*mint_height),
             serialize(tx_hash),
-            call_index,
+            *call_index,
             key,
         ];
 
         // Execute the query
-        self.wallet.exec_sql(&query, params)
+        self.wallet.exec_sql(&query, params).await
     }
 
     /// Import given DAO proposal into the wallet.
@@ -1531,10 +1533,7 @@ impl Drk {
         );
 
         // Create its params
-        let data = match &proposal.data {
-            Some(data) => Some(data),
-            None => None,
-        };
+        let data = proposal.data.clone();
 
         let leaf_position = match &proposal.leaf_position {
             Some(leaf_position) => Some(serialize_async(leaf_position).await),
@@ -1561,7 +1560,7 @@ impl Drk {
             None => None,
         };
 
-        let params = rusqlite::params![
+        let params = params![
             key,
             serialize(&proposal.proposal.dao_bulla),
             serialize(&proposal.proposal),
@@ -1577,7 +1576,7 @@ impl Drk {
         ];
 
         // Execute the query
-        if let Err(e) = self.wallet.exec_sql(&query, params) {
+        if let Err(e) = self.wallet.exec_sql(&query, params).await {
             return Err(Error::DatabaseError(format!(
                 "[put_dao_proposal] Proposal insert failed: {e}"
             )))
@@ -1604,9 +1603,9 @@ impl Drk {
         );
 
         // Create its params
-        let params = rusqlite::params![
+        let params = params![
             serialize(&vote.proposal),
-            vote.vote_option as u64,
+            vote.vote_option as u8,
             serialize(&vote.yes_vote_blind),
             serialize(&vote.all_vote_value),
             serialize(&vote.all_vote_blind),
@@ -1617,7 +1616,7 @@ impl Drk {
         ];
 
         // Execute the query
-        self.wallet.exec_sql(&query, params)?;
+        self.wallet.exec_sql(&query, params).await?;
 
         Ok(())
     }
@@ -1640,7 +1639,7 @@ impl Drk {
     }
 
     /// Reset confirmed DAOs in the wallet.
-    pub fn reset_daos(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_daos(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting DAO confirmations"));
         let query = format!(
             "UPDATE {} SET {} = NULL, {} = NULL, {} = NULL, {} = NULL;",
@@ -1650,7 +1649,7 @@ impl Drk {
             DAO_DAOS_COL_TX_HASH,
             DAO_DAOS_COL_CALL_INDEX,
         );
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully unconfirmed DAOs"));
 
         Ok(())
@@ -1658,7 +1657,7 @@ impl Drk {
 
     /// Reset confirmed DAOs in the wallet that were minted after
     /// provided height.
-    pub fn unconfirm_daos_after(
+    pub async fn unconfirm_daos_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1673,14 +1672,14 @@ impl Drk {
             DAO_DAOS_COL_CALL_INDEX,
             DAO_DAOS_COL_MINT_HEIGHT,
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully unconfirmed DAOs"));
 
         Ok(())
     }
 
     /// Reset all DAO proposals in the wallet.
-    pub fn reset_dao_proposals(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_dao_proposals(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting DAO proposals confirmations"));
         let query = format!(
             "UPDATE {} SET {} = NULL, {} = NULL, {} = NULL, {} = NULL, {} = NULL, {} = NULL, {} = NULL, {} = NULL;",
@@ -1694,7 +1693,7 @@ impl Drk {
             DAO_PROPOSALS_COL_EXEC_HEIGHT,
             DAO_PROPOSALS_COL_EXEC_TX_HASH,
         );
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully unconfirmed DAO proposals"));
 
         Ok(())
@@ -1702,7 +1701,7 @@ impl Drk {
 
     /// Reset DAO proposals in the wallet that were minted after
     /// provided height.
-    pub fn unconfirm_dao_proposals_after(
+    pub async fn unconfirm_dao_proposals_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1721,7 +1720,7 @@ impl Drk {
             DAO_PROPOSALS_COL_EXEC_TX_HASH,
             DAO_PROPOSALS_COL_MINT_HEIGHT,
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully unconfirmed DAO proposals"));
 
         Ok(())
@@ -1729,7 +1728,7 @@ impl Drk {
 
     /// Reset execution information in the wallet for DAO proposals
     /// that were executed after provided height.
-    pub fn unexec_dao_proposals_after(
+    pub async fn unexec_dao_proposals_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1742,17 +1741,17 @@ impl Drk {
             DAO_PROPOSALS_COL_EXEC_TX_HASH,
             DAO_PROPOSALS_COL_EXEC_HEIGHT,
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully reset DAO proposals execution information"));
 
         Ok(())
     }
 
     /// Reset all DAO votes in the wallet.
-    pub fn reset_dao_votes(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_dao_votes(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting DAO votes"));
         let query = format!("DELETE FROM {};", *DAO_VOTES_TABLE);
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully reset DAO votes"));
 
         Ok(())
@@ -1760,7 +1759,7 @@ impl Drk {
 
     /// Remove the DAO votes in the wallet that were created after
     /// provided height.
-    pub fn remove_dao_votes_after(
+    pub async fn remove_dao_votes_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1768,7 +1767,7 @@ impl Drk {
         output.push(format!("Removing DAO votes after: {height}"));
         let query =
             format!("DELETE FROM {} WHERE {} > ?1;", *DAO_VOTES_TABLE, DAO_VOTES_COL_BLOCK_HEIGHT);
-        self.wallet.exec_sql(&query, rusqlite::params![height])?;
+        self.wallet.exec_sql(&query, params![*height]).await?;
         output.push(String::from("Successfully removed DAO votes"));
 
         Ok(())
@@ -1792,14 +1791,14 @@ impl Drk {
                 "UPDATE {} SET {} = ?1, {} = ?2 WHERE {} = ?3;",
                 *DAO_DAOS_TABLE, DAO_DAOS_COL_NAME, DAO_DAOS_COL_PARAMS, DAO_DAOS_COL_BULLA
             );
-            if let Err(e) = self.wallet.exec_sql(
-                &query,
-                rusqlite::params![
-                    name,
-                    serialize_async(params).await,
-                    serialize_async(&bulla).await
-                ],
-            ) {
+            if let Err(e) = self
+                .wallet
+                .exec_sql(
+                    &query,
+                    params![name, serialize_async(params).await, serialize_async(&bulla).await],
+                )
+                .await
+            {
                 return Err(Error::DatabaseError(format!("[import_dao] DAO update failed: {e}")))
             };
             return Ok(())
@@ -1811,14 +1810,18 @@ impl Drk {
             "INSERT INTO {} ({}, {}, {}) VALUES (?1, ?2, ?3);",
             *DAO_DAOS_TABLE, DAO_DAOS_COL_BULLA, DAO_DAOS_COL_NAME, DAO_DAOS_COL_PARAMS
         );
-        if let Err(e) = self.wallet.exec_sql(
-            &query,
-            rusqlite::params![
-                serialize_async(&params.dao.to_bulla()).await,
-                name,
-                serialize_async(params).await
-            ],
-        ) {
+        if let Err(e) = self
+            .wallet
+            .exec_sql(
+                &query,
+                params![
+                    serialize_async(&params.dao.to_bulla()).await,
+                    name,
+                    serialize_async(params).await
+                ],
+            )
+            .await
+        {
             return Err(Error::DatabaseError(format!("[import_dao] DAO insert failed: {e}")))
         };
 
@@ -1829,7 +1832,7 @@ impl Drk {
     pub async fn remove_dao(&self, name: &str, output: &mut Vec<String>) -> Result<()> {
         output.push(format!("Removing \"{name}\" DAO from the wallet"));
         let query = format!("DELETE FROM {} WHERE {} = ?1;", *DAO_DAOS_TABLE, DAO_DAOS_COL_NAME);
-        if let Err(e) = self.wallet.exec_sql(&query, rusqlite::params![name]) {
+        if let Err(e) = self.wallet.exec_sql(&query, params![name]).await {
             return Err(Error::DatabaseError(format!("[remove_dao] DAO removal failed: {e}")))
         };
         output.push(String::from("Successfully removed DAO"));
@@ -1839,11 +1842,15 @@ impl Drk {
 
     /// Fetch a DAO given its bulla.
     pub async fn get_dao_by_bulla(&self, bulla: &DaoBulla) -> Result<DaoRecord> {
-        let row = match self.wallet.query_single(
-            &DAO_DAOS_TABLE,
-            &[],
-            convert_named_params! {(DAO_DAOS_COL_BULLA, serialize_async(bulla).await)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &DAO_DAOS_TABLE,
+                &[],
+                convert_named_params! {(DAO_DAOS_COL_BULLA, serialize_async(bulla).await)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -1857,11 +1864,11 @@ impl Drk {
 
     /// Fetch a DAO given its name.
     pub async fn get_dao_by_name(&self, name: &str) -> Result<DaoRecord> {
-        let row = match self.wallet.query_single(
-            &DAO_DAOS_TABLE,
-            &[],
-            convert_named_params! {(DAO_DAOS_COL_NAME, name)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(&DAO_DAOS_TABLE, &[], convert_named_params! {(DAO_DAOS_COL_NAME, name)})
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -1943,7 +1950,7 @@ impl Drk {
 
     /// Fetch all known DAO proposalss from the wallet.
     pub async fn get_proposals(&self) -> Result<Vec<ProposalRecord>> {
-        let rows = match self.wallet.query_multiple(&DAO_PROPOSALS_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&DAO_PROPOSALS_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -1966,11 +1973,15 @@ impl Drk {
         bulla: &DaoProposalBulla,
     ) -> Result<ProposalRecord> {
         // Grab the proposal record
-        let row = match self.wallet.query_single(
-            &DAO_PROPOSALS_TABLE,
-            &[],
-            convert_named_params! {(DAO_PROPOSALS_COL_BULLA, serialize_async(bulla).await)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &DAO_PROPOSALS_TABLE,
+                &[],
+                convert_named_params! {(DAO_PROPOSALS_COL_BULLA, serialize_async(bulla).await)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -1992,7 +2003,7 @@ impl Drk {
             &DAO_VOTES_TABLE,
             &[],
             convert_named_params! {(DAO_VOTES_COL_PROPOSAL_BULLA, serialize_async(proposal).await)},
-        ) {
+        ).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(

+ 77 - 63
bin/drk/src/deploy.rs

@@ -42,9 +42,10 @@ use darkfi_sdk::{
     ContractCall,
 };
 use darkfi_serial::{deserialize_async, serialize, serialize_async, AsyncEncodable};
-use rusqlite::types::Value;
 
-use crate::{convert_named_params, error::WalletDbResult, rpc::ScanCache, Drk};
+use crate::{
+    convert_named_params, error::WalletDbResult, params, rpc::ScanCache, walletdb::Value, Drk,
+};
 
 // Wallet SQL table constant names. These have to represent the `wallet.sql`
 // SQL schema. Table names are prefixed with the contract ID to avoid collisions.
@@ -71,10 +72,10 @@ pub const DEPLOY_HISTORY_COL_DEPLOY_IX: &str = "deploy_ix";
 
 impl Drk {
     /// Initialize wallet with tables for the Deployooor contract.
-    pub fn initialize_deployooor(&self) -> WalletDbResult<()> {
+    pub async fn initialize_deployooor(&self) -> WalletDbResult<()> {
         // Initialize Deployooor wallet schema
         let wallet_schema = include_str!("../deploy.sql");
-        self.wallet.exec_batch_sql(wallet_schema)?;
+        self.wallet.exec_batch_sql(wallet_schema).await?;
 
         Ok(())
     }
@@ -95,15 +96,17 @@ impl Drk {
             DEPLOY_AUTH_COL_IS_LOCKED,
             DEPLOY_AUTH_COL_LOCK_HEIGHT,
         );
-        self.wallet.exec_sql(
-            &query,
-            rusqlite::params![
-                serialize_async(&contract_id).await,
-                serialize_async(&secret_key).await,
-                0,
-                lock_height
-            ],
-        )?;
+        self.wallet
+            .exec_sql(
+                &query,
+                params![
+                    serialize_async(&contract_id).await,
+                    serialize_async(&secret_key).await,
+                    0,
+                    lock_height
+                ],
+            )
+            .await?;
 
         output.push(String::from("Created new contract deploy authority"));
         output.push(format!("Contract ID: {contract_id}"));
@@ -112,7 +115,7 @@ impl Drk {
     }
 
     /// Insert a deploy authority history record into the wallet.
-    pub fn put_deploy_history_record(
+    pub async fn put_deploy_history_record(
         &self,
         tx_hash: &TransactionHash,
         contract: &ContractId,
@@ -131,29 +134,31 @@ impl Drk {
             DEPLOY_HISTORY_COL_WASM_BINCODE,
             DEPLOY_HISTORY_COL_DEPLOY_IX,
         );
-        self.wallet.exec_sql(
-            &query,
-            rusqlite::params![
-                tx_hash.to_string(),
-                serialize(contract),
-                tx_type,
-                block_height,
-                serialize(wasm_bincode),
-                serialize(deploy_ix),
-            ],
-        )?;
+        self.wallet
+            .exec_sql(
+                &query,
+                params![
+                    tx_hash.to_string(),
+                    serialize(contract),
+                    tx_type,
+                    *block_height,
+                    serialize(wasm_bincode),
+                    serialize(deploy_ix),
+                ],
+            )
+            .await?;
 
         Ok(())
     }
 
     /// Reset all contract deploy authorities locked status in the wallet.
-    pub fn reset_deploy_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_deploy_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting deploy authorities locked status"));
         let query = format!(
             "UPDATE {} SET {} = 0, {} = NULL;",
             *DEPLOY_AUTH_TABLE, DEPLOY_AUTH_COL_IS_LOCKED, DEPLOY_AUTH_COL_LOCK_HEIGHT
         );
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully reset deploy authorities locked status"));
 
         Ok(())
@@ -161,7 +166,7 @@ impl Drk {
 
     /// Remove deploy authorities locked status in the wallet that
     /// where locked after provided height.
-    pub fn unlock_deploy_authorities_after(
+    pub async fn unlock_deploy_authorities_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -174,17 +179,17 @@ impl Drk {
             DEPLOY_AUTH_COL_LOCK_HEIGHT,
             DEPLOY_AUTH_COL_LOCK_HEIGHT
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully reset deploy authorities locked status"));
 
         Ok(())
     }
 
     /// Reset all contracts history records in the wallet.
-    pub fn reset_deploy_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_deploy_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting deployment history"));
         let query = format!("DELETE FROM {};", *DEPLOY_HISTORY_TABLE);
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully deployment history"));
 
         Ok(())
@@ -192,7 +197,7 @@ impl Drk {
 
     /// Remove the contracts history records in the wallet that were
     /// created after provided height.
-    pub fn remove_deploy_history_after(
+    pub async fn remove_deploy_history_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -202,7 +207,7 @@ impl Drk {
             "DELETE FROM {} WHERE {} > ?1;",
             *DEPLOY_HISTORY_TABLE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT
         );
-        self.wallet.exec_sql(&query, rusqlite::params![height])?;
+        self.wallet.exec_sql(&query, params![*height]).await?;
         output.push(String::from("Successfully removed deployment history records"));
 
         Ok(())
@@ -212,7 +217,7 @@ impl Drk {
     pub async fn list_deploy_auth(
         &self,
     ) -> Result<Vec<(ContractId, SecretKey, bool, Option<u32>)>> {
-        let rows = match self.wallet.query_multiple(&DEPLOY_AUTH_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&DEPLOY_AUTH_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -270,7 +275,7 @@ impl Drk {
             &DEPLOY_AUTH_TABLE,
             &[DEPLOY_AUTH_COL_SECRET_KEY, DEPLOY_AUTH_COL_IS_LOCKED],
             convert_named_params! {(DEPLOY_AUTH_COL_CONTRACT_ID, serialize_async(contract_id).await)},
-        ) {
+        ).await {
             Ok(v) => v,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -297,8 +302,8 @@ impl Drk {
         let rows = match self.wallet.query_multiple(
             &DEPLOY_AUTH_TABLE,
             &[DEPLOY_AUTH_COL_SECRET_KEY],
-            &[],
-        ) {
+            vec![],
+        ).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -331,7 +336,7 @@ impl Drk {
             &DEPLOY_HISTORY_TABLE,
             &[DEPLOY_HISTORY_COL_TX_HASH, DEPLOY_HISTORY_COL_TYPE, DEPLOY_HISTORY_COL_BLOCK_HEIGHT],
             convert_named_params! {(DEPLOY_HISTORY_COL_CONTRACT, serialize_async(contract_id).await)},
-        ) {
+        ).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -375,11 +380,15 @@ impl Drk {
         &self,
         tx_hash: &str,
     ) -> Result<(Option<Vec<u8>>, Option<Vec<u8>>)> {
-        let row = match self.wallet.query_single(
-            &DEPLOY_HISTORY_TABLE,
-            &[DEPLOY_HISTORY_COL_WASM_BINCODE, DEPLOY_HISTORY_COL_DEPLOY_IX],
-            convert_named_params! {(DEPLOY_HISTORY_COL_TX_HASH, tx_hash)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &DEPLOY_HISTORY_TABLE,
+                &[DEPLOY_HISTORY_COL_WASM_BINCODE, DEPLOY_HISTORY_COL_DEPLOY_IX],
+                convert_named_params! {(DEPLOY_HISTORY_COL_TX_HASH, tx_hash)},
+            )
+            .await
+        {
             Ok(v) => v,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -409,7 +418,7 @@ impl Drk {
     /// data to the wallet.
     /// Returns a flag indicating if the provided call refers to our
     /// own wallet.
-    fn apply_deploy_deploy_data(
+    async fn apply_deploy_deploy_data(
         &self,
         scan_cache: &ScanCache,
         params: &DeployParamsV1,
@@ -422,14 +431,17 @@ impl Drk {
         };
 
         // Create a new history record containing the deployment data
-        if let Err(e) = self.put_deploy_history_record(
-            tx_hash,
-            &ContractId::derive_public(params.public_key),
-            "DEPLOYMENT",
-            block_height,
-            &Some(params.wasm_bincode.clone()),
-            &Some(params.ix.clone()),
-        ) {
+        if let Err(e) = self
+            .put_deploy_history_record(
+                tx_hash,
+                &ContractId::derive_public(params.public_key),
+                "DEPLOYMENT",
+                block_height,
+                &Some(params.wasm_bincode.clone()),
+                &Some(params.ix.clone()),
+            )
+            .await
+        {
             return Err(Error::DatabaseError(format!(
                 "[apply_deploy_deploy_data] Inserting deploy history recod failed: {e}"
             )))
@@ -463,8 +475,7 @@ impl Drk {
             DEPLOY_AUTH_COL_LOCK_HEIGHT,
             DEPLOY_AUTH_COL_SECRET_KEY
         );
-        if let Err(e) =
-            self.wallet.exec_sql(&query, rusqlite::params![Some(*lock_height), secret_key])
+        if let Err(e) = self.wallet.exec_sql(&query, params![Some(*lock_height), secret_key]).await
         {
             return Err(Error::DatabaseError(format!(
                 "[apply_deploy_lock_data] Lock deploy authority failed: {e}"
@@ -472,14 +483,17 @@ impl Drk {
         }
 
         // Create a new history record for the lock transaction
-        if let Err(e) = self.put_deploy_history_record(
-            tx_hash,
-            &ContractId::derive_public(*public_key),
-            "LOCK",
-            lock_height,
-            &None,
-            &None,
-        ) {
+        if let Err(e) = self
+            .put_deploy_history_record(
+                tx_hash,
+                &ContractId::derive_public(*public_key),
+                "LOCK",
+                lock_height,
+                &None,
+                &None,
+            )
+            .await
+        {
             return Err(Error::DatabaseError(format!(
                 "[apply_deploy_lock_data] Inserting deploy history recod failed: {e}"
             )))
@@ -504,7 +518,7 @@ impl Drk {
             DeployFunction::DeployV1 => {
                 scan_cache.log(String::from("[apply_tx_deploy_data] Found Deploy::DeployV1 call"));
                 let params: DeployParamsV1 = deserialize_async(&data[1..]).await?;
-                self.apply_deploy_deploy_data(scan_cache, &params, tx_hash, block_height)
+                self.apply_deploy_deploy_data(scan_cache, &params, tx_hash, block_height).await
             }
             DeployFunction::LockV1 => {
                 scan_cache.log(String::from("[apply_tx_deploy_data] Found Deploy::LockV1 call"));

+ 0 - 2
bin/drk/src/error.rs

@@ -28,7 +28,6 @@ pub enum WalletDbError {
 
     // Connection related errors
     ConnectionFailed = -32110,
-    FailedToAquireLock = -32111,
 
     // Configuration related errors
     PragmaUpdateError = -32120,
@@ -49,7 +48,6 @@ impl std::fmt::Display for WalletDbError {
         match self {
             WalletDbError::InitializationFailed => write!(f, "WalletDbError::InitializationFailed"),
             WalletDbError::ConnectionFailed => write!(f, "WalletDbError::ConnectionFailed"),
-            WalletDbError::FailedToAquireLock => write!(f, "WalletDbError::FailedToAquireLock"),
             WalletDbError::PragmaUpdateError => write!(f, "WalletDbError::PragmaUpdateError"),
             WalletDbError::QueryPreparationFailed => {
                 write!(f, "WalletDbError::QueryPreparationFailed")

+ 6 - 6
bin/drk/src/interactive.rs

@@ -833,7 +833,7 @@ async fn handle_wallet_initialize(drk: &DrkPtr, output: &mut Vec<String>) {
         output.push(format!("Failed to initialize DAO: {e}"));
         return
     }
-    if let Err(e) = lock.initialize_deployooor() {
+    if let Err(e) = lock.initialize_deployooor().await {
         output.push(format!("Failed to initialize Deployooor: {e}"));
     }
 }
@@ -919,7 +919,7 @@ async fn handle_wallet_default_address(drk: &DrkPtr, parts: &[&str], output: &mu
         return
     }
 
-    let index = match usize::from_str(parts[2]) {
+    let index = match u16::from_str(parts[2]) {
         Ok(i) => i,
         Err(e) => {
             output.push(format!("Invalid address id: {e}"));
@@ -927,7 +927,7 @@ async fn handle_wallet_default_address(drk: &DrkPtr, parts: &[&str], output: &mu
         }
     };
 
-    if let Err(e) = drk.read().await.set_default_address(index) {
+    if let Err(e) = drk.read().await.set_default_address(index).await {
         output.push(format!("Failed to set default address: {e}"));
     }
 }
@@ -1032,7 +1032,7 @@ async fn handle_wallet_mining_config(drk: &DrkPtr, parts: &[&str], output: &mut
 
     // Parse command
     let mut index = 2;
-    let wallet_index = match usize::from_str(parts[index]) {
+    let wallet_index = match u16::from_str(parts[index]) {
         Ok(i) => i,
         Err(e) => {
             output.push(format!("Invalid address id: {e}"));
@@ -2761,7 +2761,7 @@ async fn handle_explorer_txs_history(drk: &DrkPtr, parts: &[&str], output: &mut
         return
     }
 
-    let map = match lock.get_txs_history() {
+    let map = match lock.get_txs_history().await {
         Ok(m) => m,
         Err(e) => {
             output.push(format!("Failed to retrieve transactions history records: {e}"));
@@ -2797,7 +2797,7 @@ async fn handle_explorer_clear_reverted(drk: &DrkPtr, parts: &[&str], output: &m
         return
     }
 
-    if let Err(e) = drk.read().await.remove_reverted_txs(output) {
+    if let Err(e) = drk.read().await.remove_reverted_txs(output).await {
         output.push(format!("Failed to remove reverted transactions: {e}"));
     }
 }

+ 11 - 11
bin/drk/src/lib.rs

@@ -114,7 +114,7 @@ impl Drk {
                 create_dir_all(parent)?;
             }
         }
-        let Ok(wallet) = WalletDb::new(Some(wallet_path), Some(&wallet_pass)) else {
+        let Ok(wallet) = WalletDb::new(Some(wallet_path), Some(&wallet_pass)).await else {
             return Err(Error::DatabaseError(format!("{}", WalletDbError::InitializationFailed)));
         };
 
@@ -135,26 +135,26 @@ impl Drk {
     /// Initialize wallet with tables for `Drk`.
     pub async fn initialize_wallet(&self) -> WalletDbResult<()> {
         // Initialize wallet schema
-        self.wallet.exec_batch_sql(include_str!("../wallet.sql"))?;
+        self.wallet.exec_batch_sql(include_str!("../wallet.sql")).await?;
 
         Ok(())
     }
 
     /// Auxiliary function to completely reset wallet state.
-    pub fn reset(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting full wallet state"));
         self.reset_scanned_blocks(output)?;
         self.reset_money_tree(output)?;
         self.reset_money_smt(output)?;
-        self.reset_money_coins(output)?;
-        self.reset_mint_authorities(output)?;
+        self.reset_money_coins(output).await?;
+        self.reset_mint_authorities(output).await?;
         self.reset_dao_trees(output)?;
-        self.reset_daos(output)?;
-        self.reset_dao_proposals(output)?;
-        self.reset_dao_votes(output)?;
-        self.reset_deploy_authorities(output)?;
-        self.reset_deploy_history(output)?;
-        self.reset_tx_history(output)?;
+        self.reset_daos(output).await?;
+        self.reset_dao_proposals(output).await?;
+        self.reset_dao_votes(output).await?;
+        self.reset_deploy_authorities(output).await?;
+        self.reset_deploy_history(output).await?;
+        self.reset_tx_history(output).await?;
         output.push(String::from("Successfully reset full wallet state"));
         Ok(())
     }

+ 6 - 6
bin/drk/src/main.rs

@@ -246,7 +246,7 @@ enum WalletSubcmd {
     /// Set the default address in the wallet
     DefaultAddress {
         /// Identifier of the address
-        index: usize,
+        index: u16,
     },
 
     /// Print all the secret keys from the wallet
@@ -264,7 +264,7 @@ enum WalletSubcmd {
     /// Print a wallet address mining configuration
     MiningConfig {
         /// Identifier of the address
-        index: usize,
+        index: u16,
 
         /// Optional contract spend hook to use
         spend_hook: Option<String>,
@@ -724,7 +724,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                         eprintln!("Failed to initialize DAO: {e}");
                         exit(2);
                     }
-                    if let Err(e) = drk.initialize_deployooor() {
+                    if let Err(e) = drk.initialize_deployooor().await {
                         eprintln!("Failed to initialize Deployooor: {e}");
                         exit(2);
                     }
@@ -793,7 +793,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 }
 
                 WalletSubcmd::DefaultAddress { index } => {
-                    if let Err(e) = drk.set_default_address(index) {
+                    if let Err(e) = drk.set_default_address(index).await {
                         eprintln!("Failed to set default address: {e}");
                         exit(2);
                     }
@@ -2227,7 +2227,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                     return Ok(())
                 }
 
-                let map = match drk.get_txs_history() {
+                let map = match drk.get_txs_history().await {
                     Ok(m) => m,
                     Err(e) => {
                         eprintln!("Failed to retrieve transactions history records: {e}");
@@ -2269,7 +2269,7 @@ async fn realmain(args: Args, ex: ExecutorPtr) -> Result<()> {
                 .await;
 
                 let mut output = vec![];
-                if let Err(e) = drk.remove_reverted_txs(&mut output) {
+                if let Err(e) = drk.remove_reverted_txs(&mut output).await {
                     print_output(&output);
                     eprintln!("Failed to remove reverted transactions: {e}");
                     exit(2);

+ 128 - 99
bin/drk/src/money.rs

@@ -23,7 +23,6 @@ use std::{
 
 use lazy_static::lazy_static;
 use rand::rngs::OsRng;
-use rusqlite::types::Value;
 
 use darkfi::{
     tx::Transaction,
@@ -65,7 +64,9 @@ use crate::{
     cli_util::kaching,
     convert_named_params,
     error::{WalletDbError, WalletDbResult},
+    params,
     rpc::ScanCache,
+    walletdb::Value,
     Drk,
 };
 
@@ -126,7 +127,7 @@ impl Drk {
     pub async fn initialize_money(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         // Initialize Money wallet schema
         let wallet_schema = include_str!("../money.sql");
-        self.wallet.exec_batch_sql(wallet_schema)?;
+        self.wallet.exec_batch_sql(wallet_schema).await?;
 
         // Insert DRK alias
         self.add_alias("DRK".to_string(), *DARK_TOKEN_ID, output).await?;
@@ -149,14 +150,16 @@ impl Drk {
             MONEY_KEYS_COL_PUBLIC,
             MONEY_KEYS_COL_SECRET
         );
-        self.wallet.exec_sql(
-            &query,
-            rusqlite::params![
-                is_default,
-                serialize_async(&keypair.public).await,
-                serialize_async(&keypair.secret).await
-            ],
-        )?;
+        self.wallet
+            .exec_sql(
+                &query,
+                params![
+                    is_default,
+                    serialize_async(&keypair.public).await,
+                    serialize_async(&keypair.secret).await
+                ],
+            )
+            .await?;
 
         output.push(String::from("New address:"));
         let address: Address = StandardAddress::from_public(self.network, keypair.public).into();
@@ -167,11 +170,15 @@ impl Drk {
 
     /// Fetch default secret key from the wallet.
     pub async fn default_secret(&self) -> Result<SecretKey> {
-        let row = match self.wallet.query_single(
-            &MONEY_KEYS_TABLE,
-            &[MONEY_KEYS_COL_SECRET],
-            convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &MONEY_KEYS_TABLE,
+                &[MONEY_KEYS_COL_SECRET],
+                convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -190,11 +197,15 @@ impl Drk {
 
     /// Fetch default pubkey from the wallet.
     pub async fn default_address(&self) -> Result<PublicKey> {
-        let row = match self.wallet.query_single(
-            &MONEY_KEYS_TABLE,
-            &[MONEY_KEYS_COL_PUBLIC],
-            convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &MONEY_KEYS_TABLE,
+                &[MONEY_KEYS_COL_PUBLIC],
+                convert_named_params! {(MONEY_KEYS_COL_IS_DEFAULT, 1)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -212,11 +223,11 @@ impl Drk {
     }
 
     /// Set provided index address as default in the wallet.
-    pub fn set_default_address(&self, idx: usize) -> WalletDbResult<()> {
+    pub async fn set_default_address(&self, idx: u16) -> WalletDbResult<()> {
         // First we update previous default record
         let is_default = 0;
         let query = format!("UPDATE {} SET {} = ?1", *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT,);
-        self.wallet.exec_sql(&query, rusqlite::params![is_default])?;
+        self.wallet.exec_sql(&query, params![is_default]).await?;
 
         // and then we set the new one
         let is_default = 1;
@@ -224,12 +235,12 @@ impl Drk {
             "UPDATE {} SET {} = ?1 WHERE {} = ?2",
             *MONEY_KEYS_TABLE, MONEY_KEYS_COL_IS_DEFAULT, MONEY_KEYS_COL_KEY_ID,
         );
-        self.wallet.exec_sql(&query, rusqlite::params![is_default, idx])
+        self.wallet.exec_sql(&query, params![is_default, idx]).await
     }
 
     /// Fetch all pukeys from the wallet.
     pub async fn addresses(&self) -> Result<Vec<(u64, PublicKey, SecretKey, u64)>> {
-        let rows = match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -274,16 +285,20 @@ impl Drk {
     /// mining configuration.
     pub async fn mining_config(
         &self,
-        idx: usize,
+        idx: u16,
         spend_hook: Option<FuncId>,
         user_data: Option<pallas::Base>,
         output: &mut Vec<String>,
     ) -> Result<()> {
-        let row = match self.wallet.query_single(
-            &MONEY_KEYS_TABLE,
-            &[MONEY_KEYS_COL_PUBLIC],
-            convert_named_params! {(MONEY_KEYS_COL_KEY_ID, idx)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                &MONEY_KEYS_TABLE,
+                &[MONEY_KEYS_COL_PUBLIC],
+                convert_named_params! {(MONEY_KEYS_COL_KEY_ID, idx)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -308,15 +323,18 @@ impl Drk {
 
     /// Fetch all secret keys from the wallet.
     pub async fn get_money_secrets(&self) -> Result<Vec<SecretKey>> {
-        let rows =
-            match self.wallet.query_multiple(&MONEY_KEYS_TABLE, &[MONEY_KEYS_COL_SECRET], &[]) {
-                Ok(r) => r,
-                Err(e) => {
-                    return Err(Error::DatabaseError(format!(
-                        "[get_money_secrets] Secret keys retrieval failed: {e}"
-                    )))
-                }
-            };
+        let rows = match self
+            .wallet
+            .query_multiple(&MONEY_KEYS_TABLE, &[MONEY_KEYS_COL_SECRET], vec![])
+            .await
+        {
+            Ok(r) => r,
+            Err(e) => {
+                return Err(Error::DatabaseError(format!(
+                    "[get_money_secrets] Secret keys retrieval failed: {e}"
+                )))
+            }
+        };
 
         let mut secrets = Vec::with_capacity(rows.len());
 
@@ -365,8 +383,7 @@ impl Drk {
                 MONEY_KEYS_COL_PUBLIC,
                 MONEY_KEYS_COL_SECRET
             );
-            if let Err(e) =
-                self.wallet.exec_sql(&query, rusqlite::params![is_default, public, secret])
+            if let Err(e) = self.wallet.exec_sql(&query, params![is_default, public, secret]).await
             {
                 return Err(Error::DatabaseError(format!(
                     "[import_money_secrets] Inserting new address failed: {e}"
@@ -407,13 +424,15 @@ impl Drk {
         fetch_spent: bool,
     ) -> Result<Vec<(OwnCoin, u32, bool, Option<u32>, String)>> {
         let query = if fetch_spent {
-            self.wallet.query_multiple(&MONEY_COINS_TABLE, &[], &[])
+            self.wallet.query_multiple(&MONEY_COINS_TABLE, &[], vec![]).await
         } else {
-            self.wallet.query_multiple(
-                &MONEY_COINS_TABLE,
-                &[],
-                convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false)},
-            )
+            self.wallet
+                .query_multiple(
+                    &MONEY_COINS_TABLE,
+                    &[],
+                    convert_named_params! {(MONEY_COINS_COL_IS_SPENT, false)},
+                )
+                .await
         };
 
         let rows = match query {
@@ -433,15 +452,18 @@ impl Drk {
 
     /// Fetch provided token unspend balances from the wallet.
     pub async fn get_token_coins(&self, token_id: &TokenId) -> Result<Vec<OwnCoin>> {
-        let query = self.wallet.query_multiple(
-            &MONEY_COINS_TABLE,
-            &[],
-            convert_named_params! {
-                (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
-                (MONEY_COINS_COL_SPEND_HOOK, serialize_async(&FuncId::none()).await),
-                (MONEY_COINS_COL_IS_SPENT, false),
-            },
-        );
+        let query = self
+            .wallet
+            .query_multiple(
+                &MONEY_COINS_TABLE,
+                &[],
+                convert_named_params! {
+                    (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
+                    (MONEY_COINS_COL_SPEND_HOOK, serialize_async(&FuncId::none()).await),
+                    (MONEY_COINS_COL_IS_SPENT, false),
+                },
+            )
+            .await;
 
         let rows = match query {
             Ok(r) => r,
@@ -467,16 +489,19 @@ impl Drk {
         spend_hook: &FuncId,
         user_data: &pallas::Base,
     ) -> Result<Vec<OwnCoin>> {
-        let query = self.wallet.query_multiple(
-            &MONEY_COINS_TABLE,
-            &[],
-            convert_named_params! {
-                (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
-                (MONEY_COINS_COL_SPEND_HOOK, serialize_async(spend_hook).await),
-                (MONEY_COINS_COL_USER_DATA, serialize_async(user_data).await),
-                (MONEY_COINS_COL_IS_SPENT, false),
-            },
-        );
+        let query = self
+            .wallet
+            .query_multiple(
+                &MONEY_COINS_TABLE,
+                &[],
+                convert_named_params! {
+                    (MONEY_COINS_COL_TOKEN_ID, serialize_async(token_id).await),
+                    (MONEY_COINS_COL_SPEND_HOOK, serialize_async(spend_hook).await),
+                    (MONEY_COINS_COL_USER_DATA, serialize_async(user_data).await),
+                    (MONEY_COINS_COL_IS_SPENT, false),
+                },
+            )
+            .await;
 
         let rows = match query {
             Ok(r) => r,
@@ -622,10 +647,12 @@ impl Drk {
             "INSERT OR REPLACE INTO {} ({}, {}) VALUES (?1, ?2);",
             *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
         );
-        self.wallet.exec_sql(
-            &query,
-            rusqlite::params![serialize_async(&alias).await, serialize_async(&token_id).await],
-        )
+        self.wallet
+            .exec_sql(
+                &query,
+                params![serialize_async(&alias).await, serialize_async(&token_id).await],
+            )
+            .await
     }
 
     /// Fetch all aliases from the wallet.
@@ -635,7 +662,7 @@ impl Drk {
         alias_filter: Option<String>,
         token_id_filter: Option<TokenId>,
     ) -> Result<HashMap<String, TokenId>> {
-        let rows = match self.wallet.query_multiple(&MONEY_ALIASES_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&MONEY_ALIASES_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -697,7 +724,7 @@ impl Drk {
             "DELETE FROM {} WHERE {} = ?1;",
             *MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS,
         );
-        self.wallet.exec_sql(&query, rusqlite::params![serialize_async(&alias).await])
+        self.wallet.exec_sql(&query, params![serialize_async(&alias).await]).await
     }
 
     /// Mark a given coin in the wallet as unspent.
@@ -710,7 +737,7 @@ impl Drk {
             MONEY_COINS_COL_SPENT_TX_HASH,
             MONEY_COINS_COL_COIN
         );
-        self.wallet.exec_sql(&query, rusqlite::params![serialize_async(&coin.inner()).await])
+        self.wallet.exec_sql(&query, params![serialize_async(&coin.inner()).await]).await
     }
 
     /// Fetch the Money Merkle tree from the cache.
@@ -909,8 +936,8 @@ impl Drk {
                 .insert(coin.nullifier().to_bytes(), (key, coin.leaf_position));
 
             // Execute the query
-            let params = rusqlite::params![
-                key,
+            let params = params![
+                key.to_vec(),
                 serialize(&coin.note.value),
                 serialize(&coin.note.token_id),
                 serialize(&coin.note.spend_hook),
@@ -921,12 +948,12 @@ impl Drk {
                 serialize(&coin.secret),
                 serialize(&coin.leaf_position),
                 serialize(&coin.note.memo),
-                creation_height,
+                *creation_height,
                 0, // <-- is_spent
                 spent_height,
             ];
 
-            if let Err(e) = self.wallet.exec_sql(&query, params) {
+            if let Err(e) = self.wallet.exec_sql(&query, params).await {
                 return Err(Error::DatabaseError(format!(
                     "[handle_money_call_owncoins] Inserting Money coin failed: {e}"
                 )))
@@ -978,9 +1005,7 @@ impl Drk {
             let key = serialize_async(token_id).await;
 
             // Execute the query
-            if let Err(e) =
-                self.wallet.exec_sql(&query, rusqlite::params![Some(*freeze_height), key])
-            {
+            if let Err(e) = self.wallet.exec_sql(&query, params![Some(*freeze_height), key]).await {
                 return Err(Error::DatabaseError(format!(
                     "[handle_money_call_freezes] Update Money token freeze failed: {e}"
                 )))
@@ -999,7 +1024,7 @@ impl Drk {
         scan_cache: &mut ScanCache,
         call_idx: &usize,
         calls: &[DarkLeaf<ContractCall>],
-        tx_hash: &String,
+        tx_hash: &str,
         block_height: &u32,
     ) -> Result<(bool, Option<SecretKey>)> {
         // Parse the call
@@ -1018,13 +1043,15 @@ impl Drk {
         self.smt_insert(&mut scan_cache.money_smt, &nullifiers)?;
 
         // Check if we have any spent coins
-        let wallet_spent_coins = self.mark_spent_coins(
-            Some(&mut scan_cache.money_tree),
-            &scan_cache.owncoins_nullifiers,
-            &nullifiers,
-            &Some(*block_height),
-            tx_hash,
-        )?;
+        let wallet_spent_coins = self
+            .mark_spent_coins(
+                Some(&mut scan_cache.money_tree),
+                &scan_cache.owncoins_nullifiers,
+                &nullifiers,
+                &Some(*block_height),
+                tx_hash,
+            )
+            .await?;
 
         // Handle our own coins
         self.handle_money_call_owncoins(scan_cache, &owncoins, block_height).await?;
@@ -1083,7 +1110,7 @@ impl Drk {
 
             output.push(format!("[mark_tx_spend] Found Money contract in call {i}"));
             let nullifiers = self.money_call_nullifiers(call).await?;
-            self.mark_spent_coins(None, &owncoins_nullifiers, &nullifiers, &None, &tx_hash)?;
+            self.mark_spent_coins(None, &owncoins_nullifiers, &nullifiers, &None, &tx_hash).await?;
         }
 
         Ok(())
@@ -1091,13 +1118,13 @@ impl Drk {
 
     /// Marks all coins in the wallet as spent, if their nullifier is in the given set.
     /// Returns a flag indicating if any of the provided nullifiers refer to our own wallet.
-    pub fn mark_spent_coins(
+    pub async fn mark_spent_coins(
         &self,
         mut tree: Option<&mut MerkleTree>,
         owncoins_nullifiers: &BTreeMap<[u8; 32], ([u8; 32], Position)>,
         nullifiers: &[Nullifier],
         spent_height: &Option<u32>,
-        spent_tx_hash: &String,
+        spent_tx_hash: &str,
     ) -> Result<bool> {
         if nullifiers.is_empty() {
             return Ok(false)
@@ -1127,8 +1154,10 @@ impl Drk {
         // Mark spent own coins
         for (ownoin, leaf_position) in spent_owncoins {
             // Execute the query
-            if let Err(e) =
-                self.wallet.exec_sql(&query, rusqlite::params![spent_height, spent_tx_hash, ownoin])
+            if let Err(e) = self
+                .wallet
+                .exec_sql(&query, params![*spent_height, spent_tx_hash, ownoin.to_vec()])
+                .await
             {
                 return Err(Error::DatabaseError(format!(
                     "[mark_spent_coins] Marking spent coin failed: {e}"
@@ -1176,10 +1205,10 @@ impl Drk {
     }
 
     /// Reset the Money coins in the wallet.
-    pub fn reset_money_coins(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_money_coins(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting coins"));
         let query = format!("DELETE FROM {};", *MONEY_COINS_TABLE);
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully reset coins"));
 
         Ok(())
@@ -1187,7 +1216,7 @@ impl Drk {
 
     /// Remove the Money coins in the wallet that were created after
     /// provided height.
-    pub fn remove_money_coins_after(
+    pub async fn remove_money_coins_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1197,7 +1226,7 @@ impl Drk {
             "DELETE FROM {} WHERE {} > ?1;",
             *MONEY_COINS_TABLE, MONEY_COINS_COL_CREATION_HEIGHT
         );
-        self.wallet.exec_sql(&query, rusqlite::params![height])?;
+        self.wallet.exec_sql(&query, params![*height]).await?;
         output.push(String::from("Successfully removed coins"));
 
         Ok(())
@@ -1205,7 +1234,7 @@ impl Drk {
 
     /// Mark the Money coins in the wallet that were spent after
     /// provided height as unspent.
-    pub fn unspent_money_coins_after(
+    pub async fn unspent_money_coins_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -1219,7 +1248,7 @@ impl Drk {
             MONEY_COINS_COL_SPENT_TX_HASH,
             MONEY_COINS_COL_SPENT_HEIGHT
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully unspent coins"));
 
         Ok(())

+ 1 - 1
bin/drk/src/rpc.rs

@@ -367,7 +367,7 @@ impl Drk {
         // otherwise continue with the next block height.
         if height == 0 {
             let mut buf = vec![];
-            self.reset(&mut buf)?;
+            self.reset(&mut buf).await?;
             append_or_print(output, sender, print, buf).await;
         } else {
             height += 1;

+ 11 - 11
bin/drk/src/scanned_blocks.rs

@@ -112,7 +112,7 @@ impl Drk {
         // If genesis block height(0) was provided,
         // perform a full reset.
         if height == 0 {
-            return self.reset(output)
+            return self.reset(output).await
         }
 
         // Grab last scanned block height
@@ -205,39 +205,39 @@ impl Drk {
         }
 
         // Remove all wallet coins created after the reset height
-        self.remove_money_coins_after(&height, output)?;
+        self.remove_money_coins_after(&height, output).await?;
 
         // Unspent all wallet coins spent after the reset height
-        self.unspent_money_coins_after(&height, output)?;
+        self.unspent_money_coins_after(&height, output).await?;
 
         // Unfreeze tokens mint authorities frozen after the reset
         // height.
-        self.unfreeze_mint_authorities_after(&height, output)?;
+        self.unfreeze_mint_authorities_after(&height, output).await?;
 
         // Unconfirm DAOs minted after the reset height
-        self.unconfirm_daos_after(&height, output)?;
+        self.unconfirm_daos_after(&height, output).await?;
 
         // Unconfirm DAOs proposals minted after the reset height
-        self.unconfirm_dao_proposals_after(&height, output)?;
+        self.unconfirm_dao_proposals_after(&height, output).await?;
 
         // Reset execution information for DAOs proposals executed
         // after the reset height.
-        self.unexec_dao_proposals_after(&height, output)?;
+        self.unexec_dao_proposals_after(&height, output).await?;
 
         // Remove all DAOs proposals votes created after the reset
         // height.
-        self.remove_dao_votes_after(&height, output)?;
+        self.remove_dao_votes_after(&height, output).await?;
 
         // Unlock all contracts frozen after the reset height
-        self.unlock_deploy_authorities_after(&height, output)?;
+        self.unlock_deploy_authorities_after(&height, output).await?;
 
         // Remove all contracts history records created after the reset
         // height.
-        self.remove_deploy_history_after(&height, output)?;
+        self.remove_deploy_history_after(&height, output).await?;
 
         // Set reverted status to all transactions executed after reset
         // height.
-        self.revert_transactions_after(&height, output)?;
+        self.revert_transactions_after(&height, output).await?;
 
         output.push(String::from("Successfully reset wallet state"));
         Ok(())

+ 22 - 17
bin/drk/src/token.rs

@@ -17,7 +17,6 @@
  */
 
 use rand::rngs::OsRng;
-use rusqlite::types::Value;
 
 use darkfi::{
     tx::{ContractCallLeaf, Transaction, TransactionBuilder},
@@ -55,6 +54,8 @@ use crate::{
         MONEY_TOKENS_COL_MINT_AUTHORITY, MONEY_TOKENS_COL_TOKEN_BLIND, MONEY_TOKENS_COL_TOKEN_ID,
         MONEY_TOKENS_TABLE,
     },
+    params,
+    walletdb::Value,
     Drk,
 };
 
@@ -103,16 +104,20 @@ impl Drk {
             MONEY_TOKENS_COL_FREEZE_HEIGHT,
         );
 
-        if let Err(e) = self.wallet.exec_sql(
-            &query,
-            rusqlite::params![
-                serialize_async(&token_id).await,
-                serialize_async(&mint_authority).await,
-                serialize_async(&token_blind).await,
-                is_frozen,
-                freeze_height,
-            ],
-        ) {
+        if let Err(e) = self
+            .wallet
+            .exec_sql(
+                &query,
+                params![
+                    serialize_async(&token_id).await,
+                    serialize_async(&mint_authority).await,
+                    serialize_async(&token_blind).await,
+                    is_frozen,
+                    freeze_height,
+                ],
+            )
+            .await
+        {
             return Err(Error::DatabaseError(format!(
                 "[import_mint_authority] Inserting mint authority failed: {e}"
             )))
@@ -176,13 +181,13 @@ impl Drk {
     }
 
     /// Reset all token mint authorities frozen status in the wallet.
-    pub fn reset_mint_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_mint_authorities(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting mint authorities frozen status"));
         let query = format!(
             "UPDATE {} SET {} = 0, {} = NULL;",
             *MONEY_TOKENS_TABLE, MONEY_TOKENS_COL_IS_FROZEN, MONEY_TOKENS_COL_FREEZE_HEIGHT
         );
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully reset mint authorities frozen status"));
 
         Ok(())
@@ -190,7 +195,7 @@ impl Drk {
 
     /// Remove token mint authorities frozen status in the wallet that
     /// where frozen after provided height.
-    pub fn unfreeze_mint_authorities_after(
+    pub async fn unfreeze_mint_authorities_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -203,7 +208,7 @@ impl Drk {
             MONEY_TOKENS_COL_FREEZE_HEIGHT,
             MONEY_TOKENS_COL_FREEZE_HEIGHT
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully reset mint authorities frozen status"));
 
         Ok(())
@@ -213,7 +218,7 @@ impl Drk {
     pub async fn get_mint_authorities(
         &self,
     ) -> Result<Vec<(TokenId, SecretKey, BaseBlind, bool, Option<u32>)>> {
-        let rows = match self.wallet.query_multiple(&MONEY_TOKENS_TABLE, &[], &[]) {
+        let rows = match self.wallet.query_multiple(&MONEY_TOKENS_TABLE, &[], vec![]).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -239,7 +244,7 @@ impl Drk {
             &MONEY_TOKENS_TABLE,
             &[],
             convert_named_params! {(MONEY_TOKENS_COL_TOKEN_ID, serialize_async(token_id).await)},
-        ) {
+        ).await {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(

+ 32 - 24
bin/drk/src/txs_history.rs

@@ -16,14 +16,14 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use rusqlite::types::Value;
-
 use darkfi::{tx::Transaction, Error, Result};
 use darkfi_serial::{deserialize_async, serialize};
 
 use crate::{
     convert_named_params,
     error::{WalletDbError, WalletDbResult},
+    params,
+    walletdb::Value,
     Drk,
 };
 
@@ -52,7 +52,8 @@ impl Drk {
         // Execute the query
         let tx_hash = tx.hash().to_string();
         self.wallet
-            .exec_sql(&query, rusqlite::params![tx_hash, status, block_height, &serialize(tx)])?;
+            .exec_sql(&query, params![tx_hash.clone(), status, block_height, serialize(tx)])
+            .await?;
 
         Ok(tx_hash)
     }
@@ -77,11 +78,15 @@ impl Drk {
         &self,
         tx_hash: &str,
     ) -> Result<(String, String, Option<u32>, Transaction)> {
-        let row = match self.wallet.query_single(
-            WALLET_TXS_HISTORY_TABLE,
-            &[],
-            convert_named_params! {(WALLET_TXS_HISTORY_COL_TX_HASH, tx_hash)},
-        ) {
+        let row = match self
+            .wallet
+            .query_single(
+                WALLET_TXS_HISTORY_TABLE,
+                &[],
+                convert_named_params! {(WALLET_TXS_HISTORY_COL_TX_HASH, tx_hash)},
+            )
+            .await
+        {
             Ok(r) => r,
             Err(e) => {
                 return Err(Error::DatabaseError(format!(
@@ -128,16 +133,19 @@ impl Drk {
     }
 
     /// Fetch all transactions history records, excluding bytes column.
-    pub fn get_txs_history(&self) -> WalletDbResult<Vec<(String, String, Option<u32>)>> {
-        let rows = self.wallet.query_multiple(
-            WALLET_TXS_HISTORY_TABLE,
-            &[
-                WALLET_TXS_HISTORY_COL_TX_HASH,
-                WALLET_TXS_HISTORY_COL_STATUS,
-                WALLET_TXS_HISTORY_BLOCK_HEIGHT,
-            ],
-            &[],
-        )?;
+    pub async fn get_txs_history(&self) -> WalletDbResult<Vec<(String, String, Option<u32>)>> {
+        let rows = self
+            .wallet
+            .query_multiple(
+                WALLET_TXS_HISTORY_TABLE,
+                &[
+                    WALLET_TXS_HISTORY_COL_TX_HASH,
+                    WALLET_TXS_HISTORY_COL_STATUS,
+                    WALLET_TXS_HISTORY_BLOCK_HEIGHT,
+                ],
+                vec![],
+            )
+            .await?;
 
         let mut ret = Vec::with_capacity(rows.len());
         for row in rows {
@@ -167,10 +175,10 @@ impl Drk {
     }
 
     /// Reset the transaction history records in the wallet.
-    pub fn reset_tx_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn reset_tx_history(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Resetting transactions history"));
         let query = format!("DELETE FROM {WALLET_TXS_HISTORY_TABLE};");
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully reset transactions history"));
 
         Ok(())
@@ -178,7 +186,7 @@ impl Drk {
 
     /// Set reverted status to the transaction history records in the
     /// wallet that where executed after provided height.
-    pub fn revert_transactions_after(
+    pub async fn revert_transactions_after(
         &self,
         height: &u32,
         output: &mut Vec<String>,
@@ -187,7 +195,7 @@ impl Drk {
         let query = format!(
             "UPDATE {WALLET_TXS_HISTORY_TABLE} SET {WALLET_TXS_HISTORY_COL_STATUS} = 'Reverted', {WALLET_TXS_HISTORY_BLOCK_HEIGHT} = NULL WHERE {WALLET_TXS_HISTORY_BLOCK_HEIGHT} > ?1;"
         );
-        self.wallet.exec_sql(&query, rusqlite::params![Some(*height)])?;
+        self.wallet.exec_sql(&query, params![Some(*height)]).await?;
         output.push(String::from("Successfully reverted transactions history"));
 
         Ok(())
@@ -195,12 +203,12 @@ impl Drk {
 
     /// Remove the transaction history records in the wallet
     /// that have been reverted.
-    pub fn remove_reverted_txs(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
+    pub async fn remove_reverted_txs(&self, output: &mut Vec<String>) -> WalletDbResult<()> {
         output.push(String::from("Removing reverted transactions history records"));
         let query = format!(
             "DELETE FROM {WALLET_TXS_HISTORY_TABLE} WHERE {WALLET_TXS_HISTORY_COL_STATUS} = 'Reverted';"
         );
-        self.wallet.exec_sql(&query, &[])?;
+        self.wallet.exec_sql(&query, vec![]).await?;
         output.push(String::from("Successfully removed reverted transactions history records"));
 
         Ok(())

+ 266 - 235
bin/drk/src/walletdb.rs

@@ -16,58 +16,76 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::{
-    path::PathBuf,
-    sync::{Arc, Mutex},
-};
-
-use rusqlite::{
-    types::{ToSql, Value},
-    Connection,
-};
+use std::{convert::From, path::PathBuf, sync::Arc};
+
+use smol::lock::Mutex as AsyncMutex;
 use tracing::{debug, error};
+pub use turso::{Builder, Connection, EncryptionOpts, Value};
 
 use crate::error::{WalletDbError, WalletDbResult};
 
 pub type WalletPtr = Arc<WalletDb>;
 
+const ENCRYPTION_ALGO: &str = "aegis256";
+
 /// Structure representing base wallet database operations.
 pub struct WalletDb {
-    /// Connection to the SQLite database.
-    pub conn: Mutex<Connection>,
+    /// Connection to the turso database.
+    pub conn: AsyncMutex<Connection>,
 }
 
 impl WalletDb {
     /// Create a new wallet database handler. If `path` is `None`, create it in memory.
-    pub fn new(path: Option<PathBuf>, password: Option<&str>) -> WalletDbResult<WalletPtr> {
-        let Ok(conn) = (match path.clone() {
-            Some(p) => Connection::open(p),
-            None => Connection::open_in_memory(),
-        }) else {
+    pub async fn new(path: Option<PathBuf>, password: Option<&str>) -> WalletDbResult<WalletPtr> {
+        // Parse database path
+        let path = match path {
+            Some(p) => {
+                let Some(p) = p.to_str() else {
+                    return Err(WalletDbError::ConnectionFailed);
+                };
+                String::from(p)
+            }
+            None => String::from(":memory:"),
+        };
+
+        // Set encryption. We have to manually devire the key since
+        // turso doesn't support it yet.
+        let builder = match password {
+            Some(password) => {
+                let opts = EncryptionOpts {
+                    cipher: String::from(ENCRYPTION_ALGO),
+                    hexkey: blake3::hash(password.as_bytes()).to_hex().to_string(),
+                };
+                Builder::new_local(&path).experimental_encryption(true).with_encryption(opts)
+            }
+            None => Builder::new_local(&path),
+        };
+
+        // Initialize connection builder
+        let Ok(builder) = builder.build().await else {
             return Err(WalletDbError::ConnectionFailed);
         };
 
-        if let Some(password) = password {
-            if let Err(e) = conn.pragma_update(None, "key", password) {
-                error!(target: "walletdb::new", "[WalletDb] Pragma update failed: {e}");
-                return Err(WalletDbError::PragmaUpdateError);
-            };
-        }
-        if let Err(e) = conn.pragma_update(None, "foreign_keys", "ON") {
-            error!(target: "walletdb::new", "[WalletDb] Pragma update failed: {e}");
+        // Connect to database
+        let Ok(conn) = builder.connect() else {
+            return Err(WalletDbError::ConnectionFailed);
+        };
+
+        // Set foreign keys pragma
+        if let Err(e) = conn.pragma_update("foreign_keys", "ON").await {
+            error!(target: "walletdb::new", "[WalletDb] Foreign keys pragma update failed: {e}");
             return Err(WalletDbError::PragmaUpdateError);
         };
 
         debug!(target: "walletdb::new", "[WalletDb] Opened Sqlite connection at \"{path:?}\"");
-        Ok(Arc::new(Self { conn: Mutex::new(conn) }))
+        Ok(Arc::new(Self { conn: AsyncMutex::new(conn) }))
     }
 
     /// This function executes a given SQL query that contains multiple SQL statements,
     /// that don't contain any parameters.
-    pub fn exec_batch_sql(&self, query: &str) -> WalletDbResult<()> {
+    pub async fn exec_batch_sql(&self, query: &str) -> WalletDbResult<()> {
         debug!(target: "walletdb::exec_batch_sql", "[WalletDb] Executing batch SQL query:\n{query}");
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
-        if let Err(e) = conn.execute_batch(query) {
+        if let Err(e) = self.conn.lock().await.execute_batch(query).await {
             error!(target: "walletdb::exec_batch_sql", "[WalletDb] Query failed: {e}");
             return Err(WalletDbError::QueryExecutionFailed)
         };
@@ -77,13 +95,13 @@ impl WalletDb {
 
     /// This function executes a given SQL query, but isn't able to return anything.
     /// Therefore it's best to use it for initializing a table or similar things.
-    pub fn exec_sql(&self, query: &str, params: &[&dyn ToSql]) -> WalletDbResult<()> {
+    pub async fn exec_sql(&self, query: &str, params: Vec<Value>) -> WalletDbResult<()> {
         debug!(target: "walletdb::exec_sql", "[WalletDb] Executing SQL query:\n{query}");
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
+        let conn = self.conn.lock().await;
 
         // If no params are provided, execute directly
         if params.is_empty() {
-            if let Err(e) = conn.execute(query, ()) {
+            if let Err(e) = conn.execute(query, ()).await {
                 error!(target: "walletdb::exec_sql", "[WalletDb] Query failed: {e}");
                 return Err(WalletDbError::QueryExecutionFailed)
             };
@@ -91,58 +109,20 @@ impl WalletDb {
         }
 
         // First we prepare the query
-        let Ok(mut stmt) = conn.prepare(query) else {
+        let Ok(mut stmt) = conn.prepare(query).await else {
             return Err(WalletDbError::QueryPreparationFailed)
         };
 
         // Execute the query using provided params
-        if let Err(e) = stmt.execute(params) {
+        if let Err(e) = stmt.execute(params).await {
             error!(target: "walletdb::exec_sql", "[WalletDb] Query failed: {e}");
             return Err(WalletDbError::QueryExecutionFailed)
         };
-
-        // Finalize query and drop connection lock
-        if let Err(e) = stmt.finalize() {
-            error!(target: "walletdb::exec_sql", "[WalletDb] Query finalization failed: {e}");
-            return Err(WalletDbError::QueryFinalizationFailed)
-        };
         drop(conn);
 
         Ok(())
     }
 
-    /// Generate a new statement for provided query and bind the provided params,
-    /// returning the raw SQL query as a string.
-    pub fn create_prepared_statement(
-        &self,
-        query: &str,
-        params: &[&dyn ToSql],
-    ) -> WalletDbResult<String> {
-        debug!(target: "walletdb::create_prepared_statement", "[WalletDb] Preparing statement for SQL query:\n{query}");
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
-
-        // First we prepare the query
-        let Ok(mut stmt) = conn.prepare(query) else {
-            return Err(WalletDbError::QueryPreparationFailed)
-        };
-
-        // Bind all provided params
-        for (index, param) in params.iter().enumerate() {
-            if stmt.raw_bind_parameter(index + 1, param).is_err() {
-                return Err(WalletDbError::QueryPreparationFailed)
-            };
-        }
-
-        // Grab the raw SQL
-        let query = stmt.expanded_sql().unwrap();
-
-        // Drop statement and the connection lock
-        drop(stmt);
-        drop(conn);
-
-        Ok(query)
-    }
-
     /// Generate a `SELECT` query for provided table from selected column names and
     /// provided `WHERE` clauses. Named parameters are supported in the `WHERE` clauses,
     /// assuming they follow the normal formatting ":{column_name}".
@@ -150,7 +130,7 @@ impl WalletDb {
         &self,
         table: &str,
         col_names: &[&str],
-        params: &[(&str, &dyn ToSql)],
+        params: &[(String, Value)],
     ) -> String {
         let mut query = if col_names.is_empty() {
             format!("SELECT * FROM {table}")
@@ -173,30 +153,30 @@ impl WalletDb {
 
     /// Query provided table from selected column names and provided `WHERE` clauses,
     /// for a single row.
-    pub fn query_single(
+    pub async fn query_single(
         &self,
         table: &str,
         col_names: &[&str],
-        params: &[(&str, &dyn ToSql)],
+        params: Vec<(String, Value)>,
     ) -> WalletDbResult<Vec<Value>> {
         // Generate `SELECT` query
-        let query = self.generate_select_query(table, col_names, params);
+        let query = self.generate_select_query(table, col_names, &params);
         debug!(target: "walletdb::query_single", "[WalletDb] Executing SQL query:\n{query}");
 
         // First we prepare the query
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
+        let conn = self.conn.lock().await;
 
-        let Ok(mut stmt) = conn.prepare(&query) else {
+        let Ok(mut stmt) = conn.prepare(&query).await else {
             return Err(WalletDbError::QueryPreparationFailed)
         };
 
         // Execute the query using provided params
-        let Ok(mut rows) = stmt.query(params) else {
+        let Ok(mut rows) = stmt.query(params).await else {
             return Err(WalletDbError::QueryExecutionFailed)
         };
 
         // Check if row exists
-        let Ok(next) = rows.next() else { return Err(WalletDbError::QueryExecutionFailed) };
+        let Ok(next) = rows.next().await else { return Err(WalletDbError::QueryExecutionFailed) };
         let row = match next {
             Some(row_result) => row_result,
             None => return Err(WalletDbError::RowNotFound),
@@ -207,13 +187,16 @@ impl WalletDb {
         if col_names.is_empty() {
             let mut idx = 0;
             loop {
-                let Ok(value) = row.get(idx) else { break };
+                let Ok(value) = row.get_value(idx) else { break };
                 result.push(value);
                 idx += 1;
             }
         } else {
             for col in col_names {
-                let Ok(value) = row.get(*col) else {
+                let Ok(idx) = rows.column_index(col) else {
+                    return Err(WalletDbError::ParseColumnValueError)
+                };
+                let Ok(value) = row.get_value(idx) else {
                     return Err(WalletDbError::ParseColumnValueError)
                 };
                 result.push(value);
@@ -225,24 +208,24 @@ impl WalletDb {
 
     /// Query provided table from selected column names and provided `WHERE` clauses,
     /// for multiple rows.
-    pub fn query_multiple(
+    pub async fn query_multiple(
         &self,
         table: &str,
         col_names: &[&str],
-        params: &[(&str, &dyn ToSql)],
+        params: Vec<(String, Value)>,
     ) -> WalletDbResult<Vec<Vec<Value>>> {
         // Generate `SELECT` query
-        let query = self.generate_select_query(table, col_names, params);
+        let query = self.generate_select_query(table, col_names, &params);
         debug!(target: "walletdb::query_multiple", "[WalletDb] Executing SQL query:\n{query}");
 
         // First we prepare the query
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
-        let Ok(mut stmt) = conn.prepare(&query) else {
+        let conn = self.conn.lock().await;
+        let Ok(mut stmt) = conn.prepare(&query).await else {
             return Err(WalletDbError::QueryPreparationFailed)
         };
 
         // Execute the query using provided converted params
-        let Ok(mut rows) = stmt.query(params) else {
+        let Ok(mut rows) = stmt.query(params).await else {
             return Err(WalletDbError::QueryExecutionFailed)
         };
 
@@ -250,7 +233,7 @@ impl WalletDb {
         let mut result = vec![];
         loop {
             // Check if an error occured
-            let row = match rows.next() {
+            let row = match rows.next().await {
                 Ok(r) => r,
                 Err(_) => return Err(WalletDbError::QueryExecutionFailed),
             };
@@ -266,13 +249,16 @@ impl WalletDb {
             if col_names.is_empty() {
                 let mut idx = 0;
                 loop {
-                    let Ok(value) = row.get(idx) else { break };
+                    let Ok(value) = row.get_value(idx) else { break };
                     row_values.push(value);
                     idx += 1;
                 }
             } else {
                 for col in col_names {
-                    let Ok(value) = row.get(*col) else {
+                    let Ok(idx) = rows.column_index(col) else {
+                        return Err(WalletDbError::ParseColumnValueError)
+                    };
+                    let Ok(value) = row.get_value(idx) else {
                         return Err(WalletDbError::ParseColumnValueError)
                     };
                     row_values.push(value);
@@ -285,21 +271,21 @@ impl WalletDb {
     }
 
     /// Query provided table using provided query for multiple rows.
-    pub fn query_custom(
+    pub async fn query_custom(
         &self,
         query: &str,
-        params: &[&dyn ToSql],
+        params: Vec<Value>,
     ) -> WalletDbResult<Vec<Vec<Value>>> {
         debug!(target: "walletdb::query_custom", "[WalletDb] Executing SQL query:\n{query}");
 
         // First we prepare the query
-        let Ok(conn) = self.conn.lock() else { return Err(WalletDbError::FailedToAquireLock) };
-        let Ok(mut stmt) = conn.prepare(query) else {
+        let conn = self.conn.lock().await;
+        let Ok(mut stmt) = conn.prepare(query).await else {
             return Err(WalletDbError::QueryPreparationFailed)
         };
 
         // Execute the query using provided converted params
-        let Ok(mut rows) = stmt.query(params) else {
+        let Ok(mut rows) = stmt.query(params).await else {
             return Err(WalletDbError::QueryExecutionFailed)
         };
 
@@ -307,7 +293,7 @@ impl WalletDb {
         let mut result = vec![];
         loop {
             // Check if an error occured
-            let row = match rows.next() {
+            let row = match rows.next().await {
                 Ok(r) => r,
                 Err(_) => return Err(WalletDbError::QueryExecutionFailed),
             };
@@ -322,7 +308,7 @@ impl WalletDb {
             let mut row_values = vec![];
             let mut idx = 0;
             loop {
-                let Ok(value) = row.get(idx) else { break };
+                let Ok(value) = row.get_value(idx) else { break };
                 row_values.push(value);
                 idx += 1;
             }
@@ -333,164 +319,209 @@ impl WalletDb {
     }
 }
 
-/// Custom implementation of rusqlite::named_params! to use `expr` instead of `literal` as `$param_name`,
-/// and append the ":" named parameters prefix.
+/// Custom implementation of `turso::params!` to construct positional
+/// params from a heterogeneous set of params types as a vec.
+#[macro_export]
+macro_rules! params {
+    () => {
+       ()
+    };
+    ($($value:expr),* $(,)?) => {
+        [$(turso::Value::from($value)),*].to_vec()
+
+    };
+}
+
+/// Custom implementation of `turso::named_params!` to construct named
+/// params from a heterogeneous set of params types as a vec.
+#[macro_export]
+macro_rules! named_params {
+    () => {
+        ()
+    };
+    ($($param_name:literal: $value:expr),* $(,)?) => {
+        [$((String::from($param_name), turso::Value::from($value))),*].to_vec()
+    };
+}
+
+/// Custom implementation of `turso::named_params!` to use `expr`
+/// instead of `literal` as `$param_name`, and append the ":" named
+/// parameters prefix.
 #[macro_export]
 macro_rules! convert_named_params {
     () => {
-        &[] as &[(&str, &dyn rusqlite::types::ToSql)]
+        ()
     };
-    ($(($param_name:expr, $param_val:expr)),+ $(,)?) => {
-        &[$((format!(":{}", $param_name).as_str(), &$param_val as &dyn rusqlite::types::ToSql)),+] as &[(&str, &dyn rusqlite::types::ToSql)]
+    ($(($param_name:expr, $value:expr)),* $(,)?) => {
+        [$((format!(":{}", $param_name), turso::Value::from($value))),*].to_vec()
     };
 }
 
 #[cfg(test)]
 mod tests {
-    use rusqlite::types::Value;
-
-    use crate::walletdb::WalletDb;
+    use crate::walletdb::{Value, WalletDb};
 
     #[test]
     fn test_mem_wallet() {
-        let wallet = WalletDb::new(None, Some("foobar")).unwrap();
-        wallet
-            .exec_batch_sql(
-                "CREATE TABLE mista ( numba INTEGER ); INSERT INTO mista ( numba ) VALUES ( 42 );",
-            )
-            .unwrap();
-
-        let ret = wallet.query_single("mista", &["numba"], &[]).unwrap();
-        assert_eq!(ret.len(), 1);
-        let numba: i64 = if let Value::Integer(numba) = ret[0] { numba } else { -1 };
-        assert_eq!(numba, 42);
-
-        let ret = wallet.query_custom("SELECT numba FROM mista;", &[]).unwrap();
-        assert_eq!(ret.len(), 1);
-        assert_eq!(ret[0].len(), 1);
-        let numba: i64 = if let Value::Integer(numba) = ret[0][0] { numba } else { -1 };
-        assert_eq!(numba, 42);
+        smol::block_on(async {
+            let wallet = WalletDb::new(None, Some("foobar")).await.unwrap();
+            wallet
+                .exec_batch_sql(
+                    "CREATE TABLE mista ( numba INTEGER ); INSERT INTO mista ( numba ) VALUES ( 42 );",
+                ).await
+                .unwrap();
+
+            let ret = wallet.query_single("mista", &["numba"], vec![]).await.unwrap();
+            assert_eq!(ret.len(), 1);
+            let numba: i64 = if let Value::Integer(numba) = ret[0] { numba } else { -1 };
+            assert_eq!(numba, 42);
+
+            let ret = wallet.query_custom("SELECT numba FROM mista;", vec![]).await.unwrap();
+            assert_eq!(ret.len(), 1);
+            assert_eq!(ret[0].len(), 1);
+            let numba: i64 = if let Value::Integer(numba) = ret[0][0] { numba } else { -1 };
+            assert_eq!(numba, 42);
+        })
     }
 
     #[test]
     fn test_query_single() {
-        let wallet = WalletDb::new(None, None).unwrap();
-        wallet
-            .exec_batch_sql("CREATE TABLE mista ( why INTEGER, are TEXT, you INTEGER, gae BLOB );")
-            .unwrap();
-
-        let why = 42;
-        let are = "are".to_string();
-        let you = 69;
-        let gae = vec![42u8; 32];
-
-        wallet
-            .exec_sql(
-                "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
-                rusqlite::params![why, are, you, gae],
-            )
-            .unwrap();
-
-        let ret = wallet.query_single("mista", &["why", "are", "you", "gae"], &[]).unwrap();
-        assert_eq!(ret.len(), 4);
-        assert_eq!(ret[0], Value::Integer(why));
-        assert_eq!(ret[1], Value::Text(are.clone()));
-        assert_eq!(ret[2], Value::Integer(you));
-        assert_eq!(ret[3], Value::Blob(gae.clone()));
-        let ret = wallet.query_custom("SELECT why, are, you, gae FROM mista;", &[]).unwrap();
-        assert_eq!(ret.len(), 1);
-        assert_eq!(ret[0].len(), 4);
-        assert_eq!(ret[0][0], Value::Integer(why));
-        assert_eq!(ret[0][1], Value::Text(are.clone()));
-        assert_eq!(ret[0][2], Value::Integer(you));
-        assert_eq!(ret[0][3], Value::Blob(gae.clone()));
-
-        let ret = wallet
-            .query_single(
-                "mista",
-                &["gae"],
-                rusqlite::named_params! {":why": why, ":are": are, ":you": you},
-            )
-            .unwrap();
-        assert_eq!(ret.len(), 1);
-        assert_eq!(ret[0], Value::Blob(gae.clone()));
-        let ret = wallet
-            .query_custom(
-                "SELECT gae FROM mista WHERE why = ?1 AND are = ?2 AND you = ?3;",
-                rusqlite::params![why, are, you],
-            )
-            .unwrap();
-        assert_eq!(ret.len(), 1);
-        assert_eq!(ret[0].len(), 1);
-        assert_eq!(ret[0][0], Value::Blob(gae));
+        smol::block_on(async {
+            let wallet = WalletDb::new(None, None).await.unwrap();
+            wallet
+                .exec_batch_sql(
+                    "CREATE TABLE mista ( why INTEGER, are TEXT, you INTEGER, gae BLOB );",
+                )
+                .await
+                .unwrap();
+
+            let why = 42;
+            let are = "are".to_string();
+            let you = 69;
+            let gae = vec![42u8; 32];
+
+            wallet
+                .exec_sql(
+                    "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
+                    params![why, are.clone(), you, gae.clone()],
+                )
+                .await
+                .unwrap();
+
+            let ret =
+                wallet.query_single("mista", &["why", "are", "you", "gae"], vec![]).await.unwrap();
+            assert_eq!(ret.len(), 4);
+            assert_eq!(ret[0], Value::Integer(why));
+            assert_eq!(ret[1], Value::Text(are.clone()));
+            assert_eq!(ret[2], Value::Integer(you));
+            assert_eq!(ret[3], Value::Blob(gae.clone()));
+            let ret =
+                wallet.query_custom("SELECT why, are, you, gae FROM mista;", vec![]).await.unwrap();
+            assert_eq!(ret.len(), 1);
+            assert_eq!(ret[0].len(), 4);
+            assert_eq!(ret[0][0], Value::Integer(why));
+            assert_eq!(ret[0][1], Value::Text(are.clone()));
+            assert_eq!(ret[0][2], Value::Integer(you));
+            assert_eq!(ret[0][3], Value::Blob(gae.clone()));
+
+            let ret = wallet
+                .query_single(
+                    "mista",
+                    &["gae"],
+                    named_params! {":why": why, ":are": are.clone(), ":you": you},
+                )
+                .await
+                .unwrap();
+            assert_eq!(ret.len(), 1);
+            assert_eq!(ret[0], Value::Blob(gae.clone()));
+            let ret = wallet
+                .query_custom(
+                    "SELECT gae FROM mista WHERE why = ?1 AND are = ?2 AND you = ?3;",
+                    params![why, are, you],
+                )
+                .await
+                .unwrap();
+            assert_eq!(ret.len(), 1);
+            assert_eq!(ret[0].len(), 1);
+            assert_eq!(ret[0][0], Value::Blob(gae));
+        })
     }
 
     #[test]
     fn test_query_multi() {
-        let wallet = WalletDb::new(None, None).unwrap();
-        wallet
-            .exec_batch_sql("CREATE TABLE mista ( why INTEGER, are TEXT, you INTEGER, gae BLOB );")
-            .unwrap();
-
-        let why = 42;
-        let are = "are".to_string();
-        let you = 69;
-        let gae = vec![42u8; 32];
-
-        wallet
-            .exec_sql(
-                "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
-                rusqlite::params![why, are, you, gae],
-            )
-            .unwrap();
-        wallet
-            .exec_sql(
-                "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
-                rusqlite::params![why, are, you, gae],
-            )
-            .unwrap();
-
-        let ret = wallet.query_multiple("mista", &[], &[]).unwrap();
-        assert_eq!(ret.len(), 2);
-        for row in ret {
-            assert_eq!(row.len(), 4);
-            assert_eq!(row[0], Value::Integer(why));
-            assert_eq!(row[1], Value::Text(are.clone()));
-            assert_eq!(row[2], Value::Integer(you));
-            assert_eq!(row[3], Value::Blob(gae.clone()));
-        }
-        let ret = wallet.query_custom("SELECT * FROM mista;", &[]).unwrap();
-        assert_eq!(ret.len(), 2);
-        for row in ret {
-            assert_eq!(row.len(), 4);
-            assert_eq!(row[0], Value::Integer(why));
-            assert_eq!(row[1], Value::Text(are.clone()));
-            assert_eq!(row[2], Value::Integer(you));
-            assert_eq!(row[3], Value::Blob(gae.clone()));
-        }
+        smol::block_on(async {
+            let wallet = WalletDb::new(None, None).await.unwrap();
+            wallet
+                .exec_batch_sql(
+                    "CREATE TABLE mista ( why INTEGER, are TEXT, you INTEGER, gae BLOB );",
+                )
+                .await
+                .unwrap();
+
+            let why = 42;
+            let are = "are".to_string();
+            let you = 69;
+            let gae = vec![42u8; 32];
+
+            wallet
+                .exec_sql(
+                    "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
+                    params![why, are.clone(), you, gae.clone()],
+                )
+                .await
+                .unwrap();
+            wallet
+                .exec_sql(
+                    "INSERT INTO mista ( why, are, you, gae ) VALUES (?1, ?2, ?3, ?4);",
+                    params![why, are.clone(), you, gae.clone()],
+                )
+                .await
+                .unwrap();
+
+            let ret = wallet.query_multiple("mista", &[], vec![]).await.unwrap();
+            assert_eq!(ret.len(), 2);
+            for row in ret {
+                assert_eq!(row.len(), 4);
+                assert_eq!(row[0], Value::Integer(why));
+                assert_eq!(row[1], Value::Text(are.clone()));
+                assert_eq!(row[2], Value::Integer(you));
+                assert_eq!(row[3], Value::Blob(gae.clone()));
+            }
+            let ret = wallet.query_custom("SELECT * FROM mista;", vec![]).await.unwrap();
+            assert_eq!(ret.len(), 2);
+            for row in ret {
+                assert_eq!(row.len(), 4);
+                assert_eq!(row[0], Value::Integer(why));
+                assert_eq!(row[1], Value::Text(are.clone()));
+                assert_eq!(row[2], Value::Integer(you));
+                assert_eq!(row[3], Value::Blob(gae.clone()));
+            }
 
-        let ret = wallet
-            .query_multiple(
-                "mista",
-                &["gae"],
-                convert_named_params! {("why", why), ("are", are), ("you", you)},
-            )
-            .unwrap();
-        assert_eq!(ret.len(), 2);
-        for row in ret {
-            assert_eq!(row.len(), 1);
-            assert_eq!(row[0], Value::Blob(gae.clone()));
-        }
-        let ret = wallet
-            .query_custom(
-                "SELECT gae FROM mista WHERE why = ?1 AND are = ?2 AND you = ?3;",
-                rusqlite::params![why, are, you],
-            )
-            .unwrap();
-        assert_eq!(ret.len(), 2);
-        for row in ret {
-            assert_eq!(row.len(), 1);
-            assert_eq!(row[0], Value::Blob(gae.clone()));
-        }
+            let ret = wallet
+                .query_multiple(
+                    "mista",
+                    &["gae"],
+                    convert_named_params! {("why", why), ("are", are.clone()), ("you", you)},
+                )
+                .await
+                .unwrap();
+            assert_eq!(ret.len(), 2);
+            for row in ret {
+                assert_eq!(row.len(), 1);
+                assert_eq!(row[0], Value::Blob(gae.clone()));
+            }
+            let ret = wallet
+                .query_custom(
+                    "SELECT gae FROM mista WHERE why = ?1 AND are = ?2 AND you = ?3;",
+                    params![why, are, you],
+                )
+                .await
+                .unwrap();
+            assert_eq!(ret.len(), 2);
+            for row in ret {
+                assert_eq!(row.len(), 1);
+                assert_eq!(row[0], Value::Blob(gae.clone()));
+            }
+        })
     }
 }