]> Untitled Git - bdk/commitdiff
Remove Blockchain from wallet
authorLLFourn <lloyd.fourn@gmail.com>
Wed, 26 Jan 2022 04:17:48 +0000 (15:17 +1100)
committerLLFourn <lloyd.fourn@gmail.com>
Thu, 24 Feb 2022 09:39:00 +0000 (20:39 +1100)
Although somewhat convenient to have, coupling the Wallet with
the blockchain trait causes development friction and complexity.
What if sometimes the wallet is "offline" (no access to the blockchain)
but sometimes its online?
The only thing the Wallet needs the blockchain for is to sync.
But not all applications will even use the sync method and the sync
method doesn't require the full blockchain functionality.
So we instead pass the blockchain in when we want to sync.

- To further reduce the coupling with blockchain I removed the get_height call from `new` and just use the height of the
last sync in the database.
- I split up the blockchain trait a bit into subtraits.

22 files changed:
CHANGELOG.md
README.md
examples/address_validator.rs
examples/compact_filters_balance.rs
examples/compiler.rs
src/blockchain/any.rs
src/blockchain/compact_filters/mod.rs
src/blockchain/electrum.rs
src/blockchain/esplora/reqwest.rs
src/blockchain/esplora/ureq.rs
src/blockchain/mod.rs
src/blockchain/rpc.rs
src/database/any.rs
src/database/memory.rs
src/descriptor/template.rs
src/lib.rs
src/testutils/blockchain_tests.rs
src/wallet/address_validator.rs
src/wallet/export.rs
src/wallet/mod.rs
src/wallet/signer.rs
src/wallet/tx_builder.rs

index 17bf1624261f4577b3f7c95d6d758be614804787..73a1bfe0392be2d0389ee500e8431f27aa90bde9 100644 (file)
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Removed default verification from `wallet::sync`. sync-time verification is added in `script_sync` and is activated by `verify` feature flag.
 - `verify` flag removed from `TransactionDetails`.
+- Removed Blockchain from Wallet.
+- Removed `Wallet::broadcast` (just use blockchain.broadcast)
+- Depreciated `Wallet::new_offline` (all wallets are offline now)
+- Changed `Wallet::sync` to take a blockchain argument.
 
 ## [v0.16.1] - [v0.16.0]
 
index d9491400f254add6a44dcf7ccff26fb829765d37..af449ac0b16695af5acec5d00fa4bf8c5dda0ecc 100644 (file)
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@ use bdk::{Wallet, database::MemoryDatabase};
 use bdk::wallet::AddressIndex::New;
 
 fn main() -> Result<(), bdk::Error> {
-    let wallet = Wallet::new_offline(
+    let wallet = Wallet::new(
         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
         bitcoin::Network::Testnet,
@@ -135,7 +135,7 @@ use bdk::{Wallet, SignOptions, database::MemoryDatabase};
 use bitcoin::consensus::deserialize;
 
 fn main() -> Result<(), bdk::Error> {
-    let wallet = Wallet::new_offline(
+    let wallet = Wallet::new(
         "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
         Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
         bitcoin::Network::Testnet,
index 560a6df50b8333ce25aefe9a05d2bab2f1afd297..85a23560ff619f90a71ccb83dbde834480e828f8 100644 (file)
@@ -48,8 +48,7 @@ impl AddressValidator for DummyValidator {
 
 fn main() -> Result<(), bdk::Error> {
     let descriptor = "sh(and_v(v:pk(tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/*),after(630000)))";
-    let mut wallet =
-        Wallet::new_offline(descriptor, None, Network::Regtest, MemoryDatabase::new())?;
+    let mut wallet = Wallet::new(descriptor, None, Network::Regtest, MemoryDatabase::new())?;
 
     wallet.add_address_validator(Arc::new(DummyValidator));
 
index 78b69d6ccbabfd976931fe6e7f6506b912067a08..2154de4f143dd6e5219bfce0acad99e3e3a87a56 100644 (file)
@@ -35,9 +35,8 @@ fn main() -> Result<(), CompactFiltersError> {
     let descriptor = "wpkh(tpubD6NzVbkrYhZ4X2yy78HWrr1M9NT8dKeWfzNiQqDdMqqa9UmmGztGGz6TaLFGsLfdft5iu32gxq1T4eMNxExNNWzVCpf9Y6JZi5TnqoC9wJq/*)";
 
     let database = MemoryDatabase::default();
-    let wallet =
-        Arc::new(Wallet::new(descriptor, None, Network::Testnet, database, blockchain).unwrap());
-    wallet.sync(noop_progress(), None).unwrap();
+    let wallet = Arc::new(Wallet::new(descriptor, None, Network::Testnet, database).unwrap());
+    wallet.sync(&blockchain, noop_progress(), None).unwrap();
     info!("balance: {}", wallet.get_balance()?);
     Ok(())
 }
index 0af034cb71c57de5bdc9b7ed0e554607a6f42dff..c3a3cb4f3da40233fd10523ddd0e26b1579bbb2a 100644 (file)
@@ -89,7 +89,7 @@ fn main() -> Result<(), Box<dyn Error>> {
         .transpose()
         .unwrap()
         .unwrap_or(Network::Testnet);
-    let wallet = Wallet::new_offline(&format!("{}", descriptor), None, network, database)?;
+    let wallet = Wallet::new(&format!("{}", descriptor), None, network, database)?;
 
     info!("... First address: {}", wallet.get_address(New)?);
 
index 8470959d513b8ccf679c9b2896607dcf1af2e3b7..4ff9459fc8d4fa36c3e835e65224ffb6e39a70b2 100644 (file)
 //!
 //! ## Example
 //!
-//! In this example both `wallet_electrum` and `wallet_esplora` have the same type of
-//! `Wallet<AnyBlockchain, MemoryDatabase>`. This means that they could both, for instance, be
-//! assigned to a struct member.
-//!
-//! ```no_run
-//! # use bitcoin::Network;
-//! # use bdk::blockchain::*;
-//! # use bdk::database::MemoryDatabase;
-//! # use bdk::Wallet;
-//! # #[cfg(feature = "electrum")]
-//! # {
-//! let electrum_blockchain = ElectrumBlockchain::from(electrum_client::Client::new("...")?);
-//! let wallet_electrum: Wallet<AnyBlockchain, _> = Wallet::new(
-//!     "...",
-//!     None,
-//!     Network::Testnet,
-//!     MemoryDatabase::default(),
-//!     electrum_blockchain.into(),
-//! )?;
-//! # }
-//!
-//! # #[cfg(all(feature = "esplora", feature = "ureq"))]
-//! # {
-//! let esplora_blockchain = EsploraBlockchain::new("...", 20);
-//! let wallet_esplora: Wallet<AnyBlockchain, _> = Wallet::new(
-//!     "...",
-//!     None,
-//!     Network::Testnet,
-//!     MemoryDatabase::default(),
-//!     esplora_blockchain.into(),
-//! )?;
-//! # }
-//!
-//! # Ok::<(), bdk::Error>(())
-//! ```
-//!
 //! When paired with the use of [`ConfigurableBlockchain`], it allows creating wallets with any
 //! blockchain type supported using a single line of code:
 //!
 //! ```no_run
 //! # use bitcoin::Network;
 //! # use bdk::blockchain::*;
-//! # use bdk::database::MemoryDatabase;
-//! # use bdk::Wallet;
 //! # #[cfg(all(feature = "esplora", feature = "ureq"))]
 //! # {
 //! let config = serde_json::from_str("...")?;
 //! let blockchain = AnyBlockchain::from_config(&config)?;
-//! let wallet = Wallet::new(
-//!     "...",
-//!     None,
-//!     Network::Testnet,
-//!     MemoryDatabase::default(),
-//!     blockchain,
-//! )?;
+//! let height = blockchain.get_height();
 //! # }
 //! # Ok::<(), bdk::Error>(())
 //! ```
@@ -133,21 +89,6 @@ impl Blockchain for AnyBlockchain {
         maybe_await!(impl_inner_method!(self, get_capabilities))
     }
 
-    fn setup<D: BatchDatabase, P: 'static + Progress>(
-        &self,
-        database: &mut D,
-        progress_update: P,
-    ) -> Result<(), Error> {
-        maybe_await!(impl_inner_method!(self, setup, database, progress_update))
-    }
-    fn sync<D: BatchDatabase, P: 'static + Progress>(
-        &self,
-        database: &mut D,
-        progress_update: P,
-    ) -> Result<(), Error> {
-        maybe_await!(impl_inner_method!(self, sync, database, progress_update))
-    }
-
     fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
         maybe_await!(impl_inner_method!(self, get_tx, txid))
     }
@@ -155,11 +96,44 @@ impl Blockchain for AnyBlockchain {
         maybe_await!(impl_inner_method!(self, broadcast, tx))
     }
 
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        maybe_await!(impl_inner_method!(self, estimate_fee, target))
+    }
+}
+
+#[maybe_async]
+impl GetHeight for AnyBlockchain {
     fn get_height(&self) -> Result<u32, Error> {
         maybe_await!(impl_inner_method!(self, get_height))
     }
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        maybe_await!(impl_inner_method!(self, estimate_fee, target))
+}
+
+#[maybe_async]
+impl WalletSync for AnyBlockchain {
+    fn wallet_sync<D: BatchDatabase, P: Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(
+            self,
+            wallet_sync,
+            database,
+            progress_update
+        ))
+    }
+
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(
+            self,
+            wallet_setup,
+            database,
+            progress_update
+        ))
     }
 }
 
index 56e9efc3a1518efd4294432c613af71eea12ace2..1fd99fc3ef6f5828d37acb606f4b85b15a589ee8 100644 (file)
@@ -67,7 +67,7 @@ mod peer;
 mod store;
 mod sync;
 
-use super::{Blockchain, Capability, ConfigurableBlockchain, Progress};
+use super::{Blockchain, Capability, ConfigurableBlockchain, GetHeight, Progress, WalletSync};
 use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
 use crate::error::Error;
 use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
@@ -225,8 +225,33 @@ impl Blockchain for CompactFiltersBlockchain {
         vec![Capability::FullHistory].into_iter().collect()
     }
 
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.peers[0]
+            .get_mempool()
+            .get_tx(&Inventory::Transaction(*txid)))
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        self.peers[0].broadcast_tx(tx.clone())?;
+
+        Ok(())
+    }
+
+    fn estimate_fee(&self, _target: usize) -> Result<FeeRate, Error> {
+        // TODO
+        Ok(FeeRate::default())
+    }
+}
+
+impl GetHeight for CompactFiltersBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.headers.get_height()? as u32)
+    }
+}
+
+impl WalletSync for CompactFiltersBlockchain {
     #[allow(clippy::mutex_atomic)] // Mutex is easier to understand than a CAS loop.
-    fn setup<D: BatchDatabase, P: 'static + Progress>(
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         progress_update: P,
@@ -430,27 +455,6 @@ impl Blockchain for CompactFiltersBlockchain {
 
         Ok(())
     }
-
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.peers[0]
-            .get_mempool()
-            .get_tx(&Inventory::Transaction(*txid)))
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        self.peers[0].broadcast_tx(tx.clone())?;
-
-        Ok(())
-    }
-
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(self.headers.get_height()? as u32)
-    }
-
-    fn estimate_fee(&self, _target: usize) -> Result<FeeRate, Error> {
-        // TODO
-        Ok(FeeRate::default())
-    }
 }
 
 /// Data to connect to a Bitcoin P2P peer
index 1ab0db1c3ee6cb79985faa5408192c5fad46d1e2..40efdd5595a8efad45e1471e95fd5d45603533e6 100644 (file)
@@ -68,7 +68,34 @@ impl Blockchain for ElectrumBlockchain {
         .collect()
     }
 
-    fn setup<D: BatchDatabase, P: Progress>(
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.client.transaction_get(txid).map(Option::Some)?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(self.client.transaction_broadcast(tx).map(|_| ())?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        Ok(FeeRate::from_btc_per_kvb(
+            self.client.estimate_fee(target)? as f32
+        ))
+    }
+}
+
+impl GetHeight for ElectrumBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        // TODO: unsubscribe when added to the client, or is there a better call to use here?
+
+        Ok(self
+            .client
+            .block_headers_subscribe()
+            .map(|data| data.height as u32)?)
+    }
+}
+
+impl WalletSync for ElectrumBlockchain {
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         _progress_update: P,
@@ -207,29 +234,6 @@ impl Blockchain for ElectrumBlockchain {
         database.commit_batch(batch_update)?;
         Ok(())
     }
-
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.client.transaction_get(txid).map(Option::Some)?)
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        Ok(self.client.transaction_broadcast(tx).map(|_| ())?)
-    }
-
-    fn get_height(&self) -> Result<u32, Error> {
-        // TODO: unsubscribe when added to the client, or is there a better call to use here?
-
-        Ok(self
-            .client
-            .block_headers_subscribe()
-            .map(|data| data.height as u32)?)
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        Ok(FeeRate::from_btc_per_kvb(
-            self.client.estimate_fee(target)? as f32
-        ))
-    }
 }
 
 struct TxCache<'a, 'b, D> {
index 494c6d307e9bc461c348e0489b391ee0a7d30724..d64bf5631847ed416ed4a58f4621494dda2047ad 100644 (file)
@@ -91,7 +91,30 @@ impl Blockchain for EsploraBlockchain {
         .collect()
     }
 
-    fn setup<D: BatchDatabase, P: Progress>(
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(await_or_block!(self.url_client._get_tx(txid))?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(await_or_block!(self.url_client._broadcast(tx))?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = await_or_block!(self.url_client._get_fee_estimates())?;
+        super::into_fee_rate(target, estimates)
+    }
+}
+
+#[maybe_async]
+impl GetHeight for EsploraBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(await_or_block!(self.url_client._get_height())?)
+    }
+}
+
+#[maybe_async]
+impl WalletSync for EsploraBlockchain {
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         _progress_update: P,
@@ -180,23 +203,6 @@ impl Blockchain for EsploraBlockchain {
 
         Ok(())
     }
-
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(await_or_block!(self.url_client._get_tx(txid))?)
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        Ok(await_or_block!(self.url_client._broadcast(tx))?)
-    }
-
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(await_or_block!(self.url_client._get_height())?)
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        let estimates = await_or_block!(self.url_client._get_fee_estimates())?;
-        super::into_fee_rate(target, estimates)
-    }
 }
 
 impl UrlClient {
index 856f6958e19c3eb60fc97f600e7ba75d5e9710a9..ad0dd77332b4fad0686c8f77559e1c83eb7a0fd6 100644 (file)
@@ -87,7 +87,29 @@ impl Blockchain for EsploraBlockchain {
         .collect()
     }
 
-    fn setup<D: BatchDatabase, P: Progress>(
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.url_client._get_tx(txid)?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        let _txid = self.url_client._broadcast(tx)?;
+        Ok(())
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = self.url_client._get_fee_estimates()?;
+        super::into_fee_rate(target, estimates)
+    }
+}
+
+impl GetHeight for EsploraBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.url_client._get_height()?)
+    }
+}
+
+impl WalletSync for EsploraBlockchain {
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         _progress_update: P,
@@ -179,24 +201,6 @@ impl Blockchain for EsploraBlockchain {
 
         Ok(())
     }
-
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(self.url_client._get_tx(txid)?)
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        let _txid = self.url_client._broadcast(tx)?;
-        Ok(())
-    }
-
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(self.url_client._get_height()?)
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        let estimates = self.url_client._get_fee_estimates()?;
-        super::into_fee_rate(target, estimates)
-    }
 }
 
 impl UrlClient {
index bbf0303df9c5f01ca4286e82e74689758a8b10f3..8f3e2523688eee0ab6dd7c1036cf4995308879d8 100644 (file)
@@ -86,28 +86,45 @@ pub enum Capability {
 
 /// Trait that defines the actions that must be supported by a blockchain backend
 #[maybe_async]
-pub trait Blockchain {
+pub trait Blockchain: WalletSync + GetHeight {
     /// Return the set of [`Capability`] supported by this backend
     fn get_capabilities(&self) -> HashSet<Capability>;
+    /// Fetch a transaction from the blockchain given its txid
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
+    /// Broadcast a transaction
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error>;
+    /// Estimate the fee rate required to confirm a transaction in a given `target` of blocks
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>;
+}
 
+/// Trait for getting the current height of the blockchain.
+#[maybe_async]
+pub trait GetHeight {
+    /// Return the current height
+    fn get_height(&self) -> Result<u32, Error>;
+}
+
+/// Trait for blockchains that can sync by updating the database directly.
+#[maybe_async]
+pub trait WalletSync {
     /// Setup the backend and populate the internal database for the first time
     ///
-    /// This method is the equivalent of [`Blockchain::sync`], but it's guaranteed to only be
+    /// This method is the equivalent of [`Self::wallet_sync`], but it's guaranteed to only be
     /// called once, at the first [`Wallet::sync`](crate::wallet::Wallet::sync).
     ///
     /// The rationale behind the distinction between `sync` and `setup` is that some custom backends
     /// might need to perform specific actions only the first time they are synced.
     ///
     /// For types that do not have that distinction, only this method can be implemented, since
-    /// [`Blockchain::sync`] defaults to calling this internally if not overridden.
-    fn setup<D: BatchDatabase, P: 'static + Progress>(
+    /// [`WalletSync::wallet_sync`] defaults to calling this internally if not overridden.
+    /// Populate the internal database with transactions and UTXOs
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         progress_update: P,
     ) -> Result<(), Error>;
-    /// Populate the internal database with transactions and UTXOs
-    ///
-    /// If not overridden, it defaults to calling [`Blockchain::setup`] internally.
+
+    /// If not overridden, it defaults to calling [`Self::wallet_setup`] internally.
     ///
     /// This method should implement the logic required to iterate over the list of the wallet's
     /// script_pubkeys using [`Database::iter_script_pubkeys`] and look for relevant transactions
@@ -124,23 +141,13 @@ pub trait Blockchain {
     /// [`BatchOperations::set_tx`]: crate::database::BatchOperations::set_tx
     /// [`BatchOperations::set_utxo`]: crate::database::BatchOperations::set_utxo
     /// [`BatchOperations::del_utxo`]: crate::database::BatchOperations::del_utxo
-    fn sync<D: BatchDatabase, P: 'static + Progress>(
+    fn wallet_sync<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         progress_update: P,
     ) -> Result<(), Error> {
-        maybe_await!(self.setup(database, progress_update))
+        maybe_await!(self.wallet_setup(database, progress_update))
     }
-
-    /// Fetch a transaction from the blockchain given its txid
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
-    /// Broadcast a transaction
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error>;
-
-    /// Return the current height
-    fn get_height(&self) -> Result<u32, Error>;
-    /// Estimate the fee rate required to confirm a transaction in a given `target` of blocks
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>;
 }
 
 /// Trait for [`Blockchain`] types that can be created given a configuration
@@ -155,9 +162,9 @@ pub trait ConfigurableBlockchain: Blockchain + Sized {
 /// Data sent with a progress update over a [`channel`]
 pub type ProgressData = (f32, Option<String>);
 
-/// Trait for types that can receive and process progress updates during [`Blockchain::sync`] and
-/// [`Blockchain::setup`]
-pub trait Progress: Send {
+/// Trait for types that can receive and process progress updates during [`WalletSync::wallet_sync`] and
+/// [`WalletSync::wallet_setup`]
+pub trait Progress: Send + 'static {
     /// Send a new progress update
     ///
     /// The `progress` value should be in the range 0.0 - 100.0, and the `message` value is an
@@ -223,22 +230,6 @@ impl<T: Blockchain> Blockchain for Arc<T> {
         maybe_await!(self.deref().get_capabilities())
     }
 
-    fn setup<D: BatchDatabase, P: 'static + Progress>(
-        &self,
-        database: &mut D,
-        progress_update: P,
-    ) -> Result<(), Error> {
-        maybe_await!(self.deref().setup(database, progress_update))
-    }
-
-    fn sync<D: BatchDatabase, P: 'static + Progress>(
-        &self,
-        database: &mut D,
-        progress_update: P,
-    ) -> Result<(), Error> {
-        maybe_await!(self.deref().sync(database, progress_update))
-    }
-
     fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
         maybe_await!(self.deref().get_tx(txid))
     }
@@ -246,10 +237,33 @@ impl<T: Blockchain> Blockchain for Arc<T> {
         maybe_await!(self.deref().broadcast(tx))
     }
 
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        maybe_await!(self.deref().estimate_fee(target))
+    }
+}
+
+#[maybe_async]
+impl<T: GetHeight> GetHeight for Arc<T> {
     fn get_height(&self) -> Result<u32, Error> {
         maybe_await!(self.deref().get_height())
     }
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        maybe_await!(self.deref().estimate_fee(target))
+}
+
+#[maybe_async]
+impl<T: WalletSync> WalletSync for Arc<T> {
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().wallet_setup(database, progress_update))
+    }
+
+    fn wallet_sync<D: BatchDatabase, P: Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().wallet_sync(database, progress_update))
     }
 }
index 1b56cbaadc27c155649676f46785c1285d24bfe6..403f0bbd15de8cca30519f30d4da2f81123d4bce 100644 (file)
@@ -33,7 +33,9 @@
 
 use crate::bitcoin::consensus::deserialize;
 use crate::bitcoin::{Address, Network, OutPoint, Transaction, TxOut, Txid};
-use crate::blockchain::{Blockchain, Capability, ConfigurableBlockchain, Progress};
+use crate::blockchain::{
+    Blockchain, Capability, ConfigurableBlockchain, GetHeight, Progress, WalletSync,
+};
 use crate::database::{BatchDatabase, DatabaseUtils};
 use crate::{BlockTime, Error, FeeRate, KeychainKind, LocalUtxo, TransactionDetails};
 use bitcoincore_rpc::json::{
@@ -139,7 +141,34 @@ impl Blockchain for RpcBlockchain {
         self.capabilities.clone()
     }
 
-    fn setup<D: BatchDatabase, P: 'static + Progress>(
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(Some(self.client.get_raw_transaction(txid, None)?))
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(self.client.send_raw_transaction(tx).map(|_| ())?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let sat_per_kb = self
+            .client
+            .estimate_smart_fee(target as u16, None)?
+            .fee_rate
+            .ok_or(Error::FeeRateUnavailable)?
+            .as_sat() as f64;
+
+        Ok(FeeRate::from_sat_per_vb((sat_per_kb / 1000f64) as f32))
+    }
+}
+
+impl GetHeight for RpcBlockchain {
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.client.get_blockchain_info().map(|i| i.blocks as u32)?)
+    }
+}
+
+impl WalletSync for RpcBlockchain {
+    fn wallet_setup<D: BatchDatabase, P: Progress>(
         &self,
         database: &mut D,
         progress_update: P,
@@ -187,10 +216,10 @@ impl Blockchain for RpcBlockchain {
             }
         }
 
-        self.sync(database, progress_update)
+        self.wallet_sync(database, progress_update)
     }
 
-    fn sync<D: BatchDatabase, P: 'static + Progress>(
+    fn wallet_sync<D: BatchDatabase, P: Progress>(
         &self,
         db: &mut D,
         _progress_update: P,
@@ -324,29 +353,6 @@ impl Blockchain for RpcBlockchain {
 
         Ok(())
     }
-
-    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
-        Ok(Some(self.client.get_raw_transaction(txid, None)?))
-    }
-
-    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
-        Ok(self.client.send_raw_transaction(tx).map(|_| ())?)
-    }
-
-    fn get_height(&self) -> Result<u32, Error> {
-        Ok(self.client.get_blockchain_info().map(|i| i.blocks as u32)?)
-    }
-
-    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
-        let sat_per_kb = self
-            .client
-            .estimate_smart_fee(target as u16, None)?
-            .fee_rate
-            .ok_or(Error::FeeRateUnavailable)?
-            .as_sat() as f64;
-
-        Ok(FeeRate::from_sat_per_vb((sat_per_kb / 1000f64) as f32))
-    }
 }
 
 impl ConfigurableBlockchain for RpcBlockchain {
index 8b626e4b71a6bbb83d532b357fbf65c512bc3028..c4c74dc70c32186ba12e770ed29888697c9fa0e1 100644 (file)
 //! # use bdk::database::{AnyDatabase, MemoryDatabase};
 //! # use bdk::{Wallet};
 //! let memory = MemoryDatabase::default();
-//! let wallet_memory = Wallet::new_offline("...", None, Network::Testnet, memory)?;
+//! let wallet_memory = Wallet::new("...", None, Network::Testnet, memory)?;
 //!
 //! # #[cfg(feature = "key-value-db")]
 //! # {
 //! let sled = sled::open("my-database")?.open_tree("default_tree")?;
-//! let wallet_sled = Wallet::new_offline("...", None, Network::Testnet, sled)?;
+//! let wallet_sled = Wallet::new("...", None, Network::Testnet, sled)?;
 //! # }
 //! # Ok::<(), bdk::Error>(())
 //! ```
@@ -42,7 +42,7 @@
 //! # use bdk::{Wallet};
 //! let config = serde_json::from_str("...")?;
 //! let database = AnyDatabase::from_config(&config)?;
-//! let wallet = Wallet::new_offline("...", None, Network::Testnet, database)?;
+//! let wallet = Wallet::new("...", None, Network::Testnet, database)?;
 //! # Ok::<(), bdk::Error>(())
 //! ```
 
index afde6fee1d12131c19d51032dc1a1921536ad0c3..0d5b7ef3d7f384dec99f684d3f40eb57cc28e1a9 100644 (file)
@@ -554,7 +554,7 @@ macro_rules! doctest_wallet {
             Some(100),
         );
 
-        $crate::Wallet::new_offline(
+        $crate::Wallet::new(
             &descriptors.0,
             descriptors.1.as_ref(),
             Network::Regtest,
index 9b5d025e9da7df4cb47828b21d50c943ef8d8786..fb4e7b04d92e4d88344e5be0590a8db19e801317 100644 (file)
@@ -79,7 +79,7 @@ impl<T: DescriptorTemplate> IntoWalletDescriptor for T {
 ///
 /// let key =
 ///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     P2Pkh(key),
 ///     None,
 ///     Network::Testnet,
@@ -113,7 +113,7 @@ impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for P2Pkh<K> {
 ///
 /// let key =
 ///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     P2Wpkh_P2Sh(key),
 ///     None,
 ///     Network::Testnet,
@@ -148,7 +148,7 @@ impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh_P2Sh<K> {
 ///
 /// let key =
 ///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     P2Wpkh(key),
 ///     None,
 ///     Network::Testnet,
@@ -186,7 +186,7 @@ impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh<K> {
 /// use bdk::template::Bip44;
 ///
 /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip44(key.clone(), KeychainKind::External),
 ///     Some(Bip44(key, KeychainKind::Internal)),
 ///     Network::Testnet,
@@ -226,7 +226,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44<K> {
 ///
 /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
 /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip44Public(key.clone(), fingerprint, KeychainKind::External),
 ///     Some(Bip44Public(key, fingerprint, KeychainKind::Internal)),
 ///     Network::Testnet,
@@ -262,7 +262,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44Public<K> {
 /// use bdk::template::Bip49;
 ///
 /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip49(key.clone(), KeychainKind::External),
 ///     Some(Bip49(key, KeychainKind::Internal)),
 ///     Network::Testnet,
@@ -302,7 +302,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49<K> {
 ///
 /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
 /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip49Public(key.clone(), fingerprint, KeychainKind::External),
 ///     Some(Bip49Public(key, fingerprint, KeychainKind::Internal)),
 ///     Network::Testnet,
@@ -338,7 +338,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49Public<K> {
 /// use bdk::template::Bip84;
 ///
 /// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip84(key.clone(), KeychainKind::External),
 ///     Some(Bip84(key, KeychainKind::Internal)),
 ///     Network::Testnet,
@@ -378,7 +378,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip84<K> {
 ///
 /// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
 /// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
-/// let wallet = Wallet::new_offline(
+/// let wallet = Wallet::new(
 ///     Bip84Public(key.clone(), fingerprint, KeychainKind::External),
 ///     Some(Bip84Public(key, fingerprint, KeychainKind::Internal)),
 ///     Network::Testnet,
index 0423dc4f6d0ee7349f8bf8bb8a307f9711ef5f24..b998d36aca3cb65d0c0b5f75be3f21e97ff50585 100644 (file)
@@ -60,15 +60,15 @@ use bdk::electrum_client::Client;
 
 fn main() -> Result<(), bdk::Error> {
     let client = Client::new("ssl://electrum.blockstream.info:60002")?;
+    let blockchain = ElectrumBlockchain::from(client);
     let wallet = Wallet::new(
         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
         bitcoin::Network::Testnet,
         MemoryDatabase::default(),
-        ElectrumBlockchain::from(client)
     )?;
 
-    wallet.sync(noop_progress(), None)?;
+    wallet.sync(&blockchain, noop_progress(), None)?;
 
     println!("Descriptor balance: {} SAT", wallet.get_balance()?);
 
@@ -87,7 +87,7 @@ fn main() -> Result<(), bdk::Error> {
 //! use bdk::wallet::AddressIndex::New;
 //!
 //! fn main() -> Result<(), bdk::Error> {
-//! let wallet = Wallet::new_offline(
+//! let wallet = Wallet::new(
 //!         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
 //!         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
 //!         bitcoin::Network::Testnet,
@@ -123,10 +123,10 @@ fn main() -> Result<(), bdk::Error> {
         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
         bitcoin::Network::Testnet,
         MemoryDatabase::default(),
-        ElectrumBlockchain::from(client)
     )?;
+    let blockchain = ElectrumBlockchain::from(client);
 
-    wallet.sync(noop_progress(), None)?;
+    wallet.sync(&blockchain, noop_progress(), None)?;
 
     let send_to = wallet.get_address(New)?;
     let (psbt, details) = {
@@ -160,7 +160,7 @@ fn main() -> Result<(), bdk::Error> {
 //! use bdk::database::MemoryDatabase;
 //!
 //! fn main() -> Result<(), bdk::Error> {
-//!     let wallet = Wallet::new_offline(
+//!     let wallet = Wallet::new(
 //!         "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
 //!         Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
 //!         bitcoin::Network::Testnet,
index 02047d678fdef0151cc8dd53b736f83879ac3b77..cf6be5a7086d6e7f7cd0f4fa8e50abd1e1e1275d 100644 (file)
@@ -361,7 +361,7 @@ macro_rules! bdk_blockchain_tests {
         mod bdk_blockchain_tests {
             use $crate::bitcoin::{Transaction, Network};
             use $crate::testutils::blockchain_tests::TestClient;
-            use $crate::blockchain::noop_progress;
+            use $crate::blockchain::{Blockchain, noop_progress};
             use $crate::database::MemoryDatabase;
             use $crate::types::KeychainKind;
             use $crate::{Wallet, FeeRate};
@@ -375,11 +375,11 @@ macro_rules! bdk_blockchain_tests {
                 $block
             }
 
-            fn get_wallet_from_descriptors(descriptors: &(String, Option<String>), test_client: &TestClient) -> Wallet<$blockchain, MemoryDatabase> {
-                Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new(), get_blockchain(test_client)).unwrap()
+            fn get_wallet_from_descriptors(descriptors: &(String, Option<String>)) -> Wallet<MemoryDatabase> {
+                Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new()).unwrap()
             }
 
-            fn init_single_sig() -> (Wallet<$blockchain, MemoryDatabase>, (String, Option<String>), TestClient) {
+            fn init_single_sig() -> (Wallet<MemoryDatabase>, $blockchain, (String, Option<String>), TestClient) {
                 let _ = env_logger::try_init();
 
                 let descriptors = testutils! {
@@ -387,13 +387,14 @@ macro_rules! bdk_blockchain_tests {
                 };
 
                 let test_client = TestClient::default();
-                let wallet = get_wallet_from_descriptors(&descriptors, &test_client);
+                let blockchain = get_blockchain(&test_client);
+                let wallet = get_wallet_from_descriptors(&descriptors);
 
                 // rpc need to call import_multi before receiving any tx, otherwise will not see tx in the mempool
                 #[cfg(feature = "test-rpc")]
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
-                (wallet, descriptors, test_client)
+                (wallet, blockchain, descriptors, test_client)
             }
 
             #[test]
@@ -401,7 +402,7 @@ macro_rules! bdk_blockchain_tests {
                 use std::ops::Deref;
                 use crate::database::Database;
 
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 let tx = testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
@@ -414,7 +415,7 @@ macro_rules! bdk_blockchain_tests {
                 #[cfg(not(feature = "test-rpc"))]
                 assert!(wallet.database().deref().get_sync_time().unwrap().is_none(), "initial sync_time not none");
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert!(wallet.database().deref().get_sync_time().unwrap().is_some(), "sync_time hasn't been updated");
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
@@ -429,7 +430,7 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_stop_gap_20() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 5) => 50_000 )
@@ -438,7 +439,7 @@ macro_rules! bdk_blockchain_tests {
                     @tx ( (@external descriptors, 25) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 100_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "incorrect number of txs");
@@ -446,16 +447,16 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_before_and_after_receive() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 0);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@@ -463,13 +464,13 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_multiple_outputs_same_tx() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 let txid = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000, (@external descriptors, 5) => 30_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 105_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@@ -484,7 +485,7 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_receive_multi() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
@@ -493,7 +494,7 @@ macro_rules! bdk_blockchain_tests {
                     @tx ( (@external descriptors, 5) => 25_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "incorrect number of txs");
@@ -502,32 +503,32 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_address_reuse() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 25_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
             }
 
             #[test]
             fn test_sync_receive_rbf_replaced() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 let txid = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 ) ( @replaceable true )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@@ -541,7 +542,7 @@ macro_rules! bdk_blockchain_tests {
 
                 let new_txid = test_client.bump_fee(&txid);
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance after bump");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs after bump");
@@ -559,13 +560,13 @@ macro_rules! bdk_blockchain_tests {
             #[cfg(not(feature = "esplora"))]
             #[test]
             fn test_sync_reorg_block() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 let txid = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 ) ( @confirmations 1 ) ( @replaceable true )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@@ -578,7 +579,7 @@ macro_rules! bdk_blockchain_tests {
                 // Invalidate 1 block
                 test_client.invalidate(1);
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance after invalidate");
 
@@ -589,15 +590,15 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_after_send() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                println!("{}", descriptors.0);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                println!("{}", descriptors.0);
                 let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -607,8 +608,8 @@ macro_rules! bdk_blockchain_tests {
                 assert!(finalized, "Cannot finalize transaction");
                 let tx = psbt.extract_tx();
                 println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
-                wallet.broadcast(&tx).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&tx).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after send");
 
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "incorrect number of txs");
@@ -619,16 +620,16 @@ macro_rules! bdk_blockchain_tests {
             /// The coins should only be received once!
             #[test]
             fn test_sync_double_receive() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let receiver_wallet = get_wallet_from_descriptors(&("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)".to_string(), None), &test_client);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let receiver_wallet = get_wallet_from_descriptors(&("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)".to_string(), None));
                 // need to sync so rpc can start watching
-                receiver_wallet.sync(noop_progress(), None).unwrap();
+                receiver_wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
                 let target_addr = receiver_wallet.get_address($crate::wallet::AddressIndex::New).unwrap().address;
 
@@ -650,16 +651,16 @@ macro_rules! bdk_blockchain_tests {
                     psbt.extract_tx()
                 };
 
-                wallet.broadcast(&tx1).unwrap();
-                wallet.broadcast(&tx2).unwrap();
+                blockchain.broadcast(&tx1).unwrap();
+                blockchain.broadcast(&tx2).unwrap();
 
-                receiver_wallet.sync(noop_progress(), None).unwrap();
+                receiver_wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(receiver_wallet.get_balance().unwrap(), 49_000, "should have received coins once and only once");
             }
 
             #[test]
             fn test_sync_many_sends_to_a_single_address() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 for _ in 0..4 {
                     // split this up into multiple blocks so rpc doesn't get angry
@@ -678,22 +679,22 @@ macro_rules! bdk_blockchain_tests {
                     });
                 }
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 assert_eq!(wallet.get_balance().unwrap(), 100_000);
             }
 
             #[test]
             fn test_update_confirmation_time_after_generate() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                println!("{}", descriptors.0);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                println!("{}", descriptors.0);
                 let node_addr = test_client.get_node_address(None);
 
                 let received_txid = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
@@ -701,7 +702,7 @@ macro_rules! bdk_blockchain_tests {
                 assert!(details.confirmation_time.is_none());
 
                 test_client.generate(1, Some(node_addr));
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                 let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
                 let details = tx_map.get(&received_txid).unwrap();
@@ -711,13 +712,13 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_outgoing_from_scratch() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
                 let received_txid = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -726,25 +727,26 @@ macro_rules! bdk_blockchain_tests {
 
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                let sent_txid = wallet.broadcast(&psbt.extract_tx()).unwrap();
+                let sent_tx = psbt.extract_tx();
+                blockchain.broadcast(&sent_tx).unwrap();
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after receive");
 
                 // empty wallet
-                let wallet = get_wallet_from_descriptors(&descriptors, &test_client);
+                let wallet = get_wallet_from_descriptors(&descriptors);
 
                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
                 test_client.generate(1, Some(node_addr));
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
 
                 let received = tx_map.get(&received_txid).unwrap();
                 assert_eq!(received.received, 50_000, "incorrect received from receiver");
                 assert_eq!(received.sent, 0, "incorrect sent from receiver");
 
-                let sent = tx_map.get(&sent_txid).unwrap();
+                let sent = tx_map.get(&sent_tx.txid()).unwrap();
                 assert_eq!(sent.received, details.received, "incorrect received from sender");
                 assert_eq!(sent.sent, details.sent, "incorrect sent from sender");
                 assert_eq!(sent.fee.unwrap_or(0), details.fee.unwrap_or(0), "incorrect fees from sender");
@@ -752,14 +754,14 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_long_change_chain() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut total_sent = 0;
@@ -769,38 +771,38 @@ macro_rules! bdk_blockchain_tests {
                     let (mut psbt, details) = builder.finish().unwrap();
                     let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                     assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(&psbt.extract_tx()).unwrap();
+                    blockchain.broadcast(&psbt.extract_tx()).unwrap();
 
-                    wallet.sync(noop_progress(), None).unwrap();
+                    wallet.sync(&blockchain, noop_progress(), None).unwrap();
 
                     total_sent += 5_000 + details.fee.unwrap_or(0);
                 }
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent, "incorrect balance after chain");
 
                 // empty wallet
 
-                let wallet = get_wallet_from_descriptors(&descriptors, &test_client);
+                let wallet = get_wallet_from_descriptors(&descriptors);
 
                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
                 test_client.generate(1, Some(node_addr));
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent, "incorrect balance empty wallet");
 
             }
 
             #[test]
             fn test_sync_bump_fee_basic() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -808,8 +810,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut psbt, details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fee.unwrap_or(0) - 5_000, "incorrect balance from fees");
                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance from received");
 
@@ -818,8 +820,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut new_psbt, new_details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&new_psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fee.unwrap_or(0) - 5_000, "incorrect balance from fees after bump");
                 assert_eq!(wallet.get_balance().unwrap(), new_details.received, "incorrect balance from received after bump");
 
@@ -828,14 +830,14 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_bump_fee_remove_change() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -843,8 +845,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut psbt, details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fee.unwrap_or(0), "incorrect balance after send");
                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect received after send");
 
@@ -853,8 +855,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut new_psbt, new_details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&new_psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance after change removal");
                 assert_eq!(new_details.received, 0, "incorrect received after change removal");
 
@@ -863,14 +865,14 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_sync_bump_fee_add_input_simple() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -878,8 +880,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut psbt, details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fee.unwrap_or(0), "incorrect balance after send");
                 assert_eq!(details.received, 1_000 - details.fee.unwrap_or(0), "incorrect received after send");
 
@@ -888,22 +890,22 @@ macro_rules! bdk_blockchain_tests {
                 let (mut new_psbt, new_details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&new_psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(new_details.sent, 75_000, "incorrect sent");
                 assert_eq!(wallet.get_balance().unwrap(), new_details.received, "incorrect balance after add input");
             }
 
             #[test]
             fn test_sync_bump_fee_add_input_no_change() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
 
                 test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -911,8 +913,8 @@ macro_rules! bdk_blockchain_tests {
                 let (mut psbt, details) = builder.finish().unwrap();
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fee.unwrap_or(0), "incorrect balance after send");
                 assert_eq!(details.received, 1_000 - details.fee.unwrap_or(0), "incorrect received after send");
 
@@ -923,8 +925,8 @@ macro_rules! bdk_blockchain_tests {
 
                 let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
                 assert!(finalized, "Cannot finalize transaction");
-                wallet.broadcast(&new_psbt.extract_tx()).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(new_details.sent, 75_000, "incorrect sent");
                 assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance after add input");
                 assert_eq!(new_details.received, 0, "incorrect received after add input");
@@ -933,13 +935,13 @@ macro_rules! bdk_blockchain_tests {
 
             #[test]
             fn test_add_data() {
-                let (wallet, descriptors, mut test_client) = init_single_sig();
-                let node_addr = test_client.get_node_address(None);
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
+                                let node_addr = test_client.get_node_address(None);
                 let _ = test_client.receive(testutils! {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
 
                 let mut builder = wallet.build_tx();
@@ -952,22 +954,22 @@ macro_rules! bdk_blockchain_tests {
                 let tx = psbt.extract_tx();
                 let serialized_tx = bitcoin::consensus::encode::serialize(&tx);
                 assert!(serialized_tx.windows(data.len()).any(|e| e==data), "cannot find op_return data in transaction");
-                let sent_txid = wallet.broadcast(&tx).unwrap();
+                blockchain.broadcast(&tx).unwrap();
                 test_client.generate(1, Some(node_addr));
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fee.unwrap_or(0), "incorrect balance after send");
 
                 let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
-                let _ = tx_map.get(&sent_txid).unwrap();
+                let _ = tx_map.get(&tx.txid()).unwrap();
             }
 
             #[test]
             fn test_sync_receive_coinbase() {
-                let (wallet, _, mut test_client) = init_single_sig();
+                let (wallet, blockchain, _, mut test_client) = init_single_sig();
 
                 let wallet_addr = wallet.get_address($crate::wallet::AddressIndex::New).unwrap().address;
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance");
 
                 test_client.generate(1, Some(wallet_addr));
@@ -980,7 +982,7 @@ macro_rules! bdk_blockchain_tests {
                 }
 
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert!(wallet.get_balance().unwrap() > 0, "incorrect balance after receiving coinbase");
             }
 
@@ -993,7 +995,7 @@ macro_rules! bdk_blockchain_tests {
                 use bitcoincore_rpc::jsonrpc::serde_json::Value;
                 use bitcoincore_rpc::{Auth, Client, RpcApi};
 
-                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
 
                 // TODO remove once rust-bitcoincore-rpc with PR 199 released
                 // https://github.com/rust-bitcoin/rust-bitcoincore-rpc/pull/199
@@ -1056,7 +1058,7 @@ macro_rules! bdk_blockchain_tests {
                     @tx ( (@external descriptors, 0) => 50_000 )
                 });
 
-                wallet.sync(noop_progress(), None).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), 50_000, "wallet has incorrect balance");
 
                 // 4. Send 25_000 sats from test BDK wallet to test bitcoind node taproot wallet
@@ -1067,8 +1069,8 @@ macro_rules! bdk_blockchain_tests {
                 let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
                 assert!(finalized, "wallet cannot finalize transaction");
                 let tx = psbt.extract_tx();
-                wallet.broadcast(&tx).unwrap();
-                wallet.sync(noop_progress(), None).unwrap();
+                blockchain.broadcast(&tx).unwrap();
+                wallet.sync(&blockchain, noop_progress(), None).unwrap();
                 assert_eq!(wallet.get_balance().unwrap(), details.received, "wallet has incorrect balance after send");
                 assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "wallet has incorrect number of txs");
                 assert_eq!(wallet.list_unspent().unwrap().len(), 1, "wallet has incorrect number of unspents");
index ba675337369ec3a72087d9c6432907807546fe4e..a0e418abe538204596a98592f502320ddf63233e 100644 (file)
@@ -55,7 +55,7 @@
 //! }
 //!
 //! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
-//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! let mut wallet = Wallet::new(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
 //! wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
 //!
 //! let address = wallet.get_address(New)?;
index 85898345fba077d29408060cdf0e49c7aea6e45f..f531989e0fb599a4175fda6d7ad2db98fb5a9ae5 100644 (file)
@@ -30,7 +30,7 @@
 //! }"#;
 //!
 //! let import = WalletExport::from_str(import)?;
-//! let wallet = Wallet::new_offline(
+//! let wallet = Wallet::new(
 //!     &import.descriptor(),
 //!     import.change_descriptor().as_ref(),
 //!     Network::Testnet,
@@ -45,7 +45,7 @@
 //! # use bdk::database::*;
 //! # use bdk::wallet::export::*;
 //! # use bdk::*;
-//! let wallet = Wallet::new_offline(
+//! let wallet = Wallet::new(
 //!     "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
 //!     Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
 //!     Network::Testnet,
@@ -111,8 +111,8 @@ impl WalletExport {
     ///
     /// If the database is empty or `include_blockheight` is false, the `blockheight` field
     /// returned will be `0`.
-    pub fn export_wallet<B, D: BatchDatabase>(
-        wallet: &Wallet<B, D>,
+    pub fn export_wallet<D: BatchDatabase>(
+        wallet: &Wallet<D>,
         label: &str,
         include_blockheight: bool,
     ) -> Result<Self, &'static str> {
@@ -241,7 +241,7 @@ mod test {
         let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
         let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
 
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             descriptor,
             Some(change_descriptor),
             Network::Bitcoin,
@@ -265,8 +265,7 @@ mod test {
 
         let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
 
-        let wallet =
-            Wallet::new_offline(descriptor, None, Network::Bitcoin, get_test_db()).unwrap();
+        let wallet = Wallet::new(descriptor, None, Network::Bitcoin, get_test_db()).unwrap();
         WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
     }
 
@@ -279,7 +278,7 @@ mod test {
         let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
         let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)";
 
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             descriptor,
             Some(change_descriptor),
             Network::Bitcoin,
@@ -302,7 +301,7 @@ mod test {
                                        [c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\
                                  ))";
 
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             descriptor,
             Some(change_descriptor),
             Network::Testnet,
@@ -322,7 +321,7 @@ mod test {
         let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
         let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
 
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             descriptor,
             Some(change_descriptor),
             Network::Bitcoin,
index a24f922dcddebe13b6cb8a32760b68b94052ca51..9effd1c0b9e53f3b4b5fc3dd08001387eb4bcf0d 100644 (file)
@@ -55,7 +55,7 @@ use signer::{SignOptions, Signer, SignerOrdering, SignersContainer};
 use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
 use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx};
 
-use crate::blockchain::{Blockchain, Progress};
+use crate::blockchain::{GetHeight, Progress, WalletSync};
 use crate::database::memory::MemoryDatabase;
 use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils, SyncTime};
 use crate::descriptor::derived::AsDerived;
@@ -75,16 +75,17 @@ const CACHE_ADDR_BATCH_SIZE: u32 = 100;
 
 /// A Bitcoin wallet
 ///
-/// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a
-/// [`blockchain`](trait@crate::blockchain::Blockchain) and implements the basic functions that a Bitcoin wallets
-/// needs to operate, like [generating addresses](Wallet::get_address), [returning the balance](Wallet::get_balance),
-/// [creating transactions](Wallet::build_tx), etc.
+/// The `Wallet` struct acts as a way of coherently interfacing with output descriptors and related transactions.
+/// Its main components are:
 ///
-/// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided
-/// implements [`Blockchain`], or "offline" if it is the unit type `()`. Offline wallets only expose
-/// methods that don't need any interaction with the blockchain to work.
+/// 1. output *descriptors* from which it can derive addresses.
+/// 2. A [`Database`] where it tracks transactions and utxos related to the descriptors.
+/// 3. [`Signer`]s that can contribute signatures to addresses instantiated from the descriptors.
+///
+/// [`Database`]: crate::database::Database
+/// [`Signer`]: crate::signer::Signer
 #[derive(Debug)]
-pub struct Wallet<B, D> {
+pub struct Wallet<D> {
     descriptor: ExtendedDescriptor,
     change_descriptor: Option<ExtendedDescriptor>,
 
@@ -95,88 +96,11 @@ pub struct Wallet<B, D> {
 
     network: Network,
 
-    current_height: Option<u32>,
-
-    client: B,
     database: RefCell<D>,
 
     secp: SecpCtx,
 }
 
-impl<D> Wallet<(), D>
-where
-    D: BatchDatabase,
-{
-    /// Create a new "offline" wallet
-    pub fn new_offline<E: IntoWalletDescriptor>(
-        descriptor: E,
-        change_descriptor: Option<E>,
-        network: Network,
-        database: D,
-    ) -> Result<Self, Error> {
-        Self::_new(descriptor, change_descriptor, network, database, (), None)
-    }
-}
-
-impl<B, D> Wallet<B, D>
-where
-    D: BatchDatabase,
-{
-    fn _new<E: IntoWalletDescriptor>(
-        descriptor: E,
-        change_descriptor: Option<E>,
-        network: Network,
-        mut database: D,
-        client: B,
-        current_height: Option<u32>,
-    ) -> Result<Self, Error> {
-        let secp = Secp256k1::new();
-
-        let (descriptor, keymap) = into_wallet_descriptor_checked(descriptor, &secp, network)?;
-        database.check_descriptor_checksum(
-            KeychainKind::External,
-            get_checksum(&descriptor.to_string())?.as_bytes(),
-        )?;
-        let signers = Arc::new(SignersContainer::from(keymap));
-        let (change_descriptor, change_signers) = match change_descriptor {
-            Some(desc) => {
-                let (change_descriptor, change_keymap) =
-                    into_wallet_descriptor_checked(desc, &secp, network)?;
-                database.check_descriptor_checksum(
-                    KeychainKind::Internal,
-                    get_checksum(&change_descriptor.to_string())?.as_bytes(),
-                )?;
-
-                let change_signers = Arc::new(SignersContainer::from(change_keymap));
-                // if !parsed.same_structure(descriptor.as_ref()) {
-                //     return Err(Error::DifferentDescriptorStructure);
-                // }
-
-                (Some(change_descriptor), change_signers)
-            }
-            None => (None, Arc::new(SignersContainer::new())),
-        };
-
-        Ok(Wallet {
-            descriptor,
-            change_descriptor,
-            signers,
-            change_signers,
-            address_validators: Vec::new(),
-            network,
-            current_height,
-            client,
-            database: RefCell::new(database),
-            secp,
-        })
-    }
-
-    /// Get the Bitcoin network the wallet is using.
-    pub fn network(&self) -> Network {
-        self.network
-    }
-}
-
 /// The address index selection strategy to use to derived an address from the wallet's external
 /// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
 #[derive(Debug)]
@@ -232,11 +156,63 @@ impl fmt::Display for AddressInfo {
     }
 }
 
-// offline actions, always available
-impl<B, D> Wallet<B, D>
+impl<D> Wallet<D>
 where
     D: BatchDatabase,
 {
+    /// Create a wallet.
+    ///
+    /// The only way this can fail is if the descriptors passed in do not match the checksums in `database`.
+    pub fn new<E: IntoWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        mut database: D,
+    ) -> Result<Self, Error> {
+        let secp = Secp256k1::new();
+
+        let (descriptor, keymap) = into_wallet_descriptor_checked(descriptor, &secp, network)?;
+        database.check_descriptor_checksum(
+            KeychainKind::External,
+            get_checksum(&descriptor.to_string())?.as_bytes(),
+        )?;
+        let signers = Arc::new(SignersContainer::from(keymap));
+        let (change_descriptor, change_signers) = match change_descriptor {
+            Some(desc) => {
+                let (change_descriptor, change_keymap) =
+                    into_wallet_descriptor_checked(desc, &secp, network)?;
+                database.check_descriptor_checksum(
+                    KeychainKind::Internal,
+                    get_checksum(&change_descriptor.to_string())?.as_bytes(),
+                )?;
+
+                let change_signers = Arc::new(SignersContainer::from(change_keymap));
+                // if !parsed.same_structure(descriptor.as_ref()) {
+                //     return Err(Error::DifferentDescriptorStructure);
+                // }
+
+                (Some(change_descriptor), change_signers)
+            }
+            None => (None, Arc::new(SignersContainer::new())),
+        };
+
+        Ok(Wallet {
+            descriptor,
+            change_descriptor,
+            signers,
+            change_signers,
+            address_validators: Vec::new(),
+            network,
+            database: RefCell::new(database),
+            secp,
+        })
+    }
+
+    /// Get the Bitcoin network the wallet is using.
+    pub fn network(&self) -> Network {
+        self.network
+    }
+
     // Return a newly derived address using the external descriptor
     fn get_new_address(&self) -> Result<AddressInfo, Error> {
         let incremented_index = self.fetch_and_increment_index(KeychainKind::External)?;
@@ -422,7 +398,7 @@ where
     /// ```
     ///
     /// [`TxBuilder`]: crate::TxBuilder
-    pub fn build_tx(&self) -> TxBuilder<'_, B, D, DefaultCoinSelectionAlgorithm, CreateTx> {
+    pub fn build_tx(&self) -> TxBuilder<'_, D, DefaultCoinSelectionAlgorithm, CreateTx> {
         TxBuilder {
             wallet: self,
             params: TxParams::default(),
@@ -762,7 +738,7 @@ where
     pub fn build_fee_bump(
         &self,
         txid: Txid,
-    ) -> Result<TxBuilder<'_, B, D, DefaultCoinSelectionAlgorithm, BumpFee>, Error> {
+    ) -> Result<TxBuilder<'_, D, DefaultCoinSelectionAlgorithm, BumpFee>, Error> {
         let mut details = match self.database.borrow().get_tx(&txid, true)? {
             None => return Err(Error::TransactionNotFound),
             Some(tx) if tx.transaction.is_none() => return Err(Error::TransactionNotFound),
@@ -993,7 +969,11 @@ where
                 .borrow()
                 .get_tx(&input.previous_output.txid, false)?
                 .map(|tx| tx.confirmation_time.map(|c| c.height).unwrap_or(u32::MAX));
-            let current_height = sign_options.assume_height.or(self.current_height);
+            let last_sync_height = self
+                .database()
+                .get_sync_time()?
+                .map(|sync_time| sync_time.block_time.height);
+            let current_height = sign_options.assume_height.or(last_sync_height);
 
             debug!(
                 "Input #{} - {}, using `create_height` = {:?}, `current_height` = {:?}",
@@ -1453,35 +1433,15 @@ where
     }
 }
 
-impl<B, D> Wallet<B, D>
+impl<D> Wallet<D>
 where
-    B: Blockchain,
     D: BatchDatabase,
 {
-    /// Create a new "online" wallet
-    #[maybe_async]
-    pub fn new<E: IntoWalletDescriptor>(
-        descriptor: E,
-        change_descriptor: Option<E>,
-        network: Network,
-        database: D,
-        client: B,
-    ) -> Result<Self, Error> {
-        let current_height = Some(maybe_await!(client.get_height())? as u32);
-        Self::_new(
-            descriptor,
-            change_descriptor,
-            network,
-            database,
-            client,
-            current_height,
-        )
-    }
-
     /// Sync the internal database with the blockchain
     #[maybe_async]
-    pub fn sync<P: 'static + Progress>(
+    pub fn sync<P: 'static + Progress, B: WalletSync + GetHeight>(
         &self,
+        blockchain: &B,
         progress_update: P,
         max_address_param: Option<u32>,
     ) -> Result<(), Error> {
@@ -1527,18 +1487,18 @@ where
         // TODO: what if i generate an address first and cache some addresses?
         // TODO: we should sync if generating an address triggers a new batch to be stored
         if run_setup {
-            maybe_await!(self
-                .client
-                .setup(self.database.borrow_mut().deref_mut(), progress_update,))?;
+            maybe_await!(
+                blockchain.wallet_setup(self.database.borrow_mut().deref_mut(), progress_update,)
+            )?;
         } else {
-            maybe_await!(self
-                .client
-                .sync(self.database.borrow_mut().deref_mut(), progress_update,))?;
+            maybe_await!(
+                blockchain.wallet_sync(self.database.borrow_mut().deref_mut(), progress_update,)
+            )?;
         }
 
         let sync_time = SyncTime {
             block_time: BlockTime {
-                height: maybe_await!(self.client.get_height())?,
+                height: maybe_await!(blockchain.get_height())?,
                 timestamp: time::get_timestamp(),
             },
         };
@@ -1547,31 +1507,18 @@ where
 
         Ok(())
     }
-
-    /// Return a reference to the internal blockchain client
-    pub fn client(&self) -> &B {
-        &self.client
-    }
-
-    /// Broadcast a transaction to the network
-    #[maybe_async]
-    pub fn broadcast(&self, tx: &Transaction) -> Result<Txid, Error> {
-        maybe_await!(self.client.broadcast(tx))?;
-
-        Ok(tx.txid())
-    }
 }
 
 /// Return a fake wallet that appears to be funded for testing.
 pub fn get_funded_wallet(
     descriptor: &str,
 ) -> (
-    Wallet<(), MemoryDatabase>,
+    Wallet<MemoryDatabase>,
     (String, Option<String>),
     bitcoin::Txid,
 ) {
     let descriptors = testutils!(@descriptors (descriptor));
-    let wallet = Wallet::new_offline(
+    let wallet = Wallet::new(
         &descriptors.0,
         None,
         Network::Regtest,
@@ -1621,7 +1568,7 @@ pub(crate) mod test {
     #[test]
     fn test_cache_addresses_fixed() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             "wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)",
             None,
             Network::Testnet,
@@ -1655,7 +1602,7 @@ pub(crate) mod test {
     #[test]
     fn test_cache_addresses() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
 
         assert_eq!(
             wallet.get_address(New).unwrap().to_string(),
@@ -1683,7 +1630,7 @@ pub(crate) mod test {
     #[test]
     fn test_cache_addresses_refill() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
 
         assert_eq!(
             wallet.get_address(New).unwrap().to_string(),
@@ -3781,7 +3728,7 @@ pub(crate) mod test {
     #[test]
     fn test_unused_address() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
                                          None, Network::Testnet, db).unwrap();
 
         assert_eq!(
@@ -3798,7 +3745,7 @@ pub(crate) mod test {
     fn test_next_unused_address() {
         let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)";
         let descriptors = testutils!(@descriptors (descriptor));
-        let wallet = Wallet::new_offline(
+        let wallet = Wallet::new(
             &descriptors.0,
             None,
             Network::Testnet,
@@ -3827,7 +3774,7 @@ pub(crate) mod test {
     #[test]
     fn test_peek_address_at_index() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
                                          None, Network::Testnet, db).unwrap();
 
         assert_eq!(
@@ -3860,7 +3807,7 @@ pub(crate) mod test {
     #[test]
     fn test_peek_address_at_index_not_derivable() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/1)",
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/1)",
                                          None, Network::Testnet, db).unwrap();
 
         assert_eq!(
@@ -3882,7 +3829,7 @@ pub(crate) mod test {
     #[test]
     fn test_reset_address_index() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
                                          None, Network::Testnet, db).unwrap();
 
         // new index 0
@@ -3919,7 +3866,7 @@ pub(crate) mod test {
     #[test]
     fn test_returns_index_and_address() {
         let db = MemoryDatabase::new();
-        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+        let wallet = Wallet::new("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
                                          None, Network::Testnet, db).unwrap();
 
         // new index 0
index 88b98461c43e98e86aa14a6f70f44ac811accb49..15cec186efbac7a726f71438017fca59dc2ca179 100644 (file)
@@ -72,7 +72,7 @@
 //! let custom_signer = CustomSigner::connect();
 //!
 //! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
-//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! let mut wallet = Wallet::new(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
 //! wallet.add_signer(
 //!     KeychainKind::External,
 //!     SignerOrdering(200),
index 66b037854c860fd099613776e2b11cf81ce1589d..e03a935656ade5124bde8455240fb944e9ae8102 100644 (file)
@@ -120,8 +120,8 @@ impl TxBuilderContext for BumpFee {}
 /// [`finish`]: Self::finish
 /// [`coin_selection`]: Self::coin_selection
 #[derive(Debug)]
-pub struct TxBuilder<'a, B, D, Cs, Ctx> {
-    pub(crate) wallet: &'a Wallet<B, D>,
+pub struct TxBuilder<'a, D, Cs, Ctx> {
+    pub(crate) wallet: &'a Wallet<D>,
     pub(crate) params: TxParams,
     pub(crate) coin_selection: Cs,
     pub(crate) phantom: PhantomData<Ctx>,
@@ -170,7 +170,7 @@ impl std::default::Default for FeePolicy {
     }
 }
 
-impl<'a, Cs: Clone, Ctx, B, D> Clone for TxBuilder<'a, B, D, Cs, Ctx> {
+impl<'a, Cs: Clone, Ctx, D> Clone for TxBuilder<'a, D, Cs, Ctx> {
     fn clone(&self) -> Self {
         TxBuilder {
             wallet: self.wallet,
@@ -182,8 +182,8 @@ impl<'a, Cs: Clone, Ctx, B, D> Clone for TxBuilder<'a, B, D, Cs, Ctx> {
 }
 
 // methods supported by both contexts, for any CoinSelectionAlgorithm
-impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext>
-    TxBuilder<'a, B, D, Cs, Ctx>
+impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext>
+    TxBuilder<'a, D, Cs, Ctx>
 {
     /// Set a custom fee rate
     pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self {
@@ -508,7 +508,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderConte
     pub fn coin_selection<P: CoinSelectionAlgorithm<D>>(
         self,
         coin_selection: P,
-    ) -> TxBuilder<'a, B, D, P, Ctx> {
+    ) -> TxBuilder<'a, D, P, Ctx> {
         TxBuilder {
             wallet: self.wallet,
             params: self.params,
@@ -547,7 +547,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderConte
     }
 }
 
-impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, B, D, Cs, CreateTx> {
+impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, D, Cs, CreateTx> {
     /// Replace the recipients already added with a new list
     pub fn set_recipients(&mut self, recipients: Vec<(Script, u64)>) -> &mut Self {
         self.params.recipients = recipients;
@@ -614,7 +614,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, B, D,
 }
 
 // methods supported only by bump_fee
-impl<'a, B, D: BatchDatabase> TxBuilder<'a, B, D, DefaultCoinSelectionAlgorithm, BumpFee> {
+impl<'a, D: BatchDatabase> TxBuilder<'a, D, DefaultCoinSelectionAlgorithm, BumpFee> {
     /// Explicitly tells the wallet that it is allowed to reduce the fee of the output matching this
     /// `script_pubkey` in order to bump the transaction fee. Without specifying this the wallet
     /// will attempt to find a change output to shrink instead.