]> Untitled Git - bdk-cli/commitdiff
refactor(main): add runtime wallet module
authorVihiga Tyonum <withtvpeter@gmail.com>
Sun, 31 May 2026 11:00:52 +0000 (12:00 +0100)
committerVihiga Tyonum <withtvpeter@gmail.com>
Fri, 5 Jun 2026 16:32:15 +0000 (17:32 +0100)
- add wallet runtime module to serve as context
manager
- fix clippy errors

14 files changed:
src/client.rs
src/commands.rs
src/error.rs
src/handlers/mod.rs
src/handlers/offline.rs
src/handlers/online.rs
src/handlers/repl.rs
src/main.rs
src/persister.rs
src/utils/common.rs
src/utils/mod.rs
src/utils/runtime.rs [new file with mode: 0644]
src/utils/types.rs
tests/integration.rs

index c90aab2e2d02825fa8d8dc1f73ce5de4fe4dbe03..ad51391e7c93cdff0f29712f78af6a9900361c5c 100644 (file)
@@ -1,5 +1,3 @@
-#[cfg(feature = "rpc")]
-use bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi};
 #[cfg(feature = "esplora")]
 use bdk_esplora::EsploraAsyncExt;
 #[cfg(any(
@@ -14,11 +12,15 @@ use {
     bdk_wallet::{
         Wallet,
         bitcoin::{Transaction, Txid},
-        chain::CanonicalizationParams,
     },
     clap::ValueEnum,
     std::path::PathBuf,
 };
+#[cfg(feature = "rpc")]
+use {
+    bdk_bitcoind_rpc::{Emitter, bitcoincore_rpc::RpcApi},
+    bdk_wallet::chain::CanonicalizationParams,
+};
 
 #[cfg(feature = "cbf")]
 use {
@@ -79,7 +81,7 @@ pub(crate) enum BlockchainClient {
 impl BlockchainClient {
     pub async fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
         match self {
-            // #[cfg(feature = "electrum")]
+            #[cfg(feature = "electrum")]
             Self::Electrum { client, .. } => client
                 .transaction_broadcast(&tx)
                 .map_err(|e| Error::Generic(e.to_string())),
index 226e447b98cfc03a60dfb2dfcc3d11d0e19da980..cc4e121b2dfdd0192ded807ba24b1ac425e78eb1 100644 (file)
@@ -116,7 +116,7 @@ pub enum CliSubCommand {
     #[cfg(feature = "compiler")]
     #[clap(long_about = "Miniscript policy compiler")]
     Compile(CompileCommand),
-    // #[cfg(feature = "repl")]
+    #[cfg(feature = "repl")]
     /// REPL command loop mode.
     ///
     /// REPL command loop can be used to make recurring callbacks to an already loaded wallet.
index 3019e5caae3ad3064294458ed32dc785dc44df0c..1d5fd82f19c40fa839d06a06e3e945e0dbe65dab 100644 (file)
@@ -61,7 +61,7 @@ pub enum BDKCliError {
     #[error("PsbtError: {0}")]
     PsbtError(#[from] bdk_wallet::bitcoin::psbt::Error),
 
-    // #[cfg(feature = "sqlite")]
+    #[cfg(feature = "sqlite")]
     #[error("Rusqlite error: {0}")]
     RusqliteError(Box<bdk_wallet::rusqlite::Error>),
 
index d63ec3b554723ee10d8143d0230da8f155291a4f..6e2433909062150ccc7c0031bcd7d1fd34615d6b 100644 (file)
@@ -102,12 +102,6 @@ pub trait AppCommand<C> {
 ))]
 pub trait AsyncAppCommand<C> {
     type Output: FormatOutput;
-    
+
     async fn execute(&self, ctx: &mut C) -> Result<Self::Output, Error>;
 }
-
-// context for online and online
-// => cli.rs
-// handlers/{mod for commands}
-// wallet subdir /
-// wallet-offline and wallet-online (client mod)
index c8bb18fb7dd7e26790b54d50d5294a99da70e348..d45a772538660dc98a1a7c274b08e49e9fb9686e 100644 (file)
@@ -522,7 +522,7 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for CombinePsbtCommand {
     }
 }
 
-// #[cfg(feature = "bip322")]
+#[cfg(feature = "bip322")]
 #[derive(Debug, Parser, Clone, PartialEq)]
 pub struct SignMessageCommand {
     /// The message to sign
@@ -572,7 +572,7 @@ impl AppCommand<AppContext<OfflineOperations<'_>>> for SignMessageCommand {
     }
 }
 
-// #[cfg(feature = "bip322")]
+#[cfg(feature = "bip322")]
 #[derive(Debug, Parser, Clone, PartialEq)]
 pub struct VerifyMessageCommand {
     /// The signature proof to verify
index 0c44c34218e57ac39565bbc070c820849e3b00ab..adb6268e56582db2b527a15eb0dceab040d53c79 100644 (file)
@@ -170,7 +170,9 @@ impl AsyncAppCommand<AppContext<OnlineOperations<'_>>> for FullScanCommand {
                 sync_kyoto_client(wallet, client).await?;
             }
         }
-        Ok(StatusResult::new("Full scan completed successfully."))
+        Ok(StatusResult {
+            message: "Full scan completed successfully.".to_string(),
+        })
     }
 }
 
@@ -190,7 +192,7 @@ impl AsyncAppCommand<AppContext<OnlineOperations<'_>>> for SyncCommand {
         &self,
         ctx: &mut AppContext<OnlineOperations<'_>>,
     ) -> Result<Self::Output, Error> {
-        let mut wallet = &mut ctx.state.wallet;
+        let wallet = &mut ctx.state.wallet;
         let client = ctx.state.client;
         #[cfg(any(feature = "electrum", feature = "esplora"))]
         let request = wallet
@@ -267,12 +269,14 @@ impl AsyncAppCommand<AppContext<OnlineOperations<'_>>> for SyncCommand {
                 let mempool_txs = emitter.mempool()?;
                 wallet.apply_unconfirmed_txs(mempool_txs.update);
             }
-            // #[cfg(feature = "cbf")]
-            KyotoClient { client } => sync_kyoto_client(&mut wallet, client)
+            #[cfg(feature = "cbf")]
+            KyotoClient { client } => sync_kyoto_client(wallet, client)
                 .await
                 .map_err(|e| Error::Generic(e.to_string()))?,
         }
-        Ok(StatusResult::new("Wallet synced successfully."))
+        Ok(StatusResult {
+            message: "Wallet synced successfully.".to_string(),
+        })
     }
 }
 
@@ -321,7 +325,7 @@ impl AsyncAppCommand<AppContext<OnlineOperations<'_>>> for BroadcastCommand {
                 psbt.extract_tx()?
             }
             (None, Some(tx)) => {
-                let tx_bytes = Vec::<u8>::from_hex(&tx)?;
+                let tx_bytes = Vec::<u8>::from_hex(tx)?;
                 Transaction::consensus_decode(&mut tx_bytes.as_slice())?
             }
             (Some(_), Some(_)) => {
index 802e7358ad10f87db97554522c55b379fd1c8412..977e819a9bb02c7dd8d522c2d87372395a5f5d87 100644 (file)
@@ -1,13 +1,11 @@
-use bdk_wallet::{Wallet, bitcoin::Network};
-
-#[cfg(feature = "repl")]
-use crate::handlers::AppCommand;
-#[cfg(feature = "repl")]
-use crate::{handlers::AppContext, utils::output::FormatOutput};
-
 #[cfg(feature = "repl")]
-use crate::commands::ReplSubCommand;
-use clap::Parser;
+use {
+    crate::commands::ReplSubCommand,
+    crate::handlers::{AppCommand, AppContext},
+    crate::utils::output::FormatOutput,
+    bdk_wallet::{Wallet, bitcoin::Network},
+    clap::Parser,
+};
 
 #[cfg(any(
     feature = "electrum",
@@ -17,11 +15,7 @@ use clap::Parser;
 ))]
 use crate::client::BlockchainClient;
 #[cfg(feature = "repl")]
-use std::io::Write;
-use {
-    crate::commands::{CliOpts, WalletSubCommand},
-    crate::error::BDKCliError as Error,
-};
+use {crate::commands::WalletSubCommand, crate::error::BDKCliError as Error, std::io::Write};
 
 #[cfg(feature = "repl")]
 pub(crate) async fn respond(
@@ -36,7 +30,6 @@ pub(crate) async fn respond(
     client: Option<&BlockchainClient>,
     line: &str,
     datadir: std::path::PathBuf,
-    _cli_opts: &CliOpts,
 ) -> Result<bool, String> {
     let args = shlex::split(line).ok_or("error: Invalid quoting".to_string())?;
 
index 1d661223eb9c9ab94b5ff80c1b395c9feead193a..d3cac7f6e25c158d9e9747c094c61856cf934efc 100644 (file)
@@ -25,26 +25,15 @@ mod payjoin;
 mod persister;
 mod utils;
 
-#[cfg(feature = "redb")]
-use bdk_redb::Store as RedbStore;
 use bdk_wallet::bitcoin::Network;
 use log::{debug, warn};
 
-#[cfg(any(
-    feature = "electrum",
-    feature = "esplora",
-    feature = "rpc",
-    feature = "cbf"
-))]
-use crate::client::new_blockchain_client;
 use crate::commands::{CliOpts, CliSubCommand, WalletSubCommand};
 use crate::error::BDKCliError as Error;
 use crate::handlers::{AppCommand, AppContext};
-#[cfg(any(feature = "sqlite", feature = "redb"))]
-use crate::persister::{Persister, new_persisted_wallet};
 use crate::utils::output::FormatOutput;
-use crate::utils::prepare_wallet_db_dir;
-use crate::utils::{load_wallet_config, prepare_home_dir};
+use crate::utils::runtime::WalletRuntime;
+use crate::utils::{command_requires_db, prepare_home_dir};
 use clap::Parser;
 
 #[tokio::main]
@@ -81,70 +70,36 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
                 feature = "rpc",
                 feature = "cbf"
             ))]
-            WalletSubCommand::OnlineWalletSubCommand(online_cmd) => {
-                let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
-
-                let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
-                #[cfg(any(feature = "sqlite", feature = "redb"))]
-                let mut persister: Persister = match &wallet_opts.database_type {
-                    #[cfg(feature = "sqlite")]
-                    crate::persister::DatabaseType::Sqlite => {
-                        let db_file = database_path.join("wallet.sqlite");
-                        let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
-                        Persister::Connection(connection)
-                    }
-                    #[cfg(feature = "redb")]
-                    crate::persister::DatabaseType::Redb => {
-                        use crate::persister::Persister;
-
-                        let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
-                            home_dir.join("wallet.redb"),
-                        )?);
-                        let store = RedbStore::new(db, wallet_name)?;
-                        log::debug!("Redb database opened successfully");
-                        Persister::RedbStore(store)
-                    }
-                };
-
-                let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
-
-                let client = new_blockchain_client(&wallet_opts, &wallet, database_path)?;
-
-                let mut ctx =
-                    AppContext::new_online_wallet(network, home_dir, &mut wallet, &client);
-
-                online_cmd.execute(&mut ctx).await?;
+            WalletSubCommand::OnlineWalletSubCommand(cmd) => {
+                let runtime = WalletRuntime::load(&home_dir, &wallet_name)?;
+
+                let mut wallet = runtime.build_wallet(true)?;
+                let client = runtime.build_client(&wallet)?;
+
+                let mut ctx = AppContext::new_online_wallet(
+                    runtime.network,
+                    runtime.home_dir.clone(),
+                    &mut wallet,
+                    &client,
+                );
+
+                cmd.execute(&mut ctx).await?;
             }
-            WalletSubCommand::OfflineWalletSubCommand(offline_cmd) => {
-                let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
-
-                let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
-
-                #[cfg(any(feature = "sqlite", feature = "redb"))]
-                let mut persister: Persister = match &wallet_opts.database_type {
-                    #[cfg(feature = "sqlite")]
-                    crate::persister::DatabaseType::Sqlite => {
-                        let db_file = database_path.join("wallet.sqlite");
-                        let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
-                        Persister::Connection(connection)
-                    }
-                    #[cfg(feature = "redb")]
-                    crate::persister::DatabaseType::Redb => {
-                        use crate::persister::Persister;
-                        let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
-                            home_dir.join("wallet.redb"),
-                        )?);
-                        let store = RedbStore::new(db, wallet_name)?;
-                        Persister::RedbStore(store)
-                    }
-                };
-
-                let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
-
-                let mut ctx = AppContext::new_offline_wallet(network, home_dir, &mut wallet);
-
-                offline_cmd.execute(&mut ctx)?;
+
+            WalletSubCommand::OfflineWalletSubCommand(cmd) => {
+                let runtime = WalletRuntime::load(&home_dir, &wallet_name)?;
+
+                let mut wallet = runtime.build_wallet(command_requires_db(&cmd))?;
+
+                let mut ctx = AppContext::new_offline_wallet(
+                    runtime.network,
+                    runtime.home_dir.clone(),
+                    &mut wallet,
+                );
+
+                cmd.execute(&mut ctx)?;
             }
+
             WalletSubCommand::Config(mut config_cmd) => {
                 config_cmd.wallet_opts.wallet = Some(wallet_name);
 
@@ -156,107 +111,81 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
 
         CliSubCommand::Key { subcommand } => {
             let mut ctx = AppContext::new(cli_opts.network, home_dir);
+
             subcommand.execute(&mut ctx)?;
         }
-        CliSubCommand::Descriptor(descriptor_command) => {
+
+        CliSubCommand::Descriptor(cmd) => {
             let mut ctx = AppContext::new(cli_opts.network, home_dir);
-            descriptor_command
-                .execute(&mut ctx)?
-                .write_out(std::io::stdout())?;
+
+            cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
         }
+
         CliSubCommand::Wallets(cmd) => {
             let mut ctx = AppContext::new(cli_opts.network, home_dir);
+
             cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
         }
+
+        #[cfg(feature = "repl")]
         CliSubCommand::Repl {
             wallet: wallet_name,
         } => {
-            #[cfg(feature = "repl")]
-            {
-                let (wallet_opts, network) = load_wallet_config(&home_dir, &wallet_name)?;
-                let database_path = prepare_wallet_db_dir(&home_dir, &wallet_name)?;
-
-                #[cfg(any(feature = "sqlite", feature = "redb"))]
-                let mut persister: Persister = match &wallet_opts.database_type {
-                    #[cfg(feature = "sqlite")]
-                    crate::persister::DatabaseType::Sqlite => {
-                        let db_file = database_path.join("wallet.sqlite");
-                        let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
-                        Persister::Connection(connection)
-                    }
-                    #[cfg(feature = "redb")]
-                    crate::persister::DatabaseType::Redb => {
-                        use crate::persister::Persister;
-                        let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
-                            home_dir.join("wallet.redb"),
-                        )?);
-                        let store = RedbStore::new(db, wallet_name.clone())?;
-                        Persister::RedbStore(store)
-                    }
-                };
-
-                let mut wallet = new_persisted_wallet(network, &mut persister, &wallet_opts)?;
-
-                #[cfg(any(
-                    feature = "electrum",
-                    feature = "esplora",
-                    feature = "rpc",
-                    feature = "cbf"
-                ))]
-                let client = Some(new_blockchain_client(&wallet_opts, &wallet, database_path)?);
-
-                println!(
-                    "Entering REPL mode for wallet '{}'. Type 'exit' to quit.",
-                    wallet_name
-                );
+            let runtime = WalletRuntime::load(&home_dir, &wallet_name)?;
 
-                loop {
-                    let line = crate::handlers::repl::readline()?;
-                    if line.trim().is_empty() {
-                        continue;
-                    }
-
-                    // Pass it to our newly refactored respond function
-                    let should_exit = crate::handlers::repl::respond(
-                        network,
-                        &mut wallet,
-                        #[cfg(any(
-                            feature = "electrum",
-                            feature = "esplora",
-                            feature = "rpc",
-                            feature = "cbf"
-                        ))]
-                        client.as_ref(), 
-                        &line,
-                        home_dir.clone(),
-                        &cli_opts,
-                    )
-                    .await
-                    .map_err(Error::Generic)?; 
-
-                    // Break the loop if the user typed `exit`
-                    if should_exit {
-                        break;
-                    }
+            let mut wallet = runtime.build_wallet(true)?;
+
+            #[cfg(any(
+                feature = "electrum",
+                feature = "esplora",
+                feature = "rpc",
+                feature = "cbf"
+            ))]
+            let client = runtime.build_client(&wallet).ok();
+
+            println!(
+                "Entering REPL mode for wallet '{}'. \
+                     Type 'exit' to quit.",
+                wallet_name
+            );
+
+            loop {
+                let line = crate::handlers::repl::readline()?;
+
+                if line.trim().is_empty() {
+                    continue;
                 }
-            }
 
-            #[cfg(not(feature = "repl"))]
-            {
-                return Err(Error::Generic(
-                    "The 'repl' feature is not enabled in this build.".into(),
-                ));
+                let should_exit = crate::handlers::repl::respond(
+                    runtime.network,
+                    &mut wallet,
+                    #[cfg(any(
+                        feature = "electrum",
+                        feature = "esplora",
+                        feature = "rpc",
+                        feature = "cbf"
+                    ))]
+                    client.as_ref(),
+                    &line,
+                    runtime.home_dir.clone(),
+                )
+                .await
+                .map_err(Error::Generic)?;
+
+                if should_exit {
+                    break;
+                }
             }
         }
-        CliSubCommand::Completions { shell } => {
-            shell;
-        }
+
         #[cfg(feature = "compiler")]
         CliSubCommand::Compile(cmd) => {
             let mut ctx = AppContext::new(cli_opts.network, home_dir);
+
             cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
         }
-    };
+        CliSubCommand::Completions { shell: _ } => unimplemented!(),
+    }
 
     Ok(())
 }
index 2a17db1b73d5482782dab3af3467dcf547bc139c..564000fef0c0f2bbfa04fe051f43a78a29099944 100644 (file)
@@ -1,9 +1,9 @@
-#[cfg(any(feature = "sqlite", feature = "redb"))]
 use crate::commands::WalletOpts;
 use crate::error::BDKCliError as Error;
+use bdk_wallet::Wallet;
+use bdk_wallet::bitcoin::Network;
 #[cfg(any(feature = "sqlite", feature = "redb"))]
-use bdk_wallet::{KeychainKind, PersistedWallet, bitcoin::Network};
-use bdk_wallet::{Wallet, WalletPersister};
+use bdk_wallet::{KeychainKind, PersistedWallet, WalletPersister};
 use clap::ValueEnum;
 
 #[derive(Clone, ValueEnum, Debug, Eq, PartialEq)]
@@ -25,6 +25,7 @@ pub(crate) enum Persister {
     RedbStore(bdk_redb::Store),
 }
 
+#[cfg(any(feature = "sqlite", feature = "redb"))]
 impl WalletPersister for Persister {
     type Error = Error;
 
@@ -97,7 +98,6 @@ where
     Ok(wallet)
 }
 
-#[cfg(not(any(feature = "sqlite", feature = "redb")))]
 pub(crate) fn new_wallet(network: Network, wallet_opts: &WalletOpts) -> Result<Wallet, Error> {
     let ext_descriptor = wallet_opts.ext_descriptor.clone();
     let int_descriptor = wallet_opts.int_descriptor.clone();
index 7783463b70c49b3879ac52da4f2cf974f208d4e2..43ff5d85cb5116e7f2f78390639ab62db471ae88 100644 (file)
@@ -14,6 +14,7 @@ use bdk_wallet::bitcoin::{Address, Network, OutPoint, ScriptBuf};
 #[cfg(feature = "silent-payments")]
 use bdk_sp::encoding::SilentPaymentCode;
 
+use crate::commands::OfflineWalletSubCommand;
 use std::{
     path::{Path, PathBuf},
     str::FromStr,
@@ -217,3 +218,28 @@ pub(crate) fn parse_signature_format(format_str: &str) -> Result<SignatureFormat
         )),
     }
 }
+
+pub fn command_requires_db(command: &OfflineWalletSubCommand) -> bool {
+    match command {
+        OfflineWalletSubCommand::Balance(_)
+        | OfflineWalletSubCommand::Unspent(_)
+        | OfflineWalletSubCommand::Transactions(_)
+        | OfflineWalletSubCommand::BumpFee(_) => true,
+
+        OfflineWalletSubCommand::NewAddress(_)
+        | OfflineWalletSubCommand::UnusedAddress(_)
+        | OfflineWalletSubCommand::CreateTx(_)
+        | OfflineWalletSubCommand::Policies(_)
+        | OfflineWalletSubCommand::PublicDescriptor(_)
+        | OfflineWalletSubCommand::Sign(_)
+        | OfflineWalletSubCommand::ExtractPsbt(_)
+        | OfflineWalletSubCommand::FinalizePsbt(_)
+        | OfflineWalletSubCommand::CombinePsbt(_) => false,
+
+        #[cfg(feature = "bip322")]
+        OfflineWalletSubCommand::SignMessage(_) => true,
+
+        #[cfg(feature = "bip322")]
+        OfflineWalletSubCommand::VerifyMessage(_) => false,
+    }
+}
index afd02f9ab712ab488e37bdf088a795ad7bc05181..084cab52efa86468db6034eab3d7175aa9ac6158 100644 (file)
@@ -2,4 +2,5 @@ pub mod common;
 pub mod descriptors;
 pub mod output;
 pub use common::*;
+pub mod runtime;
 pub mod types;
diff --git a/src/utils/runtime.rs b/src/utils/runtime.rs
new file mode 100644 (file)
index 0000000..2bf6ec1
--- /dev/null
@@ -0,0 +1,137 @@
+#[cfg(feature = "redb")]
+use bdk_redb::Store as RedbStore;
+use bdk_wallet::{Wallet, bitcoin::Network};
+use std::{
+    ops::{Deref, DerefMut},
+    path::{Path, PathBuf},
+};
+
+use crate::{
+    error::BDKCliError as Error,
+    persister::new_wallet,
+    utils::{load_wallet_config, prepare_wallet_db_dir},
+};
+#[cfg(any(feature = "sqlite", feature = "redb"))]
+use {
+    crate::persister::{DatabaseType, Persister, new_persisted_wallet},
+    bdk_wallet::PersistedWallet,
+};
+
+#[cfg(any(
+    feature = "electrum",
+    feature = "esplora",
+    feature = "rpc",
+    feature = "cbf"
+))]
+use crate::client::{BlockchainClient, new_blockchain_client};
+
+pub enum RuntimeWallet {
+    Standard(Wallet),
+    #[cfg(any(feature = "sqlite", feature = "redb"))]
+    Persisted(PersistedWallet<Persister>),
+}
+
+impl Deref for RuntimeWallet {
+    type Target = Wallet;
+    fn deref(&self) -> &Self::Target {
+        match self {
+            Self::Standard(wallet) => wallet,
+            #[cfg(any(feature = "sqlite", feature = "redb"))]
+            Self::Persisted(wallet) => wallet,
+        }
+    }
+}
+
+impl DerefMut for RuntimeWallet {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        match self {
+            Self::Standard(wallet) => wallet,
+            #[cfg(any(feature = "sqlite", feature = "redb"))]
+            Self::Persisted(wallet) => wallet,
+        }
+    }
+}
+
+#[allow(unused)]
+pub struct WalletRuntime {
+    pub wallet_name: String,
+    pub wallet_opts: crate::commands::WalletOpts,
+    pub network: Network,
+    pub home_dir: PathBuf,
+    pub database_path: PathBuf,
+}
+
+impl WalletRuntime {
+    pub fn load(home_dir: &Path, wallet_name: &str) -> Result<Self, Error> {
+        let (wallet_opts, network) = load_wallet_config(home_dir, wallet_name)?;
+
+        let database_path = prepare_wallet_db_dir(home_dir, wallet_name)?;
+
+        Ok(Self {
+            wallet_name: wallet_name.to_string(),
+            wallet_opts,
+            network,
+            home_dir: home_dir.to_path_buf(),
+            database_path,
+        })
+    }
+
+    pub fn build_wallet(&self, require_db: bool) -> Result<RuntimeWallet, Error> {
+        if !require_db {
+            return Ok(RuntimeWallet::Standard(new_wallet(
+                self.network,
+                &self.wallet_opts,
+            )?));
+        }
+
+        #[cfg(any(feature = "sqlite", feature = "redb"))]
+        {
+            let mut persister = self.create_persister()?;
+            let wallet = new_persisted_wallet(self.network, &mut persister, &self.wallet_opts)?;
+            Ok(RuntimeWallet::Persisted(wallet))
+        }
+
+        #[cfg(not(any(feature = "sqlite", feature = "redb")))]
+        {
+            Ok(RuntimeWallet::Standard(new_wallet(
+                self.network,
+                &self.wallet_opts,
+            )?))
+        }
+    }
+
+    #[cfg(any(
+        feature = "electrum",
+        feature = "esplora",
+        feature = "rpc",
+        feature = "cbf"
+    ))]
+    pub fn build_client(&self, wallet: &Wallet) -> Result<BlockchainClient, Error> {
+        new_blockchain_client(&self.wallet_opts, wallet, self.database_path.clone())
+    }
+
+    #[cfg(any(feature = "sqlite", feature = "redb"))]
+    fn create_persister(&self) -> Result<Persister, Error> {
+        match &self.wallet_opts.database_type {
+            #[cfg(feature = "sqlite")]
+            DatabaseType::Sqlite => {
+                let db_file = self.database_path.join("wallet.sqlite");
+
+                let connection = bdk_wallet::rusqlite::Connection::open(db_file)?;
+
+                Ok(Persister::Connection(connection))
+            }
+
+            #[cfg(feature = "redb")]
+            DatabaseType::Redb => {
+                let db = std::sync::Arc::new(bdk_redb::redb::Database::create(
+                    self.home_dir.join("wallet.redb"),
+                )?);
+
+                let store = RedbStore::new(db, self.wallet_name.clone())?;
+
+                Ok(Persister::RedbStore(store))
+            }
+        }
+    }
+}
index 2ed11ae19918b9cdd20e6489415b00b3f40437b2..a8e29984c1f2af500d18dca1fe6cd0470b64b9b8 100644 (file)
@@ -25,6 +25,7 @@ impl From<AddressInfo> for AddressResult {
     }
 }
 
+#[allow(unused)]
 /// Represents the data for a single transaction
 #[derive(Serialize)]
 pub struct TransactionDetails {
@@ -133,14 +134,6 @@ pub struct StatusResult {
     pub message: String,
 }
 
-impl StatusResult {
-    pub fn new(msg: &str) -> Self {
-        Self {
-            message: msg.to_string(),
-        }
-    }
-}
-
 #[cfg(any(
     feature = "electrum",
     feature = "esplora",
index a45cf8aa2236e0d201af5f419fbfee2189a1d627..5e35181184598bd2fa2e859a2af0a8457d80a5d9 100644 (file)
@@ -245,15 +245,4 @@ mod test {
         assert_eq!(confirmed_balance, 1000000000u64);
     }
 
-    // #[test]
-    // #[cfg(feature = "regtest-bitcoin")]
-    // fn test_basic_wallet_op_bitcoind() {
-    //     basic_wallet_ops("regtest-bitcoin")
-    // }
-    //
-    // #[test]
-    // #[cfg(feature = "regtest-electrum")]
-    // fn test_basic_wallet_op_electrum() {
-    //     basic_wallet_ops("regtest-electrum")
-    // }
 }