From f50ecdb7e7bb829e97f5fceaa7c61a1d0f6ce011 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Mon, 19 Dec 2022 12:30:41 -0500 Subject: [PATCH] Refactor: separate wallet struct from lib.rs --- bdk-ffi/src/lib.rs | 114 +++--------------------------------------- bdk-ffi/src/wallet.rs | 113 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 108 deletions(-) create mode 100644 bdk-ffi/src/wallet.rs diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 6ffb6a4..daa076f 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -1,3 +1,7 @@ +mod wallet; +mod psbt; + +use crate::wallet::Wallet; use bdk::bitcoin::blockdata::script::Script as BdkScript; use bdk::bitcoin::hashes::hex::ToHex; use bdk::bitcoin::secp256k1::Secp256k1; @@ -15,8 +19,7 @@ use bdk::blockchain::{ rpc::RpcConfig as BdkRpcConfig, rpc::RpcSyncParams as BdkRpcSyncParams, ConfigurableBlockchain, }; use bdk::blockchain::{Blockchain as BdkBlockchain, Progress as BdkProgress}; -use bdk::database::any::{AnyDatabase, SledDbConfiguration, SqliteDbConfiguration}; -use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase}; +use bdk::database::any::{SledDbConfiguration, SqliteDbConfiguration}; use bdk::descriptor::{DescriptorXKey, ExtendedDescriptor, IntoWalletDescriptor}; use bdk::keys::bip39::{Language, Mnemonic as BdkMnemonic, WordCount}; use bdk::keys::{ @@ -32,10 +35,7 @@ use bdk::template::{ use bdk::wallet::tx_builder::ChangeSpendPolicy; use bdk::wallet::AddressIndex as BdkAddressIndex; use bdk::wallet::AddressInfo as BdkAddressInfo; -use bdk::{ - Balance as BdkBalance, BlockTime, Error as BdkError, FeeRate, KeychainKind, SignOptions, - SyncOptions as BdkSyncOptions, Wallet as BdkWallet, -}; +use bdk::{Balance as BdkBalance, BlockTime, Error as BdkError, FeeRate, KeychainKind}; use std::collections::HashSet; use std::convert::{From, TryFrom}; use std::fmt; @@ -498,108 +498,6 @@ impl PartiallySignedTransaction { } } -#[derive(Debug)] -struct Wallet { - wallet_mutex: Mutex>, -} - -/// A Bitcoin wallet. -/// The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are: -/// 1. Output descriptors from which it can derive addresses. -/// 2. A Database where it tracks transactions and utxos related to the descriptors. -/// 3. Signers that can contribute signatures to addresses instantiated from the descriptors. -impl Wallet { - fn new( - descriptor: Arc, - change_descriptor: Option>, - network: Network, - database_config: DatabaseConfig, - ) -> Result { - let any_database_config = match database_config { - DatabaseConfig::Memory => AnyDatabaseConfig::Memory(()), - DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config), - DatabaseConfig::Sqlite { config } => AnyDatabaseConfig::Sqlite(config), - }; - let database = AnyDatabase::from_config(&any_database_config)?; - let descriptor: String = descriptor.as_string_private(); - let change_descriptor: Option = change_descriptor.map(|d| d.as_string_private()); - - let wallet_mutex = Mutex::new(BdkWallet::new( - &descriptor, - change_descriptor.as_ref(), - network, - database, - )?); - Ok(Wallet { wallet_mutex }) - } - - fn get_wallet(&self) -> MutexGuard> { - self.wallet_mutex.lock().expect("wallet") - } - - /// Get the Bitcoin network the wallet is using. - fn network(&self) -> Network { - self.get_wallet().network() - } - - /// Sync the internal database with the blockchain. - fn sync( - &self, - blockchain: &Blockchain, - progress: Option>, - ) -> Result<(), BdkError> { - let bdk_sync_opts = BdkSyncOptions { - progress: progress.map(|p| { - Box::new(ProgressHolder { progress: p }) - as Box<(dyn bdk::blockchain::Progress + 'static)> - }), - }; - - let blockchain = blockchain.get_blockchain(); - self.get_wallet().sync(blockchain.deref(), bdk_sync_opts) - } - - /// Return a derived address using the external descriptor, see AddressIndex for available address index selection - /// strategies. If none of the keys in the descriptor are derivable (i.e. the descriptor does not end with a * character) - /// then the same address will always be returned for any AddressIndex. - fn get_address(&self, address_index: AddressIndex) -> Result { - self.get_wallet() - .get_address(address_index.into()) - .map(AddressInfo::from) - } - - /// Return the balance, meaning the sum of this wallet’s unspent outputs’ values. Note that this method only operates - /// on the internal database, which first needs to be Wallet.sync manually. - fn get_balance(&self) -> Result { - self.get_wallet().get_balance().map(|b| b.into()) - } - - /// Sign a transaction with all the wallet’s signers. - fn sign(&self, psbt: &PartiallySignedTransaction) -> Result { - let mut psbt = psbt.internal.lock().unwrap(); - self.get_wallet().sign(&mut psbt, SignOptions::default()) - } - - /// Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually. - fn list_transactions(&self) -> Result, BdkError> { - let transaction_details = self.get_wallet().list_transactions(true)?; - Ok(transaction_details - .iter() - .map(TransactionDetails::from) - .collect()) - } - - /// Return the list of unspent outputs of this wallet. Note that this method only operates on the internal database, - /// which first needs to be Wallet.sync manually. - fn list_unspent(&self) -> Result, BdkError> { - let unspents = self.get_wallet().list_unspent()?; - Ok(unspents - .iter() - .map(|u| LocalUtxo::from_utxo(u, self.network())) - .collect()) - } -} - /// A Bitcoin address. struct Address { address: BdkAddress, diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs new file mode 100644 index 0000000..724e9e1 --- /dev/null +++ b/bdk-ffi/src/wallet.rs @@ -0,0 +1,113 @@ +use bdk::bitcoin::Network; +use bdk::database::any::AnyDatabase; +use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase}; +use bdk::{Error as BdkError, SignOptions, SyncOptions as BdkSyncOptions, Wallet as BdkWallet}; +use std::ops::Deref; +use std::sync::{Arc, Mutex, MutexGuard}; + +use crate::{ + AddressIndex, AddressInfo, Balance, Blockchain, DatabaseConfig, Descriptor, LocalUtxo, + NetworkLocalUtxo, PartiallySignedTransaction, Progress, ProgressHolder, TransactionDetails, +}; + +#[derive(Debug)] +pub(crate) struct Wallet { + pub(crate) wallet_mutex: Mutex>, +} + +/// A Bitcoin wallet. +/// The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are: +/// 1. Output descriptors from which it can derive addresses. +/// 2. A Database where it tracks transactions and utxos related to the descriptors. +/// 3. Signers that can contribute signatures to addresses instantiated from the descriptors. +impl Wallet { + pub(crate) fn new( + descriptor: Arc, + change_descriptor: Option>, + network: Network, + database_config: DatabaseConfig, + ) -> Result { + let any_database_config = match database_config { + DatabaseConfig::Memory => AnyDatabaseConfig::Memory(()), + DatabaseConfig::Sled { config } => AnyDatabaseConfig::Sled(config), + DatabaseConfig::Sqlite { config } => AnyDatabaseConfig::Sqlite(config), + }; + let database = AnyDatabase::from_config(&any_database_config)?; + let descriptor: String = descriptor.as_string_private(); + let change_descriptor: Option = change_descriptor.map(|d| d.as_string_private()); + + let wallet_mutex = Mutex::new(BdkWallet::new( + &descriptor, + change_descriptor.as_ref(), + network, + database, + )?); + Ok(Wallet { wallet_mutex }) + } + + pub(crate) fn get_wallet(&self) -> MutexGuard> { + self.wallet_mutex.lock().expect("wallet") + } + + /// Get the Bitcoin network the wallet is using. + pub(crate) fn network(&self) -> Network { + self.get_wallet().network() + } + + /// Sync the internal database with the blockchain. + pub(crate) fn sync( + &self, + blockchain: &Blockchain, + progress: Option>, + ) -> Result<(), BdkError> { + let bdk_sync_opts = BdkSyncOptions { + progress: progress.map(|p| { + Box::new(ProgressHolder { progress: p }) + as Box<(dyn bdk::blockchain::Progress + 'static)> + }), + }; + + let blockchain = blockchain.get_blockchain(); + self.get_wallet().sync(blockchain.deref(), bdk_sync_opts) + } + + /// Return a derived address using the external descriptor, see AddressIndex for available address index selection + /// strategies. If none of the keys in the descriptor are derivable (i.e. the descriptor does not end with a * character) + /// then the same address will always be returned for any AddressIndex. + pub(crate) fn get_address(&self, address_index: AddressIndex) -> Result { + self.get_wallet() + .get_address(address_index.into()) + .map(AddressInfo::from) + } + + /// Return the balance, meaning the sum of this wallet’s unspent outputs’ values. Note that this method only operates + /// on the internal database, which first needs to be Wallet.sync manually. + pub(crate) fn get_balance(&self) -> Result { + self.get_wallet().get_balance().map(|b| b.into()) + } + + /// Sign a transaction with all the wallet’s signers. + pub(crate) fn sign(&self, psbt: &PartiallySignedTransaction) -> Result { + let mut psbt = psbt.internal.lock().unwrap(); + self.get_wallet().sign(&mut psbt, SignOptions::default()) + } + + /// Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually. + pub(crate) fn list_transactions(&self) -> Result, BdkError> { + let transaction_details = self.get_wallet().list_transactions(true)?; + Ok(transaction_details + .iter() + .map(TransactionDetails::from) + .collect()) + } + + /// Return the list of unspent outputs of this wallet. Note that this method only operates on the internal database, + /// which first needs to be Wallet.sync manually. + pub(crate) fn list_unspent(&self) -> Result, BdkError> { + let unspents = self.get_wallet().list_unspent()?; + Ok(unspents + .iter() + .map(|u| LocalUtxo::from_utxo(u, self.network())) + .collect()) + } +}