diff --git a/Cargo.toml b/Cargo.toml index d34710a6e0..3e745e8874 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightn bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] } bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]} bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls-ring"]} -bdk_wallet = { version = "2.3.0", default-features = false, features = ["std", "keys-bip39"]} +bdk_wallet = { version = "3.0.0", default-features = false, features = ["std", "keys-bip39"]} bitreq = { version = "0.3", default-features = false, features = ["async-https", "json-using-serde"] } rustls = { version = "0.23", default-features = false } diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index daeb7becb3..de11517e86 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -13,10 +13,9 @@ use std::sync::{Arc, Mutex}; use bdk_chain::spk_client::{FullScanRequest, SyncRequest}; use bdk_wallet::descriptor::ExtendedDescriptor; use bdk_wallet::error::{BuildFeeBumpError, CreateTxError}; -use bdk_wallet::event::WalletEvent; #[allow(deprecated)] use bdk_wallet::SignOptions; -use bdk_wallet::{Balance, KeychainKind, PersistedWallet, Update}; +use bdk_wallet::{Balance, KeychainKind, PersistedWallet, Update, WalletEvent}; use bitcoin::address::NetworkUnchecked; use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR; use bitcoin::blockdata::locktime::absolute::LockTime; @@ -181,30 +180,13 @@ impl Wallet { } let mut locked_wallet = self.inner.lock().expect("lock"); - - let chain_tip1 = locked_wallet.latest_checkpoint().block_id(); - let wallet_txs1 = locked_wallet - .transactions() - .map(|wtx| (wtx.tx_node.txid, (wtx.tx_node.tx.clone(), wtx.chain_position))) - .collect::, bdk_chain::ChainPosition), - >>(); - - locked_wallet.apply_unconfirmed_txs(unconfirmed_txs); - locked_wallet.apply_evicted_txs(evicted_txids); - - let chain_tip2 = locked_wallet.latest_checkpoint().block_id(); - let wallet_txs2 = locked_wallet - .transactions() - .map(|wtx| (wtx.tx_node.txid, (wtx.tx_node.tx.clone(), wtx.chain_position))) - .collect::, bdk_chain::ChainPosition), - >>(); - - let events = - wallet_events(&mut *locked_wallet, chain_tip1, chain_tip2, wallet_txs1, wallet_txs2); + let events = locked_wallet + .events_helper(|wallet| { + wallet.apply_unconfirmed_txs(unconfirmed_txs); + wallet.apply_evicted_txs(evicted_txids); + Ok::<(), std::convert::Infallible>(()) + }) + .expect("infallible"); self.update_payment_store(&mut *locked_wallet, events).map_err(|e| { log_error!(self.logger, "Failed to update payment store: {}", e); @@ -504,7 +486,7 @@ impl Wallet { let mut locked_wallet = self.inner.lock().expect("lock"); let mut locked_persister = self.persister.lock().expect("lock"); - locked_wallet.cancel_tx(tx); + reclaim_tx_outputs(&mut locked_wallet, tx); locked_wallet.persist(&mut locked_persister).map_err(|e| { log_error!(self.logger, "Failed to persist wallet: {}", e); Error::PersistenceFailed @@ -593,7 +575,7 @@ impl Wallet { /// Builds a temporary drain transaction and returns the maximum amount that would be sent to /// the drain output, along with the PSBT for further inspection. /// - /// The caller is responsible for cancelling the PSBT via `locked_wallet.cancel_tx()`. + /// The caller is responsible for reclaiming any used addresses from the PSBT. fn get_max_drain_amount( &self, locked_wallet: &mut PersistedWallet, drain_script: ScriptBuf, cur_anchor_reserve_sats: u64, fee_rate: FeeRate, @@ -665,7 +647,7 @@ impl Wallet { None, )?; - locked_wallet.cancel_tx(&tmp_psbt.unsigned_tx); + reclaim_tx_outputs(&mut locked_wallet, &tmp_psbt.unsigned_tx); Ok(max_amount) } @@ -695,7 +677,7 @@ impl Wallet { Some(&shared_input), )?; - locked_wallet.cancel_tx(&tmp_psbt.unsigned_tx); + reclaim_tx_outputs(&mut locked_wallet, &tmp_psbt.unsigned_tx); Ok(splice_amount) } @@ -751,7 +733,7 @@ impl Wallet { e })?; - locked_wallet.cancel_tx(&tmp_psbt.unsigned_tx); + reclaim_tx_outputs(&mut locked_wallet, &tmp_psbt.unsigned_tx); let mut tx_builder = locked_wallet.build_tx(); tx_builder @@ -1427,6 +1409,18 @@ impl Wallet { } } +fn reclaim_tx_outputs( + locked_wallet: &mut PersistedWallet, tx: &Transaction, +) { + for output in &tx.output { + if let Some((keychain, index)) = + locked_wallet.derivation_of_spk(output.script_pubkey.clone()) + { + locked_wallet.unmark_used(keychain, index); + } + } +} + impl Listen for Wallet { fn filtered_block_connected( &self, _header: &bitcoin::block::Header, @@ -1716,105 +1710,3 @@ impl ChangeDestinationSource for WalletKeysManager { } } } - -// FIXME/TODO: This is copied-over from bdk_wallet and only used to generate `WalletEvent`s after -// applying mempool transactions. We should drop this when BDK offers to generate events for -// mempool transactions natively. -pub(crate) fn wallet_events( - wallet: &mut bdk_wallet::Wallet, chain_tip1: bdk_chain::BlockId, - chain_tip2: bdk_chain::BlockId, - wallet_txs1: std::collections::BTreeMap< - Txid, - (Arc, bdk_chain::ChainPosition), - >, - wallet_txs2: std::collections::BTreeMap< - Txid, - (Arc, bdk_chain::ChainPosition), - >, -) -> Vec { - let mut events: Vec = Vec::new(); - - if chain_tip1 != chain_tip2 { - events.push(WalletEvent::ChainTipChanged { old_tip: chain_tip1, new_tip: chain_tip2 }); - } - - wallet_txs2.iter().for_each(|(txid2, (tx2, cp2))| { - if let Some((tx1, cp1)) = wallet_txs1.get(txid2) { - assert_eq!(tx1.compute_txid(), *txid2); - match (cp1, cp2) { - ( - bdk_chain::ChainPosition::Unconfirmed { .. }, - bdk_chain::ChainPosition::Confirmed { anchor, .. }, - ) => { - events.push(WalletEvent::TxConfirmed { - txid: *txid2, - tx: tx2.clone(), - block_time: *anchor, - old_block_time: None, - }); - }, - ( - bdk_chain::ChainPosition::Confirmed { anchor, .. }, - bdk_chain::ChainPosition::Unconfirmed { .. }, - ) => { - events.push(WalletEvent::TxUnconfirmed { - txid: *txid2, - tx: tx2.clone(), - old_block_time: Some(*anchor), - }); - }, - ( - bdk_chain::ChainPosition::Confirmed { anchor: anchor1, .. }, - bdk_chain::ChainPosition::Confirmed { anchor: anchor2, .. }, - ) => { - if *anchor1 != *anchor2 { - events.push(WalletEvent::TxConfirmed { - txid: *txid2, - tx: tx2.clone(), - block_time: *anchor2, - old_block_time: Some(*anchor1), - }); - } - }, - ( - bdk_chain::ChainPosition::Unconfirmed { .. }, - bdk_chain::ChainPosition::Unconfirmed { .. }, - ) => { - // do nothing if still unconfirmed - }, - } - } else { - match cp2 { - bdk_chain::ChainPosition::Confirmed { anchor, .. } => { - events.push(WalletEvent::TxConfirmed { - txid: *txid2, - tx: tx2.clone(), - block_time: *anchor, - old_block_time: None, - }); - }, - bdk_chain::ChainPosition::Unconfirmed { .. } => { - events.push(WalletEvent::TxUnconfirmed { - txid: *txid2, - tx: tx2.clone(), - old_block_time: None, - }); - }, - } - } - }); - - // find tx that are no longer canonical - wallet_txs1.iter().for_each(|(txid1, (tx1, _))| { - if !wallet_txs2.contains_key(txid1) { - let conflicts = wallet.tx_graph().direct_conflicts(tx1).collect::>(); - if !conflicts.is_empty() { - events.push(WalletEvent::TxReplaced { txid: *txid1, tx: tx1.clone(), conflicts }); - } else { - events.push(WalletEvent::TxDropped { txid: *txid1, tx: tx1.clone() }); - } - } - }); - - events -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 00c8808a7b..8d667eb9ee 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -115,6 +115,7 @@ macro_rules! expect_channel_pending_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_channel_pending_event; macro_rules! expect_channel_ready_event { @@ -141,8 +142,10 @@ macro_rules! expect_channel_ready_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_channel_ready_event; +#[allow(unused_macros)] macro_rules! expect_channel_ready_events { ($node:expr, $counterparty_node_id_a:expr, $counterparty_node_id_b:expr) => {{ let mut ids = Vec::new(); @@ -177,6 +180,7 @@ macro_rules! expect_channel_ready_events { }}; } +#[allow(unused_imports)] pub(crate) use expect_channel_ready_events; macro_rules! expect_splice_pending_event { @@ -203,6 +207,7 @@ macro_rules! expect_splice_pending_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_splice_pending_event; macro_rules! expect_payment_received_event { @@ -233,6 +238,7 @@ macro_rules! expect_payment_received_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_payment_received_event; macro_rules! expect_payment_claimable_event { @@ -269,6 +275,7 @@ macro_rules! expect_payment_claimable_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_payment_claimable_event; macro_rules! expect_payment_successful_event { @@ -299,6 +306,7 @@ macro_rules! expect_payment_successful_event { }}; } +#[allow(unused_imports)] pub(crate) use expect_payment_successful_event; pub(crate) fn setup_bitcoind_and_electrsd() -> (BitcoinD, ElectrsD) { @@ -464,6 +472,7 @@ macro_rules! setup_builder { }; } +#[allow(unused_imports)] pub(crate) use setup_builder; #[cfg(any(cln_test, lnd_test, eclair_test))]