Add SyncOptions as the second argument to Wallet::sync

The current options are awkware and it would be good if we could
introduce more in the future without breaking changes.
This commit is contained in:
LLFourn 2022-01-27 16:52:53 +11:00
parent 733300623e
commit 8de422dcfd
No known key found for this signature in database
GPG Key ID: A27093B54DA11F65
12 changed files with 119 additions and 108 deletions

View File

@ -6,10 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Removed Blockchain from Wallet.
- Removed `Wallet::broadcast` (just use blockchain.broadcast)
### Sync API change
To decouple the `Wallet` from the `Blockchain` we've made major changes:
- 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.
- Changed `Wallet::sync` to take a `Blockchain`.
- Stop making a request for the block height when calling `Wallet:new`.
- Added `SyncOptions` to capture extra (future) arguments to `Wallet::sync`.
## [v0.15.0] - [v0.14.0]

View File

@ -41,21 +41,21 @@ The `bdk` library aims to be the core building block for Bitcoin wallets of any
```rust,no_run
use bdk::Wallet;
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};
use bdk::blockchain::ElectrumBlockchain;
use bdk::SyncOptions;
use bdk::electrum_client::Client;
fn main() -> Result<(), bdk::Error> {
let client = Client::new("ssl://electrum.blockstream.info:60002")?;
let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
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, SyncOptions::default())?;
println!("Descriptor balance: {} SAT", wallet.get_balance()?);
@ -88,9 +88,9 @@ fn main() -> Result<(), bdk::Error> {
### Create a transaction
```rust,no_run
use bdk::{FeeRate, Wallet};
use bdk::{FeeRate, Wallet, SyncOptions};
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};
use bdk::blockchain::ElectrumBlockchain;
use bdk::electrum_client::Client;
use bdk::wallet::AddressIndex::New;
@ -98,16 +98,15 @@ use bdk::wallet::AddressIndex::New;
use bitcoin::consensus::serialize;
fn main() -> Result<(), bdk::Error> {
let client = Client::new("ssl://electrum.blockstream.info:60002")?;
let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
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, SyncOptions::default())?;
let send_to = wallet.get_address(New)?;
let (psbt, details) = {

View File

@ -10,7 +10,6 @@
// licenses.
use bdk::blockchain::compact_filters::*;
use bdk::blockchain::noop_progress;
use bdk::database::MemoryDatabase;
use bdk::*;
use bitcoin::*;
@ -36,7 +35,7 @@ fn main() -> Result<(), CompactFiltersError> {
let database = MemoryDatabase::default();
let wallet = Arc::new(Wallet::new(descriptor, None, Network::Testnet, database).unwrap());
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
info!("balance: {}", wallet.get_balance()?);
Ok(())
}

View File

@ -108,10 +108,10 @@ impl GetHeight for AnyBlockchain {
}
impl WalletSync for AnyBlockchain {
fn wallet_sync<D: BatchDatabase, P: Progress>(
fn wallet_sync<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
maybe_await!(impl_inner_method!(
self,
@ -121,10 +121,10 @@ impl WalletSync for AnyBlockchain {
))
}
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
maybe_await!(impl_inner_method!(
self,

View File

@ -252,10 +252,10 @@ impl GetHeight for CompactFiltersBlockchain {
impl WalletSync for CompactFiltersBlockchain {
#[allow(clippy::mutex_atomic)] // Mutex is easier to understand than a CAS loop.
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
let first_peer = &self.peers[0];

View File

@ -95,10 +95,10 @@ impl GetHeight for ElectrumBlockchain {
}
impl WalletSync for ElectrumBlockchain {
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
_progress_update: P,
_progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
let mut request = script_sync::start(database, self.stop_gap)?;
let mut block_times = HashMap::<u32, u32>::new();

View File

@ -109,10 +109,10 @@ impl GetHeight for EsploraBlockchain {
}
impl WalletSync for EsploraBlockchain {
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
_progress_update: P,
_progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
use crate::blockchain::script_sync::Request;
let mut request = script_sync::start(database, self.stop_gap)?;

View File

@ -118,10 +118,10 @@ pub trait WalletSync {
/// For types that do not have that distinction, only this method can be implemented, since
/// [`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>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error>;
/// If not overridden, it defaults to calling [`Self::wallet_setup`] internally.
@ -141,10 +141,10 @@ pub trait WalletSync {
/// [`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 wallet_sync<D: BatchDatabase, P: Progress>(
fn wallet_sync<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
maybe_await!(self.wallet_setup(database, progress_update))
}
@ -164,7 +164,7 @@ pub type ProgressData = (f32, Option<String>);
/// Trait for types that can receive and process progress updates during [`WalletSync::wallet_sync`] and
/// [`WalletSync::wallet_setup`]
pub trait Progress: Send + 'static {
pub trait Progress: Send + 'static + core::fmt::Debug {
/// Send a new progress update
///
/// The `progress` value should be in the range 0.0 - 100.0, and the `message` value is an
@ -189,7 +189,7 @@ impl Progress for Sender<ProgressData> {
}
/// Type that implements [`Progress`] and drops every update received
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default, Debug)]
pub struct NoopProgress;
/// Create a new instance of [`NoopProgress`]
@ -204,7 +204,7 @@ impl Progress for NoopProgress {
}
/// Type that implements [`Progress`] and logs at level `INFO` every update received
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default, Debug)]
pub struct LogProgress;
/// Create a new instance of [`LogProgress`]
@ -251,18 +251,18 @@ impl<T: GetHeight> GetHeight for Arc<T> {
#[maybe_async]
impl<T: WalletSync> WalletSync for Arc<T> {
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
maybe_await!(self.deref().wallet_setup(database, progress_update))
}
fn wallet_sync<D: BatchDatabase, P: Progress>(
fn wallet_sync<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
maybe_await!(self.deref().wallet_sync(database, progress_update))
}

View File

@ -168,10 +168,10 @@ impl GetHeight for RpcBlockchain {
}
impl WalletSync for RpcBlockchain {
fn wallet_setup<D: BatchDatabase, P: Progress>(
fn wallet_setup<D: BatchDatabase>(
&self,
database: &mut D,
progress_update: P,
progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
let mut scripts_pubkeys = database.iter_script_pubkeys(Some(KeychainKind::External))?;
scripts_pubkeys.extend(database.iter_script_pubkeys(Some(KeychainKind::Internal))?);
@ -219,10 +219,10 @@ impl WalletSync for RpcBlockchain {
self.wallet_sync(database, progress_update)
}
fn wallet_sync<D: BatchDatabase, P: Progress>(
fn wallet_sync<D: BatchDatabase>(
&self,
db: &mut D,
_progress_update: P,
_progress_update: Box<dyn Progress>,
) -> Result<(), Error> {
let mut indexes = HashMap::new();
for keykind in &[KeychainKind::External, KeychainKind::Internal] {

View File

@ -53,9 +53,9 @@
### Example
```no_run
use bdk::Wallet;
use bdk::{Wallet, SyncOptions};
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};
use bdk::blockchain::ElectrumBlockchain;
use bdk::electrum_client::Client;
fn main() -> Result<(), bdk::Error> {
@ -68,7 +68,7 @@ fn main() -> Result<(), bdk::Error> {
MemoryDatabase::default(),
)?;
wallet.sync(&blockchain, noop_progress(), None)?;
wallet.sync(&blockchain, SyncOptions::default())?;
println!("Descriptor balance: {} SAT", wallet.get_balance()?);
@ -108,9 +108,9 @@ fn main() -> Result<(), bdk::Error> {
### Example
```no_run
use bdk::{FeeRate, Wallet};
use bdk::{FeeRate, Wallet, SyncOptions};
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};
use bdk::blockchain::ElectrumBlockchain;
use bdk::electrum_client::Client;
use bitcoin::consensus::serialize;
@ -126,7 +126,7 @@ fn main() -> Result<(), bdk::Error> {
)?;
let blockchain = ElectrumBlockchain::from(client);
wallet.sync(&blockchain, noop_progress(), None)?;
wallet.sync(&blockchain, SyncOptions::default())?;
let send_to = wallet.get_address(New)?;
let (psbt, details) = {
@ -272,6 +272,7 @@ pub use wallet::address_validator;
pub use wallet::signer;
pub use wallet::signer::SignOptions;
pub use wallet::tx_builder::TxBuilder;
pub use wallet::SyncOptions;
pub use wallet::Wallet;
/// Get the version of BDK at runtime

View File

@ -355,10 +355,10 @@ macro_rules! bdk_blockchain_tests {
mod bdk_blockchain_tests {
use $crate::bitcoin::Network;
use $crate::testutils::blockchain_tests::TestClient;
use $crate::blockchain::{Blockchain, noop_progress};
use $crate::blockchain::Blockchain;
use $crate::database::MemoryDatabase;
use $crate::types::KeychainKind;
use $crate::{Wallet, FeeRate};
use $crate::{Wallet, FeeRate, SyncOptions};
use $crate::testutils;
use super::*;
@ -386,7 +386,7 @@ macro_rules! bdk_blockchain_tests {
// rpc need to call import_multi before receiving any tx, otherwise will not see tx in the mempool
#[cfg(feature = "test-rpc")]
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
(wallet, blockchain, descriptors, test_client)
}
@ -409,7 +409,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(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -433,7 +433,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 25) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 100_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "incorrect number of txs");
@ -443,14 +443,14 @@ macro_rules! bdk_blockchain_tests {
fn test_sync_before_and_after_receive() {
let (wallet, blockchain, descriptors, mut test_client) = init_single_sig();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 0);
test_client.receive(testutils! {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@ -464,7 +464,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000, (@external descriptors, 5) => 30_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 105_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@ -488,7 +488,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 5) => 25_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 2, "incorrect number of txs");
@ -503,14 +503,14 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000);
test_client.receive(testutils! {
@tx ( (@external descriptors, 0) => 25_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
}
@ -522,7 +522,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 ) ( @replaceable true )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@ -536,7 +536,7 @@ macro_rules! bdk_blockchain_tests {
let new_txid = test_client.bump_fee(&txid);
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -560,7 +560,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 ) ( @confirmations 1 ) ( @replaceable true )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
assert_eq!(wallet.list_transactions(false).unwrap().len(), 1, "incorrect number of txs");
@ -573,7 +573,7 @@ macro_rules! bdk_blockchain_tests {
// Invalidate 1 block
test_client.invalidate(1);
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance after invalidate");
@ -592,7 +592,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -603,7 +603,7 @@ macro_rules! bdk_blockchain_tests {
let tx = psbt.extract_tx();
println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
blockchain.broadcast(&tx).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -617,13 +617,13 @@ macro_rules! bdk_blockchain_tests {
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(&blockchain, noop_progress(), None).unwrap();
receiver_wallet.sync(&blockchain, SyncOptions::default()).unwrap();
test_client.receive(testutils! {
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
let target_addr = receiver_wallet.get_address($crate::wallet::AddressIndex::New).unwrap().address;
@ -648,7 +648,7 @@ macro_rules! bdk_blockchain_tests {
blockchain.broadcast(&tx1).unwrap();
blockchain.broadcast(&tx2).unwrap();
receiver_wallet.sync(&blockchain, noop_progress(), None).unwrap();
receiver_wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(receiver_wallet.get_balance().unwrap(), 49_000, "should have received coins once and only once");
}
@ -673,7 +673,7 @@ macro_rules! bdk_blockchain_tests {
});
}
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 100_000);
}
@ -688,7 +688,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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<_, _>>();
@ -696,7 +696,7 @@ macro_rules! bdk_blockchain_tests {
assert!(details.confirmation_time.is_none());
test_client.generate(1, Some(node_addr));
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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();
@ -712,7 +712,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -724,7 +724,7 @@ macro_rules! bdk_blockchain_tests {
let sent_tx = psbt.extract_tx();
blockchain.broadcast(&sent_tx).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after receive");
// empty wallet
@ -733,7 +733,7 @@ macro_rules! bdk_blockchain_tests {
#[cfg(feature = "rpc")] // rpc cannot see mempool tx before importmulti
test_client.generate(1, Some(node_addr));
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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();
@ -755,7 +755,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut total_sent = 0;
@ -767,12 +767,12 @@ macro_rules! bdk_blockchain_tests {
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
total_sent += 5_000 + details.fee.unwrap_or(0);
}
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent, "incorrect balance after chain");
// empty wallet
@ -782,7 +782,7 @@ macro_rules! bdk_blockchain_tests {
#[cfg(feature = "rpc")] // rpc cannot see mempool tx before importmulti
test_client.generate(1, Some(node_addr));
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent, "incorrect balance empty wallet");
}
@ -796,7 +796,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -805,7 +805,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -815,7 +815,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -831,7 +831,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -840,7 +840,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -850,7 +850,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance after change removal");
assert_eq!(new_details.received, 0, "incorrect received after change removal");
@ -866,7 +866,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -875,7 +875,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -885,7 +885,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(new_details.sent, 75_000, "incorrect sent");
assert_eq!(wallet.get_balance().unwrap(), new_details.received, "incorrect balance after add input");
}
@ -899,7 +899,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 75_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -908,7 +908,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -920,7 +920,7 @@ macro_rules! bdk_blockchain_tests {
let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
assert!(finalized, "Cannot finalize transaction");
blockchain.broadcast(&new_psbt.extract_tx()).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");
@ -935,7 +935,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 50_000, "incorrect balance");
let mut builder = wallet.build_tx();
@ -950,7 +950,7 @@ macro_rules! bdk_blockchain_tests {
assert!(serialized_tx.windows(data.len()).any(|e| e==data), "cannot find op_return data in transaction");
blockchain.broadcast(&tx).unwrap();
test_client.generate(1, Some(node_addr));
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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<_, _>>();
@ -963,7 +963,7 @@ macro_rules! bdk_blockchain_tests {
let wallet_addr = wallet.get_address($crate::wallet::AddressIndex::New).unwrap().address;
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert_eq!(wallet.get_balance().unwrap(), 0, "incorrect balance");
test_client.generate(1, Some(wallet_addr));
@ -976,7 +976,7 @@ macro_rules! bdk_blockchain_tests {
}
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).unwrap();
assert!(wallet.get_balance().unwrap() > 0, "incorrect balance after receiving coinbase");
}
@ -1052,7 +1052,7 @@ macro_rules! bdk_blockchain_tests {
@tx ( (@external descriptors, 0) => 50_000 )
});
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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
@ -1064,7 +1064,7 @@ macro_rules! bdk_blockchain_tests {
assert!(finalized, "wallet cannot finalize transaction");
let tx = psbt.extract_tx();
blockchain.broadcast(&tx).unwrap();
wallet.sync(&blockchain, noop_progress(), None).unwrap();
wallet.sync(&blockchain, SyncOptions::default()).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");

View 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::{GetHeight, Progress, WalletSync};
use crate::blockchain::{GetHeight, NoopProgress, Progress, WalletSync};
use crate::database::memory::MemoryDatabase;
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils, SyncTime};
use crate::descriptor::derived::AsDerived;
@ -156,6 +156,15 @@ impl fmt::Display for AddressInfo {
}
}
#[derive(Debug, Default)]
/// Options to a [`Wallet::sync`]
pub struct SyncOptions {
/// The progress tracker which may be informated when progress is made.
pub progress: Option<Box<dyn Progress>>,
/// The maximum number of addresses sync on.
pub max_addresses: Option<u32>,
}
impl<D> Wallet<D>
where
D: BatchDatabase,
@ -1432,27 +1441,26 @@ where
pub fn database(&self) -> impl std::ops::Deref<Target = D> + '_ {
self.database.borrow()
}
}
impl<D> Wallet<D>
where
D: BatchDatabase,
{
/// Sync the internal database with the blockchain
#[maybe_async]
pub fn sync<P: 'static + Progress, B: WalletSync + GetHeight>(
pub fn sync<B: WalletSync + GetHeight>(
&self,
blockchain: &B,
progress_update: P,
max_address_param: Option<u32>,
sync_opts: SyncOptions,
) -> Result<(), Error> {
debug!("Begin sync...");
let mut run_setup = false;
let SyncOptions {
max_addresses,
progress,
} = sync_opts;
let progress = progress.unwrap_or_else(|| Box::new(NoopProgress));
let max_address = match self.descriptor.is_deriveable() {
false => 0,
true => max_address_param.unwrap_or(CACHE_ADDR_BATCH_SIZE),
true => max_addresses.unwrap_or(CACHE_ADDR_BATCH_SIZE),
};
debug!("max_address {}", max_address);
if self
@ -1469,7 +1477,7 @@ where
if let Some(change_descriptor) = &self.change_descriptor {
let max_address = match change_descriptor.is_deriveable() {
false => 0,
true => max_address_param.unwrap_or(CACHE_ADDR_BATCH_SIZE),
true => max_addresses.unwrap_or(CACHE_ADDR_BATCH_SIZE),
};
if self
@ -1489,12 +1497,10 @@ where
// TODO: we should sync if generating an address triggers a new batch to be stored
if run_setup {
maybe_await!(
blockchain.wallet_setup(self.database.borrow_mut().deref_mut(), progress_update,)
blockchain.wallet_setup(self.database.borrow_mut().deref_mut(), progress,)
)?;
} else {
maybe_await!(
blockchain.wallet_sync(self.database.borrow_mut().deref_mut(), progress_update,)
)?;
maybe_await!(blockchain.wallet_sync(self.database.borrow_mut().deref_mut(), progress,))?;
}
#[cfg(feature = "verify")]