diff --git a/.github/workflows/cont_integration.yml b/.github/workflows/cont_integration.yml index 510af1dbf..8d63a8638 100644 --- a/.github/workflows/cont_integration.yml +++ b/.github/workflows/cont_integration.yml @@ -92,7 +92,7 @@ jobs: uses: Swatinem/rust-cache@v2.2.1 - name: Check bdk wallet working-directory: ./crates/wallet - run: cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown,dev-getrandom-wasm + run: cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown - name: Check esplora working-directory: ./crates/esplora run: cargo check --target wasm32-unknown-unknown --no-default-features --features miniscript/no-std,bdk_chain/hashbrown,async diff --git a/crates/wallet/Cargo.toml b/crates/wallet/Cargo.toml index e7e02093f..758ebf0fd 100644 --- a/crates/wallet/Cargo.toml +++ b/crates/wallet/Cargo.toml @@ -13,9 +13,9 @@ edition = "2021" rust-version = "1.63" [dependencies] -rand = "^0.8" +rand_core = { version = "0.6.0" } miniscript = { version = "12.0.0", features = ["serde"], default-features = false } -bitcoin = { version = "0.32.0", features = ["serde", "base64", "rand-std"], default-features = false } +bitcoin = { version = "0.32.0", features = ["serde", "base64"], default-features = false } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } bdk_chain = { path = "../chain", version = "0.16.0", features = ["miniscript", "serde"], default-features = false } @@ -23,10 +23,6 @@ bdk_chain = { path = "../chain", version = "0.16.0", features = ["miniscript", " # Optional dependencies bip39 = { version = "2.0", optional = true } -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = "0.2" -js-sys = "0.3" - [features] default = ["std"] std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"] @@ -34,11 +30,6 @@ compiler = ["miniscript/compiler"] all-keys = ["keys-bip39"] keys-bip39 = ["bip39"] -# This feature is used to run `cargo check` in our CI targeting wasm. It's not recommended -# for libraries to explicitly include the "getrandom/js" feature, so we only do it when -# necessary for running our CI. See: https://docs.rs/getrandom/0.2.8/getrandom/#webassembly-support -dev-getrandom-wasm = ["getrandom/js"] - [dev-dependencies] lazy_static = "1.4" assert_matches = "1.5.0" @@ -46,6 +37,7 @@ tempfile = "3" bdk_sqlite = { path = "../sqlite" } bdk_file_store = { path = "../file_store" } anyhow = "1" +rand = "^0.8" [package.metadata.docs.rs] all-features = true diff --git a/crates/wallet/README.md b/crates/wallet/README.md index ffe99474e..865a4fee3 100644 --- a/crates/wallet/README.md +++ b/crates/wallet/README.md @@ -154,6 +154,7 @@ fn main() { + @@ -173,7 +174,7 @@ fn main() { - + diff --git a/crates/wallet/examples/mnemonic_to_descriptors.rs b/crates/wallet/examples/mnemonic_to_descriptors.rs index 76c53cf29..ad1f1badc 100644 --- a/crates/wallet/examples/mnemonic_to_descriptors.rs +++ b/crates/wallet/examples/mnemonic_to_descriptors.rs @@ -15,6 +15,7 @@ use bdk_wallet::descriptor::IntoWalletDescriptor; use bdk_wallet::keys::bip39::{Language, Mnemonic, WordCount}; use bdk_wallet::keys::{GeneratableKey, GeneratedKey}; use bdk_wallet::miniscript::Tap; +use rand::thread_rng; use std::str::FromStr; /// This example demonstrates how to generate a mnemonic phrase @@ -25,8 +26,9 @@ fn main() -> Result<(), anyhow::Error> { // In this example we are generating a 12 words mnemonic phrase // but it is also possible generate 15, 18, 21 and 24 words // using their respective `WordCount` variant. + let mut rng = thread_rng(); let mnemonic: GeneratedKey<_, Tap> = - Mnemonic::generate((WordCount::Words12, Language::English)) + Mnemonic::generate((WordCount::Words12, Language::English), &mut rng) .map_err(|_| anyhow!("Mnemonic generation error"))?; println!("Mnemonic phrase: {}", *mnemonic); diff --git a/crates/wallet/src/keys/bip39.rs b/crates/wallet/src/keys/bip39.rs index 7158505f3..d1a8a4bac 100644 --- a/crates/wallet/src/keys/bip39.rs +++ b/crates/wallet/src/keys/bip39.rs @@ -158,6 +158,8 @@ mod test { use bip39::{Language, Mnemonic}; + use rand::thread_rng; + use crate::keys::{any_network, GeneratableKey, GeneratedKey}; use super::WordCount; @@ -216,12 +218,12 @@ mod test { #[test] fn test_keys_generate_bip39_random() { + let mut rng = thread_rng(); let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> = - Mnemonic::generate((WordCount::Words12, Language::English)).unwrap(); + Mnemonic::generate((WordCount::Words12, Language::English), &mut rng).unwrap(); assert_eq!(generated_mnemonic.valid_networks, any_network()); - let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> = - Mnemonic::generate((WordCount::Words24, Language::English)).unwrap(); + Mnemonic::generate((WordCount::Words24, Language::English), &mut rng).unwrap(); assert_eq!(generated_mnemonic.valid_networks, any_network()); } } diff --git a/crates/wallet/src/keys/mod.rs b/crates/wallet/src/keys/mod.rs index 108270348..939f8d8a8 100644 --- a/crates/wallet/src/keys/mod.rs +++ b/crates/wallet/src/keys/mod.rs @@ -20,6 +20,8 @@ use core::marker::PhantomData; use core::ops::Deref; use core::str::FromStr; +use rand_core::{CryptoRng, RngCore}; + use bitcoin::secp256k1::{self, Secp256k1, Signing}; use bitcoin::bip32; @@ -632,11 +634,12 @@ pub trait GeneratableKey: Sized { ) -> Result, Self::Error>; /// Generate a key given the options with a random entropy - fn generate(options: Self::Options) -> Result, Self::Error> { - use rand::{thread_rng, Rng}; - + fn generate( + options: Self::Options, + rng: &mut (impl CryptoRng + RngCore), + ) -> Result, Self::Error> { let mut entropy = Self::Entropy::default(); - thread_rng().fill(entropy.as_mut()); + rng.fill_bytes(entropy.as_mut()); Self::generate_with_entropy(options, entropy) } } @@ -657,8 +660,10 @@ where } /// Generate a key with the default options and a random entropy - fn generate_default() -> Result, Self::Error> { - Self::generate(Default::default()) + fn generate_default( + rng: &mut (impl CryptoRng + RngCore), + ) -> Result, Self::Error> { + Self::generate(Default::default(), rng) } } diff --git a/crates/wallet/src/wallet/coin_selection.rs b/crates/wallet/src/wallet/coin_selection.rs index 819a15edb..6a7617fbc 100644 --- a/crates/wallet/src/wallet/coin_selection.rs +++ b/crates/wallet/src/wallet/coin_selection.rs @@ -31,6 +31,8 @@ //! # use bdk_wallet::*; //! # use bdk_wallet::wallet::coin_selection::decide_change; //! # use anyhow::Error; +//! # use rand::{thread_rng, RngCore}; +//! //! #[derive(Debug)] //! struct AlwaysSpendEverything; //! @@ -92,7 +94,7 @@ //! let psbt = { //! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything); //! builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000)); -//! builder.finish()? +//! builder.finish_with_aux_rand(&mut thread_rng())? //! }; //! //! // inspect, sign, broadcast, ... @@ -114,8 +116,9 @@ use bitcoin::{Script, Weight}; use core::convert::TryInto; use core::fmt::{self, Formatter}; -use rand::seq::SliceRandom; +use rand_core::RngCore; +use super::utils::shuffle_slice; /// Default coin selection algorithm used by [`TxBuilder`](super::tx_builder::TxBuilder) if not /// overridden pub type DefaultCoinSelectionAlgorithm = BranchAndBoundCoinSelection; @@ -516,27 +519,16 @@ impl CoinSelectionAlgorithm for BranchAndBoundCoinSelection { )); } - Ok(self - .bnb( - required_utxos.clone(), - optional_utxos.clone(), - curr_value, - curr_available_value, - target_amount, - cost_of_change, - drain_script, - fee_rate, - ) - .unwrap_or_else(|_| { - self.single_random_draw( - required_utxos, - optional_utxos, - curr_value, - target_amount, - drain_script, - fee_rate, - ) - })) + self.bnb( + required_utxos.clone(), + optional_utxos.clone(), + curr_value, + curr_available_value, + target_amount, + cost_of_change, + drain_script, + fee_rate, + ) } } @@ -663,40 +655,6 @@ impl BranchAndBoundCoinSelection { )) } - #[allow(clippy::too_many_arguments)] - fn single_random_draw( - &self, - required_utxos: Vec, - mut optional_utxos: Vec, - curr_value: i64, - target_amount: i64, - drain_script: &Script, - fee_rate: FeeRate, - ) -> CoinSelectionResult { - optional_utxos.shuffle(&mut rand::thread_rng()); - let selected_utxos = optional_utxos.into_iter().fold( - (curr_value, vec![]), - |(mut amount, mut utxos), utxo| { - if amount >= target_amount { - (amount, utxos) - } else { - amount += utxo.effective_value; - utxos.push(utxo); - (amount, utxos) - } - }, - ); - - // remaining_amount can't be negative as that would mean the - // selection wasn't successful - // target_amount = amount_needed + (fee_amount - vin_fees) - let remaining_amount = (selected_utxos.0 - target_amount) as u64; - - let excess = decide_change(remaining_amount, fee_rate, drain_script); - - BranchAndBoundCoinSelection::calculate_cs_result(selected_utxos.1, required_utxos, excess) - } - fn calculate_cs_result( mut selected_utxos: Vec, mut required_utxos: Vec, @@ -717,6 +675,58 @@ impl BranchAndBoundCoinSelection { } } +// Pull UTXOs at random until we have enough to meet the target +pub(crate) fn single_random_draw( + required_utxos: Vec, + optional_utxos: Vec, + target_amount: u64, + drain_script: &Script, + fee_rate: FeeRate, + rng: &mut impl RngCore, +) -> CoinSelectionResult { + let target_amount = target_amount + .try_into() + .expect("Bitcoin amount to fit into i64"); + + let required_utxos: Vec = required_utxos + .into_iter() + .map(|u| OutputGroup::new(u, fee_rate)) + .collect(); + + let mut optional_utxos: Vec = optional_utxos + .into_iter() + .map(|u| OutputGroup::new(u, fee_rate)) + .collect(); + + let curr_value = required_utxos + .iter() + .fold(0, |acc, x| acc + x.effective_value); + + shuffle_slice(&mut optional_utxos, rng); + + let selected_utxos = + optional_utxos + .into_iter() + .fold((curr_value, vec![]), |(mut amount, mut utxos), utxo| { + if amount >= target_amount { + (amount, utxos) + } else { + amount += utxo.effective_value; + utxos.push(utxo); + (amount, utxos) + } + }); + + // remaining_amount can't be negative as that would mean the + // selection wasn't successful + // target_amount = amount_needed + (fee_amount - vin_fees) + let remaining_amount = (selected_utxos.0 - target_amount) as u64; + + let excess = decide_change(remaining_amount, fee_rate, drain_script); + + BranchAndBoundCoinSelection::calculate_cs_result(selected_utxos.1, required_utxos, excess) +} + /// Remove duplicate UTXOs. /// /// If a UTXO appears in both `required` and `optional`, the appearance in `required` is kept. @@ -740,6 +750,7 @@ where mod test { use assert_matches::assert_matches; use core::str::FromStr; + use rand::rngs::StdRng; use bdk_chain::ConfirmationTime; use bitcoin::{Amount, ScriptBuf, TxIn, TxOut}; @@ -748,8 +759,7 @@ mod test { use crate::types::*; use crate::wallet::coin_selection::filter_duplicates; - use rand::rngs::StdRng; - use rand::seq::SliceRandom; + use rand::prelude::SliceRandom; use rand::{Rng, RngCore, SeedableRng}; // signature len (1WU) + signature and sighash (72WU) @@ -1090,13 +1100,12 @@ mod test { } #[test] + #[ignore = "SRD fn was moved out of BnB"] fn test_bnb_coin_selection_success() { // In this case bnb won't find a suitable match and single random draw will // select three outputs let utxos = generate_same_value_utxos(100_000, 20); - let drain_script = ScriptBuf::default(); - let target_amount = 250_000 + FEE_AMOUNT; let result = BranchAndBoundCoinSelection::default() @@ -1136,6 +1145,7 @@ mod test { } #[test] + #[ignore = "no exact match for bnb, previously fell back to SRD"] fn test_bnb_coin_selection_optional_are_enough() { let utxos = get_test_utxos(); let drain_script = ScriptBuf::default(); @@ -1156,6 +1166,26 @@ mod test { assert_eq!(result.fee_amount, 136); } + #[test] + fn test_single_random_draw_function_success() { + let seed = [0; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + let mut utxos = generate_random_utxos(&mut rng, 300); + let target_amount = sum_random_utxos(&mut rng, &mut utxos) + FEE_AMOUNT; + let fee_rate = FeeRate::from_sat_per_vb_unchecked(1); + let drain_script = ScriptBuf::default(); + let result = single_random_draw( + vec![], + utxos, + target_amount, + &drain_script, + fee_rate, + &mut rng, + ); + assert!(result.selected_amount() > target_amount); + assert_eq!(result.fee_amount, (result.selected.len() * 68) as u64); + } + #[test] #[ignore] fn test_bnb_coin_selection_required_not_enough() { @@ -1410,34 +1440,6 @@ mod test { } } - #[test] - fn test_single_random_draw_function_success() { - let seed = [0; 32]; - let mut rng: StdRng = SeedableRng::from_seed(seed); - let mut utxos = generate_random_utxos(&mut rng, 300); - let target_amount = sum_random_utxos(&mut rng, &mut utxos) + FEE_AMOUNT; - - let fee_rate = FeeRate::from_sat_per_vb_unchecked(1); - let utxos: Vec = utxos - .into_iter() - .map(|u| OutputGroup::new(u, fee_rate)) - .collect(); - - let drain_script = ScriptBuf::default(); - - let result = BranchAndBoundCoinSelection::default().single_random_draw( - vec![], - utxos, - 0, - target_amount as i64, - &drain_script, - fee_rate, - ); - - assert!(result.selected_amount() > target_amount); - assert_eq!(result.fee_amount, (result.selected.len() * 68) as u64); - } - #[test] fn test_bnb_exclude_negative_effective_value() { let utxos = get_test_utxos(); diff --git a/crates/wallet/src/wallet/error.rs b/crates/wallet/src/wallet/error.rs index b6c9375a4..4f250f340 100644 --- a/crates/wallet/src/wallet/error.rs +++ b/crates/wallet/src/wallet/error.rs @@ -44,9 +44,9 @@ impl fmt::Display for MiniscriptPsbtError { impl std::error::Error for MiniscriptPsbtError {} #[derive(Debug)] -/// Error returned from [`TxBuilder::finish`] +/// Error returned from [`TxBuilder::finish_with_aux_rand`] /// -/// [`TxBuilder::finish`]: crate::wallet::tx_builder::TxBuilder::finish +/// [`TxBuilder::finish_with_aux_rand`]: crate::wallet::tx_builder::TxBuilder::finish_with_aux_rand pub enum CreateTxError { /// There was a problem with the descriptors passed in Descriptor(DescriptorError), diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index 883e954a7..0cc5b1132 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -41,6 +41,8 @@ use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt}; use bitcoin::{constants::genesis_block, Amount}; use core::fmt; use core::ops::Deref; +use rand_core::RngCore; + use descriptor::error::Error as DescriptorError; use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier}; @@ -1210,6 +1212,7 @@ impl Wallet { /// # use bdk_wallet::wallet::ChangeSet; /// # use bdk_wallet::wallet::error::CreateTxError; /// # use anyhow::Error; + /// # use rand::thread_rng; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); @@ -1217,7 +1220,7 @@ impl Wallet { /// let mut builder = wallet.build_tx(); /// builder /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000)); - /// builder.finish()? + /// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// /// // sign and broadcast ... @@ -1237,6 +1240,7 @@ impl Wallet { &mut self, coin_selection: Cs, params: TxParams, + rng: &mut impl RngCore, ) -> Result { let keychains: BTreeMap<_, _> = self.indexed_graph.index.keychains().collect(); let external_descriptor = keychains.get(&KeychainKind::External).expect("must exist"); @@ -1463,13 +1467,31 @@ impl Wallet { let (required_utxos, optional_utxos) = coin_selection::filter_duplicates(required_utxos, optional_utxos); - let coin_selection = coin_selection.coin_select( - required_utxos, - optional_utxos, + let coin_selection = match coin_selection.coin_select( + required_utxos.clone(), + optional_utxos.clone(), fee_rate, outgoing.to_sat() + fee_amount, &drain_script, - )?; + ) { + Ok(res) => res, + Err(e) => match e { + coin_selection::Error::InsufficientFunds { .. } => { + return Err(CreateTxError::CoinSelection(e)); + } + coin_selection::Error::BnBNoExactMatch + | coin_selection::Error::BnBTotalTriesExceeded => { + coin_selection::single_random_draw( + required_utxos, + optional_utxos, + outgoing.to_sat() + fee_amount, + &drain_script, + fee_rate, + rng, + ) + } + }, + }; fee_amount += coin_selection.fee_amount; let excess = &coin_selection.excess; @@ -1533,7 +1555,7 @@ impl Wallet { }; // sort input/outputs according to the chosen algorithm - params.ordering.sort_tx(&mut tx); + params.ordering.sort_tx_with_aux_rand(&mut tx, rng); let psbt = self.complete_transaction(tx, coin_selection.selected, params)?; Ok(psbt) @@ -1555,6 +1577,7 @@ impl Wallet { /// # use bdk_wallet::wallet::ChangeSet; /// # use bdk_wallet::wallet::error::CreateTxError; /// # use anyhow::Error; + /// # use rand::thread_rng; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); @@ -1563,7 +1586,7 @@ impl Wallet { /// builder /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000)) /// .enable_rbf(); - /// builder.finish()? + /// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// let _ = wallet.sign(&mut psbt, SignOptions::default())?; /// let tx = psbt.clone().extract_tx().expect("tx"); @@ -1572,7 +1595,7 @@ impl Wallet { /// let mut builder = wallet.build_fee_bump(tx.compute_txid())?; /// builder /// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate")); - /// builder.finish()? + /// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// /// let _ = wallet.sign(&mut psbt, SignOptions::default())?; @@ -1732,13 +1755,14 @@ impl Wallet { /// # use bdk_wallet::*; /// # use bdk_wallet::wallet::ChangeSet; /// # use bdk_wallet::wallet::error::CreateTxError; + /// # use rand::thread_rng; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// let mut psbt = { /// let mut builder = wallet.build_tx(); /// builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000)); - /// builder.finish()? + /// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?; /// assert!(finalized, "we should have signed all the inputs"); @@ -1783,7 +1807,6 @@ impl Wallet { { signer.sign_transaction(psbt, &sign_options, &self.secp)?; } - // attempt to finalize if sign_options.try_finalize { self.finalize_psbt(psbt, sign_options) diff --git a/crates/wallet/src/wallet/signer.rs b/crates/wallet/src/wallet/signer.rs index 16194961a..3967ba413 100644 --- a/crates/wallet/src/wallet/signer.rs +++ b/crates/wallet/src/wallet/signer.rs @@ -607,7 +607,7 @@ fn sign_psbt_schnorr( }; let msg = &Message::from(hash); - let signature = secp.sign_schnorr(msg, &keypair); + let signature = secp.sign_schnorr_no_aux_rand(msg, &keypair); secp.verify_schnorr(&signature, msg, &XOnlyPublicKey::from_keypair(&keypair).0) .expect("invalid or corrupted schnorr signature"); diff --git a/crates/wallet/src/wallet/tx_builder.rs b/crates/wallet/src/wallet/tx_builder.rs index 02d6df59d..fbb478ad8 100644 --- a/crates/wallet/src/wallet/tx_builder.rs +++ b/crates/wallet/src/wallet/tx_builder.rs @@ -20,6 +20,7 @@ //! # use bdk_wallet::wallet::ChangeSet; //! # use bdk_wallet::wallet::error::CreateTxError; //! # use anyhow::Error; +//! # use rand::thread_rng; //! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); //! # let mut wallet = doctest_wallet!(); //! // create a TxBuilder from a wallet @@ -34,7 +35,7 @@ //! .do_not_spend_change() //! // Turn on RBF signaling //! .enable_rbf(); -//! let psbt = tx_builder.finish()?; +//! let psbt = tx_builder.finish_with_aux_rand(&mut thread_rng())?; //! # Ok::<(), anyhow::Error>(()) //! ``` @@ -45,8 +46,10 @@ use core::fmt; use bitcoin::psbt::{self, Psbt}; use bitcoin::script::PushBytes; use bitcoin::{absolute, Amount, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid}; +use rand_core::RngCore; use super::coin_selection::CoinSelectionAlgorithm; +use super::utils::shuffle_slice; use super::{CreateTxError, Wallet}; use crate::collections::{BTreeMap, HashSet}; use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; @@ -54,7 +57,7 @@ use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; /// A transaction builder /// /// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After -/// assigning it, you set options on it until finally calling [`finish`] to consume the builder and +/// assigning it, you set options on it until finally calling [`finish_with_aux_rand`] to consume the builder and /// generate the transaction. /// /// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls @@ -68,6 +71,7 @@ use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; /// # use bdk_wallet::wallet::ChangeSet; /// # use bdk_wallet::wallet::error::CreateTxError; /// # use anyhow::Error; +/// # use rand::thread_rng; /// # let mut wallet = doctest_wallet!(); /// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// # let addr2 = addr1.clone(); @@ -78,7 +82,7 @@ use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; /// .ordering(TxOrdering::Untouched) /// .add_recipient(addr1.script_pubkey(), Amount::from_sat(50_000)) /// .add_recipient(addr2.script_pubkey(), Amount::from_sat(50_000)); -/// builder.finish()? +/// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// /// // non-chaining @@ -88,7 +92,7 @@ use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; /// for addr in &[addr1, addr2] { /// builder.add_recipient(addr.script_pubkey(), Amount::from_sat(50_000)); /// } -/// builder.finish()? +/// builder.finish_with_aux_rand(&mut thread_rng())? /// }; /// /// assert_eq!(psbt1.unsigned_tx.output[..2], psbt2.unsigned_tx.output[..2]); @@ -102,7 +106,7 @@ use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo}; /// /// [`build_tx`]: Wallet::build_tx /// [`build_fee_bump`]: Wallet::build_fee_bump -/// [`finish`]: Self::finish +/// [`finish_with_aux_rand`]: Self::finish_with_aux_rand /// [`coin_selection`]: Self::coin_selection #[derive(Debug)] pub struct TxBuilder<'a, Cs> { @@ -354,11 +358,11 @@ impl<'a, Cs> TxBuilder<'a, Cs> { /// 2. The data in `non_witness_utxo` does not match what is in `outpoint`. /// /// Note unless you set [`only_witness_utxo`] any non-taproot `psbt_input` you pass to this - /// method must have `non_witness_utxo` set otherwise you will get an error when [`finish`] + /// method must have `non_witness_utxo` set otherwise you will get an error when [`finish_with_aux_rand`] /// is called. /// /// [`only_witness_utxo`]: Self::only_witness_utxo - /// [`finish`]: Self::finish + /// [`finish_with_aux_rand`]: Self::finish_with_aux_rand /// [`max_weight_to_satisfy`]: miniscript::Descriptor::max_weight_to_satisfy pub fn add_foreign_utxo( &mut self, @@ -639,6 +643,7 @@ impl<'a, Cs> TxBuilder<'a, Cs> { /// # use bdk_wallet::wallet::ChangeSet; /// # use bdk_wallet::wallet::error::CreateTxError; /// # use anyhow::Error; + /// # use rand::thread_rng; /// # let to_address = /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt") /// .unwrap() @@ -653,7 +658,7 @@ impl<'a, Cs> TxBuilder<'a, Cs> { /// .drain_to(to_address.script_pubkey()) /// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate")) /// .enable_rbf(); - /// let psbt = tx_builder.finish()?; + /// let psbt = tx_builder.finish_with_aux_rand(&mut thread_rng())?; /// # Ok::<(), anyhow::Error>(()) /// ``` /// @@ -675,10 +680,10 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs> { /// /// **WARNING**: To avoid change address reuse you must persist the changes resulting from one /// or more calls to this method before closing the wallet. See [`Wallet::reveal_next_address`]. - pub fn finish(self) -> Result { + pub fn finish_with_aux_rand(self, rng: &mut impl RngCore) -> Result { self.wallet .borrow_mut() - .create_tx(self.coin_selection, self.params) + .create_tx(self.coin_selection, self.params, rng) } } @@ -758,14 +763,12 @@ pub enum TxOrdering { impl TxOrdering { /// Sort transaction inputs and outputs by [`TxOrdering`] variant - pub fn sort_tx(&self, tx: &mut Transaction) { + pub fn sort_tx_with_aux_rand(self, tx: &mut Transaction, rng: &mut impl RngCore) { match self { TxOrdering::Untouched => {} TxOrdering::Shuffle => { - use rand::seq::SliceRandom; - let mut rng = rand::thread_rng(); - tx.input.shuffle(&mut rng); - tx.output.shuffle(&mut rng); + shuffle_slice(&mut tx.input, rng); + shuffle_slice(&mut tx.output, rng); } TxOrdering::Bip69Lexicographic => { tx.input.sort_unstable_by_key(|txin| { @@ -849,20 +852,16 @@ mod test { use bitcoin::consensus::deserialize; use bitcoin::hex::FromHex; use bitcoin::TxOut; + use rand::thread_rng; use super::*; - - #[test] - fn test_output_ordering_default_shuffle() { - assert_eq!(TxOrdering::default(), TxOrdering::Shuffle); - } - #[test] fn test_output_ordering_untouched() { let original_tx = ordering_test_tx!(); let mut tx = original_tx.clone(); + let mut rng = thread_rng(); - TxOrdering::Untouched.sort_tx(&mut tx); + TxOrdering::Untouched.sort_tx_with_aux_rand(&mut tx, &mut rng); assert_eq!(original_tx, tx); } @@ -871,10 +870,11 @@ mod test { fn test_output_ordering_shuffle() { let original_tx = ordering_test_tx!(); let mut tx = original_tx.clone(); + let mut rng = thread_rng(); (0..40) .find(|_| { - TxOrdering::Shuffle.sort_tx(&mut tx); + TxOrdering::Shuffle.sort_tx_with_aux_rand(&mut tx, &mut rng); original_tx.input != tx.input }) .expect("it should have moved the inputs at least once"); @@ -882,7 +882,7 @@ mod test { let mut tx = original_tx.clone(); (0..40) .find(|_| { - TxOrdering::Shuffle.sort_tx(&mut tx); + TxOrdering::Shuffle.sort_tx_with_aux_rand(&mut tx, &mut rng); original_tx.output != tx.output }) .expect("it should have moved the outputs at least once"); @@ -894,8 +894,9 @@ mod test { let original_tx = ordering_test_tx!(); let mut tx = original_tx; + let mut rng = thread_rng(); - TxOrdering::Bip69Lexicographic.sort_tx(&mut tx); + TxOrdering::Bip69Lexicographic.sort_tx_with_aux_rand(&mut tx, &mut rng); assert_eq!( tx.input[0].previous_output, diff --git a/crates/wallet/src/wallet/utils.rs b/crates/wallet/src/wallet/utils.rs index 402361134..b79f1eb2a 100644 --- a/crates/wallet/src/wallet/utils.rs +++ b/crates/wallet/src/wallet/utils.rs @@ -14,6 +14,8 @@ use bitcoin::{absolute, relative, Script, Sequence}; use miniscript::{MiniscriptKey, Satisfier, ToPublicKey}; +use rand_core::RngCore; + /// Trait to check if a value is below the dust limit. /// We are performing dust value calculation for a given script public key using rust-bitcoin to /// keep it compatible with network dust rate @@ -110,6 +112,19 @@ impl Satisfier for Older { } } +// The Knuth shuffling algorithm based on the original [Fisher-Yates method](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) +pub(crate) fn shuffle_slice(list: &mut [T], rng: &mut impl RngCore) { + if list.is_empty() { + return; + } + let mut current_index = list.len() - 1; + while current_index > 0 { + let random_index = rng.next_u32() as usize % (current_index + 1); + list.swap(current_index, random_index); + current_index -= 1; + } +} + pub(crate) type SecpCtx = Secp256k1; #[cfg(test)] @@ -118,9 +133,11 @@ mod test { // otherwise it's time-based pub(crate) const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 1 << 22; - use super::{check_nsequence_rbf, IsDust}; + use super::{check_nsequence_rbf, shuffle_slice, IsDust}; use crate::bitcoin::{Address, Network, Sequence}; + use alloc::vec::Vec; use core::str::FromStr; + use rand::{rngs::StdRng, thread_rng, SeedableRng}; #[test] fn test_is_dust() { @@ -182,4 +199,44 @@ mod test { ); assert!(result); } + + #[test] + fn test_shuffle_slice_empty_vec() { + let mut test: Vec = vec![]; + shuffle_slice(&mut test, &mut thread_rng()); + } + + #[test] + fn test_shuffle_slice_single_vec() { + let mut test: Vec = vec![0]; + shuffle_slice(&mut test, &mut thread_rng()); + } + + #[test] + fn test_shuffle_slice_duple_vec() { + let seed = [0; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + let mut test: Vec = vec![0, 1]; + shuffle_slice(&mut test, &mut rng); + assert_eq!(test, &[0, 1]); + let seed = [6; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + let mut test: Vec = vec![0, 1]; + shuffle_slice(&mut test, &mut rng); + assert_eq!(test, &[1, 0]); + } + + #[test] + fn test_shuffle_slice_multi_vec() { + let seed = [0; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + let mut test: Vec = vec![0, 1, 2, 4, 5]; + shuffle_slice(&mut test, &mut rng); + assert_eq!(test, &[2, 1, 0, 4, 5]); + let seed = [25; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); + let mut test: Vec = vec![0, 1, 2, 4, 5]; + shuffle_slice(&mut test, &mut rng); + assert_eq!(test, &[0, 4, 1, 2, 5]); + } } diff --git a/crates/wallet/tests/psbt.rs b/crates/wallet/tests/psbt.rs index 155bb143a..e0b838100 100644 --- a/crates/wallet/tests/psbt.rs +++ b/crates/wallet/tests/psbt.rs @@ -1,6 +1,7 @@ use bdk_wallet::bitcoin::{Amount, FeeRate, Psbt, TxIn}; use bdk_wallet::{psbt, KeychainKind, SignOptions}; use core::str::FromStr; +use rand::thread_rng; mod common; use common::*; @@ -15,7 +16,7 @@ fn test_psbt_malformed_psbt_input_legacy() { let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt.inputs.push(psbt_bip.inputs[0].clone()); let options = SignOptions { trust_witness_utxo: true, @@ -32,7 +33,7 @@ fn test_psbt_malformed_psbt_input_segwit() { let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt.inputs.push(psbt_bip.inputs[1].clone()); let options = SignOptions { trust_witness_utxo: true, @@ -48,7 +49,7 @@ fn test_psbt_malformed_tx_input() { let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt.unsigned_tx.input.push(TxIn::default()); let options = SignOptions { trust_witness_utxo: true, @@ -64,7 +65,7 @@ fn test_psbt_sign_with_finalized() { let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // add a finalized input psbt.inputs.push(psbt_bip.inputs[0].clone()); @@ -86,7 +87,7 @@ fn test_psbt_fee_rate_with_witness_utxo() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(expected_fee_rate); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee_amount = psbt.fee_amount(); assert!(fee_amount.is_some()); @@ -111,7 +112,7 @@ fn test_psbt_fee_rate_with_nonwitness_utxo() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(expected_fee_rate); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee_amount = psbt.fee_amount(); assert!(fee_amount.is_some()); let unfinalized_fee_rate = psbt.fee_rate().unwrap(); @@ -135,7 +136,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let mut builder = wpkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(expected_fee_rate); - let mut wpkh_psbt = builder.finish().unwrap(); + let mut wpkh_psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); wpkh_psbt.inputs[0].witness_utxo = None; wpkh_psbt.inputs[0].non_witness_utxo = None; @@ -149,7 +150,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let mut builder = pkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(expected_fee_rate); - let mut pkh_psbt = builder.finish().unwrap(); + let mut pkh_psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); pkh_psbt.inputs[0].non_witness_utxo = None; assert!(pkh_psbt.fee_amount().is_none()); @@ -178,7 +179,7 @@ fn test_psbt_multiple_internalkey_signers() { let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.drain_to(send_to.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let unsigned_tx = psbt.unsigned_tx.clone(); // Adds a signer for the wrong internal key, bdk should not use this key to sign diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 7303bdcd8..61e678594 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -24,6 +24,8 @@ use bitcoin::{ absolute, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Weight, }; +use rand::rngs::StdRng; +use rand::{thread_rng, SeedableRng}; mod common; use common::*; @@ -496,7 +498,10 @@ macro_rules! from_str { #[should_panic(expected = "NoRecipients")] fn test_create_tx_empty_recipients() { let (mut wallet, _) = get_funded_wallet_wpkh(); - wallet.build_tx().finish().unwrap(); + wallet + .build_tx() + .finish_with_aux_rand(&mut thread_rng()) + .unwrap(); } #[test] @@ -508,7 +513,7 @@ fn test_create_tx_manually_selected_empty_utxos() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .manually_selected_only(); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -519,7 +524,10 @@ fn test_create_tx_version_0() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .version(0); - assert!(matches!(builder.finish(), Err(CreateTxError::Version0))); + assert!(matches!( + builder.finish_with_aux_rand(&mut thread_rng()), + Err(CreateTxError::Version0) + )); } #[test] @@ -530,7 +538,10 @@ fn test_create_tx_version_1_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .version(1); - assert!(matches!(builder.finish(), Err(CreateTxError::Version1Csv))); + assert!(matches!( + builder.finish_with_aux_rand(&mut thread_rng()), + Err(CreateTxError::Version1Csv) + )); } #[test] @@ -541,7 +552,7 @@ fn test_create_tx_custom_version() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .version(42); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.version.0, 42); } @@ -553,7 +564,7 @@ fn test_create_tx_default_locktime_is_last_sync_height() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // Since we never synced the wallet we don't have a last_sync_height // we could use to try to prevent fee sniping. We default to 0. @@ -567,7 +578,7 @@ fn test_create_tx_fee_sniping_locktime_last_sync() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // If there's no current_height we're left with using the last sync height assert_eq!( @@ -582,7 +593,7 @@ fn test_create_tx_default_locktime_cltv() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 100_000); } @@ -596,7 +607,7 @@ fn test_create_tx_custom_locktime() { .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .current_height(630_001) .nlocktime(absolute::LockTime::from_height(630_000).unwrap()); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // When we explicitly specify a nlocktime // we don't try any fee sniping prevention trick @@ -612,7 +623,7 @@ fn test_create_tx_custom_locktime_compatible_with_cltv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .nlocktime(absolute::LockTime::from_height(630_000).unwrap()); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 630_000); } @@ -625,7 +636,7 @@ fn test_create_tx_custom_locktime_incompatible_with_cltv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .nlocktime(absolute::LockTime::from_height(50000).unwrap()); - assert!(matches!(builder.finish(), + assert!(matches!(builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::LockTime { requested, required }) if requested.to_consensus_u32() == 50_000 && required.to_consensus_u32() == 100_000)); } @@ -636,7 +647,7 @@ fn test_create_tx_no_rbf_csv() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6)); } @@ -649,7 +660,7 @@ fn test_create_tx_with_default_rbf_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // When CSV is enabled it takes precedence over the rbf value (unless forced by the user). // It will be set to the OP_CSV value, in this case 6 assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6)); @@ -663,7 +674,7 @@ fn test_create_tx_with_custom_rbf_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf_with_sequence(Sequence(3)); - assert!(matches!(builder.finish(), + assert!(matches!(builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::RbfSequenceCsv { rbf, csv }) if rbf.to_consensus_u32() == 3 && csv.to_consensus_u32() == 6)); } @@ -674,7 +685,7 @@ fn test_create_tx_no_rbf_cltv() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -687,7 +698,10 @@ fn test_create_tx_invalid_rbf_sequence() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf_with_sequence(Sequence(0xFFFFFFFE)); - assert!(matches!(builder.finish(), Err(CreateTxError::RbfSequence))); + assert!(matches!( + builder.finish_with_aux_rand(&mut thread_rng()), + Err(CreateTxError::RbfSequence) + )); } #[test] @@ -698,7 +712,7 @@ fn test_create_tx_custom_rbf_sequence() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf_with_sequence(Sequence(0xDEADBEEF)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xDEADBEEF)); } @@ -711,7 +725,7 @@ fn test_create_tx_change_policy() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .do_not_spend_change(); - assert!(builder.finish().is_ok()); + assert!(builder.finish_with_aux_rand(&mut thread_rng()).is_ok()); // wallet has no change, so setting `only_spend_change` // should cause tx building to fail @@ -720,7 +734,7 @@ fn test_create_tx_change_policy() { .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .only_spend_change(); assert!(matches!( - builder.finish(), + builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::CoinSelection( coin_selection::Error::InsufficientFunds { .. } )), @@ -733,7 +747,7 @@ fn test_create_tx_default_sequence() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -753,7 +767,7 @@ fn test_create_tx_drain_wallet_and_drain_to() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); @@ -775,7 +789,7 @@ fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() { .add_recipient(addr.script_pubkey(), Amount::from_sat(20_000)) .drain_to(drain_addr.script_pubkey()) .drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); let outputs = psbt.unsigned_tx.output; @@ -805,7 +819,7 @@ fn test_create_tx_drain_to_and_utxos() { .drain_to(addr.script_pubkey()) .add_utxos(&utxos) .unwrap(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); @@ -822,7 +836,7 @@ fn test_create_tx_drain_to_no_drain_wallet_no_utxos() { let drain_addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(drain_addr.script_pubkey()); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -831,7 +845,7 @@ fn test_create_tx_default_fee_rate() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_fee_rate!(psbt, fee.unwrap_or(Amount::ZERO), FeeRate::BROADCAST_MIN, @add_signature); @@ -845,7 +859,7 @@ fn test_create_tx_custom_fee_rate() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_fee_rate!(psbt, fee.unwrap_or(Amount::ZERO), FeeRate::from_sat_per_vb_unchecked(5), @add_signature); @@ -860,7 +874,7 @@ fn test_create_tx_absolute_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(Amount::from_sat(100)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(fee.unwrap_or(Amount::ZERO), Amount::from_sat(100)); @@ -880,7 +894,7 @@ fn test_create_tx_absolute_zero_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(Amount::ZERO); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(fee.unwrap_or(Amount::ZERO), Amount::ZERO); @@ -901,20 +915,21 @@ fn test_create_tx_absolute_high_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(Amount::from_sat(60_000)); - let _ = builder.finish().unwrap(); + let _ = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] fn test_create_tx_add_change() { use bdk_wallet::wallet::tx_builder::TxOrdering; - + let seed = [0; 32]; + let mut rng: StdRng = SeedableRng::from_seed(seed); let (mut wallet, _) = get_funded_wallet_wpkh(); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) - .ordering(TxOrdering::Untouched); - let psbt = builder.finish().unwrap(); + .ordering(TxOrdering::Shuffle); + let psbt = builder.finish_with_aux_rand(&mut rng).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 2); @@ -931,7 +946,7 @@ fn test_create_tx_skip_change_dust() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(49_800)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); @@ -950,7 +965,7 @@ fn test_create_tx_drain_to_dust_amount() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_rate(FeeRate::from_sat_per_vb_unchecked(454)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -962,7 +977,7 @@ fn test_create_tx_ordering_respected() { .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)) .add_recipient(addr.script_pubkey(), Amount::from_sat(10_000)) .ordering(bdk_wallet::wallet::tx_builder::TxOrdering::Bip69Lexicographic); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 3); @@ -980,7 +995,7 @@ fn test_create_tx_default_sighash() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.inputs[0].sighash_type, None); } @@ -993,7 +1008,7 @@ fn test_create_tx_custom_sighash() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)) .sighash(EcdsaSighashType::Single.into()); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!( psbt.inputs[0].sighash_type, @@ -1010,7 +1025,7 @@ fn test_create_tx_input_hd_keypaths() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.inputs[0].bip32_derivation.len(), 1); assert_eq!( @@ -1032,7 +1047,7 @@ fn test_create_tx_output_hd_keypaths() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.outputs[0].bip32_derivation.len(), 1); let expected_derivation_path = format!("m/44'/0'/0'/0/{}", addr.index); @@ -1054,7 +1069,7 @@ fn test_create_tx_set_redeem_script_p2sh() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!( psbt.inputs[0].redeem_script, @@ -1077,7 +1092,7 @@ fn test_create_tx_set_witness_script_p2wsh() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.inputs[0].redeem_script, None); assert_eq!( @@ -1098,7 +1113,7 @@ fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let script = ScriptBuf::from_hex( "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac", @@ -1116,7 +1131,7 @@ fn test_create_tx_non_witness_utxo() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_none()); @@ -1132,7 +1147,7 @@ fn test_create_tx_only_witness_utxo() { .drain_to(addr.script_pubkey()) .only_witness_utxo() .drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_none()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -1145,7 +1160,7 @@ fn test_create_tx_shwpkh_has_witness_utxo() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!(psbt.inputs[0].witness_utxo.is_some()); } @@ -1157,7 +1172,7 @@ fn test_create_tx_both_non_witness_utxo_and_witness_utxo_default() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -1195,7 +1210,7 @@ fn test_create_tx_add_utxo() { vout: 0, }) .unwrap(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); @@ -1246,7 +1261,7 @@ fn test_create_tx_manually_selected_insufficient() { }) .unwrap() .manually_selected_only(); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -1259,7 +1274,7 @@ fn test_create_tx_policy_path_required() { .assume_checked(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(10_000)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -1294,7 +1309,7 @@ fn test_create_tx_policy_path_no_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)) .policy_path(path, KeychainKind::External); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFF)); } @@ -1315,7 +1330,7 @@ fn test_create_tx_policy_path_use_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)) .policy_path(path, KeychainKind::External); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(144)); } @@ -1336,7 +1351,7 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000)) .policy_path(path, KeychainKind::External); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -1350,7 +1365,7 @@ fn test_create_tx_global_xpubs_with_origin() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .add_global_xpubs(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let key = bip32::Xpub::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("73756c7f").unwrap(); @@ -1390,7 +1405,7 @@ fn test_add_foreign_utxo() { foreign_utxo_satisfaction.to_wu() as usize, ) .unwrap(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); wallet1.insert_txout(utxo.outpoint, utxo.txout); let fee = check_fee!(wallet1, psbt); let sent_received = @@ -1470,7 +1485,7 @@ fn test_calculate_fee_with_missing_foreign_utxo() { foreign_utxo_satisfaction.to_wu() as usize, ) .unwrap(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); wallet1.calculate_fee(&tx).unwrap(); } @@ -1569,7 +1584,7 @@ fn test_add_foreign_utxo_only_witness_utxo() { ) .unwrap(); assert!( - builder.finish().is_err(), + builder.finish_with_aux_rand(&mut thread_rng()).is_err(), "psbt_input with witness_utxo should fail with only witness_utxo" ); } @@ -1589,7 +1604,7 @@ fn test_add_foreign_utxo_only_witness_utxo() { ) .unwrap(); assert!( - builder.finish().is_ok(), + builder.finish_with_aux_rand(&mut thread_rng()).is_ok(), "psbt_input with just witness_utxo should succeed when `only_witness_utxo` is enabled" ); } @@ -1609,7 +1624,7 @@ fn test_add_foreign_utxo_only_witness_utxo() { ) .unwrap(); assert!( - builder.finish().is_ok(), + builder.finish_with_aux_rand(&mut thread_rng()).is_ok(), "psbt_input with non_witness_utxo should succeed by default" ); } @@ -1636,7 +1651,7 @@ fn test_create_tx_global_xpubs_origin_missing() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .add_global_xpubs(); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -1648,7 +1663,7 @@ fn test_create_tx_global_xpubs_master_without_origin() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .add_global_xpubs(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let key = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("997a323b").unwrap(); @@ -1667,14 +1682,18 @@ fn test_bump_fee_irreplaceable_tx() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); - wallet.build_fee_bump(txid).unwrap().finish().unwrap(); + wallet + .build_fee_bump(txid) + .unwrap() + .finish_with_aux_rand(&mut thread_rng()) + .unwrap(); } #[test] @@ -1684,7 +1703,7 @@ fn test_bump_fee_confirmed_tx() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); @@ -1699,7 +1718,11 @@ fn test_bump_fee_confirmed_tx() { ) .unwrap(); - wallet.build_fee_bump(txid).unwrap().finish().unwrap(); + wallet + .build_fee_bump(txid) + .unwrap() + .finish_with_aux_rand(&mut thread_rng()) + .unwrap(); } #[test] @@ -1710,7 +1733,7 @@ fn test_bump_fee_low_fee_rate() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let feerate = psbt.fee_rate().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); @@ -1722,7 +1745,7 @@ fn test_bump_fee_low_fee_rate() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::BROADCAST_MIN); - let res = builder.finish(); + let res = builder.finish_with_aux_rand(&mut thread_rng()); assert_matches!( res, Err(CreateTxError::FeeRateTooLow { .. }), @@ -1744,7 +1767,7 @@ fn test_bump_fee_low_abs() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); @@ -1755,7 +1778,7 @@ fn test_bump_fee_low_abs() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::from_sat(10)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -1767,7 +1790,7 @@ fn test_bump_fee_zero_abs() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); @@ -1777,7 +1800,7 @@ fn test_bump_fee_zero_abs() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::ZERO); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -1790,7 +1813,7 @@ fn test_bump_fee_reduce_change() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); @@ -1804,7 +1827,7 @@ fn test_bump_fee_reduce_change() { let feerate = FeeRate::from_sat_per_kwu(625); // 2.5 sat/vb let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(feerate).enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -1840,7 +1863,7 @@ fn test_bump_fee_reduce_change() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::from_sat(200)); builder.enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -1890,7 +1913,7 @@ fn test_bump_fee_reduce_single_recipient() { .drain_to(addr.script_pubkey()) .drain_wallet() .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.clone().extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let original_fee = check_fee!(wallet, psbt); @@ -1909,7 +1932,7 @@ fn test_bump_fee_reduce_single_recipient() { .drain_to(addr.script_pubkey()) // drain wallet output amount will be re-calculated with new fee rate .drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -1938,7 +1961,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() { .drain_to(addr.script_pubkey()) .drain_wallet() .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let original_fee = check_fee!(wallet, psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); @@ -1956,7 +1979,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() { .drain_to(addr.script_pubkey()) // drain wallet output amount will be re-calculated with new fee rate .drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = &psbt.unsigned_tx; let sent_received = wallet.sent_and_received(tx); let fee = check_fee!(wallet, psbt); @@ -2011,7 +2034,7 @@ fn test_bump_fee_drain_wallet() { .unwrap() .manually_selected_only() .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); @@ -2027,7 +2050,7 @@ fn test_bump_fee_drain_wallet() { builder .drain_wallet() .fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx")); assert_eq!(sent_received.0, Amount::from_sat(75_000)); @@ -2079,7 +2102,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { .unwrap() .manually_selected_only() .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); @@ -2092,7 +2115,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { builder .manually_selected_only() .fee_rate(FeeRate::from_sat_per_vb_unchecked(255)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -2125,7 +2148,7 @@ fn test_bump_fee_add_input() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_details = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); @@ -2135,7 +2158,7 @@ fn test_bump_fee_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2182,7 +2205,7 @@ fn test_bump_fee_absolute_add_input() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); @@ -2192,7 +2215,7 @@ fn test_bump_fee_absolute_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::from_sat(6_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2245,7 +2268,7 @@ fn test_bump_fee_no_change_add_input_and_change() { .unwrap() .manually_selected_only() .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); @@ -2260,7 +2283,7 @@ fn test_bump_fee_no_change_add_input_and_change() { // the original output untouched. let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2309,7 +2332,7 @@ fn test_bump_fee_add_input_change_dust() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); @@ -2342,7 +2365,7 @@ fn test_bump_fee_add_input_change_dust() { // We use epsilon here to avoid asking for a slightly too high feerate let fee_abs = 50_000 + 25_000 - 45_000 - 10; builder.fee_rate(Amount::from_sat(fee_abs) / new_tx_weight); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2386,7 +2409,7 @@ fn test_bump_fee_force_add_input() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); @@ -2403,7 +2426,7 @@ fn test_bump_fee_force_add_input() { .add_utxo(incoming_op) .unwrap() .fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2452,7 +2475,7 @@ fn test_bump_fee_absolute_force_add_input() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); @@ -2471,7 +2494,7 @@ fn test_bump_fee_absolute_force_add_input() { .add_utxo(incoming_op) .unwrap() .fee_absolute(Amount::from_sat(250)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); @@ -2526,7 +2549,7 @@ fn test_bump_fee_unconfirmed_inputs_only() { .drain_wallet() .drain_to(addr.script_pubkey()) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // Now we receive one transaction with 0 confirmations. We won't be able to use that for // fee bumping, as it's still unconfirmed! receive_output( @@ -2544,7 +2567,7 @@ fn test_bump_fee_unconfirmed_inputs_only() { .unwrap(); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(25)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -2566,7 +2589,7 @@ fn test_bump_fee_unconfirmed_input() { .drain_wallet() .drain_to(addr.script_pubkey()) .enable_rbf(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); for txin in &mut tx.input { @@ -2585,7 +2608,7 @@ fn test_bump_fee_unconfirmed_input() { .drain_to(addr.script_pubkey()) // drain wallet output amount will be re-calculated with new fee rate .drain_wallet(); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -2612,7 +2635,7 @@ fn test_fee_amount_negative_drain_val() { .unwrap() .enable_rbf() .fee_rate(fee_rate); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); assert_eq!(psbt.inputs.len(), 1); @@ -2625,7 +2648,7 @@ fn test_sign_single_xprv() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2640,7 +2663,7 @@ fn test_sign_single_xprv_with_master_fingerprint_and_path() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2655,7 +2678,7 @@ fn test_sign_single_xprv_bip44_path() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2670,7 +2693,7 @@ fn test_sign_single_xprv_sh_wpkh() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2686,7 +2709,7 @@ fn test_sign_single_wif() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2701,7 +2724,7 @@ fn test_sign_single_xprv_no_hd_keypaths() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt.inputs[0].bip32_derivation.clear(); assert_eq!(psbt.inputs[0].bip32_derivation.len(), 0); @@ -2725,7 +2748,7 @@ fn test_include_output_redeem_witness_script() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .include_output_redeem_witness_script(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // p2sh-p2wsh transaction should contain both witness and redeem scripts assert!(psbt @@ -2744,7 +2767,7 @@ fn test_signing_only_one_of_multiple_inputs() { builder .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)) .include_output_redeem_witness_script(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // add another input to the psbt that is at least passable. let dud_input = bitcoin::psbt::Input { @@ -2788,7 +2811,7 @@ fn test_remove_partial_sigs_after_finalize_sign_option() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!(wallet .sign( @@ -2818,7 +2841,7 @@ fn test_try_finalize_sign_option() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet .sign( @@ -2855,7 +2878,7 @@ fn test_sign_nonstandard_sighash() { .drain_to(addr.script_pubkey()) .sighash(sighash.into()) .drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let result = wallet.sign(&mut psbt, Default::default()); assert!( @@ -3085,7 +3108,7 @@ fn test_sending_to_bip350_bech32m_address() { .assume_checked(); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(45_000)); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -3171,7 +3194,7 @@ fn test_taproot_remove_tapfields_after_finalize_sign_option() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let finalized = wallet.sign(&mut psbt, SignOptions::default()).unwrap(); assert!(finalized); @@ -3198,7 +3221,7 @@ fn test_taproot_psbt_populate_tap_key_origins() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!( psbt.inputs[0] @@ -3241,7 +3264,7 @@ fn test_taproot_psbt_populate_tap_key_origins_repeated_key() { .drain_to(addr.script_pubkey()) .drain_wallet() .policy_path(path, KeychainKind::External); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut input_key_origins = psbt.inputs[0] .tap_key_origins @@ -3301,7 +3324,7 @@ fn test_taproot_psbt_input_tap_tree() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert_eq!( psbt.inputs[0].tap_merkle_root, @@ -3343,7 +3366,7 @@ fn test_taproot_sign_missing_witness_utxo() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let witness_utxo = psbt.inputs[0].witness_utxo.take(); let result = wallet.sign( @@ -3383,7 +3406,7 @@ fn test_taproot_sign_using_non_witness_utxo() { let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt.inputs[0].witness_utxo = None; psbt.inputs[0].non_witness_utxo = @@ -3430,7 +3453,7 @@ fn test_taproot_foreign_utxo() { foreign_utxo_satisfaction.to_wu() as usize, ) .unwrap(); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet1.insert_txout(utxo.outpoint, utxo.txout); @@ -3456,7 +3479,7 @@ fn test_spend_from_wallet(mut wallet: Wallet) { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!( wallet.sign(&mut psbt, Default::default()).unwrap(), @@ -3480,7 +3503,7 @@ fn test_taproot_no_key_spend() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!( wallet @@ -3515,7 +3538,7 @@ fn test_taproot_script_spend_sign_all_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); assert!( wallet @@ -3546,7 +3569,7 @@ fn test_taproot_script_spend_sign_include_some_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut script_leaves: Vec<_> = psbt.inputs[0] .tap_scripts .clone() @@ -3586,7 +3609,7 @@ fn test_taproot_script_spend_sign_exclude_some_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let mut script_leaves: Vec<_> = psbt.inputs[0] .tap_scripts .clone() @@ -3624,7 +3647,7 @@ fn test_taproot_script_spend_sign_no_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); wallet .sign( @@ -3647,7 +3670,7 @@ fn test_taproot_sign_derive_index_from_psbt() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); // re-create the wallet with an empty db let wallet_empty = Wallet::new( @@ -3674,7 +3697,7 @@ fn test_taproot_sign_explicit_sighash_all() { .drain_to(addr.script_pubkey()) .sighash(TapSighashType::All.into()) .drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let result = wallet.sign(&mut psbt, Default::default()); assert!( @@ -3694,7 +3717,7 @@ fn test_taproot_sign_non_default_sighash() { .drain_to(addr.script_pubkey()) .sighash(sighash.into()) .drain_wallet(); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let witness_utxo = psbt.inputs[0].witness_utxo.take(); @@ -3812,7 +3835,7 @@ fn test_spend_coinbase() { .add_recipient(addr.script_pubkey(), balance.immature / 2) .current_height(confirmation_height); assert!(matches!( - builder.finish(), + builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::CoinSelection( coin_selection::Error::InsufficientFunds { needed: _, @@ -3827,7 +3850,7 @@ fn test_spend_coinbase() { .add_recipient(addr.script_pubkey(), balance.immature / 2) .current_height(not_yet_mature_time); assert_matches!( - builder.finish(), + builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::CoinSelection( coin_selection::Error::InsufficientFunds { needed: _, @@ -3856,7 +3879,7 @@ fn test_spend_coinbase() { builder .add_recipient(addr.script_pubkey(), balance.confirmed / 2) .current_height(maturity_time); - builder.finish().unwrap(); + builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); } #[test] @@ -3870,7 +3893,7 @@ fn test_allow_dust_limit() { builder.add_recipient(addr.script_pubkey(), Amount::ZERO); assert_matches!( - builder.finish(), + builder.finish_with_aux_rand(&mut thread_rng()), Err(CreateTxError::OutputBelowDustLimit(0)) ); @@ -3880,7 +3903,7 @@ fn test_allow_dust_limit() { .allow_dust(true) .add_recipient(addr.script_pubkey(), Amount::ZERO); - assert!(builder.finish().is_ok()); + assert!(builder.finish_with_aux_rand(&mut thread_rng()).is_ok()); } #[test] @@ -3898,7 +3921,7 @@ fn test_fee_rate_sign_no_grinding_high_r() { .drain_wallet() .fee_rate(fee_rate) .add_data(&data); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); let (op_return_vout, _) = psbt .unsigned_tx @@ -3965,7 +3988,7 @@ fn test_fee_rate_sign_grinding_low_r() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_rate(fee_rate); - let mut psbt = builder.finish().unwrap(); + let mut psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); let fee = check_fee!(wallet, psbt); wallet @@ -4014,7 +4037,7 @@ fn test_tx_cancellation() { let mut builder = $wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(10_000)); - let psbt = builder.finish().unwrap(); + let psbt = builder.finish_with_aux_rand(&mut thread_rng()).unwrap(); psbt }}; diff --git a/example-crates/wallet_electrum/Cargo.toml b/example-crates/wallet_electrum/Cargo.toml index 2f562837f..7ca7fdc6e 100644 --- a/example-crates/wallet_electrum/Cargo.toml +++ b/example-crates/wallet_electrum/Cargo.toml @@ -8,3 +8,4 @@ bdk_wallet = { path = "../../crates/wallet" } bdk_electrum = { path = "../../crates/electrum" } bdk_file_store = { path = "../../crates/file_store" } anyhow = "1" +rand = "0.8.0" diff --git a/example-crates/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs index 2adf090aa..65aced9dc 100644 --- a/example-crates/wallet_electrum/src/main.rs +++ b/example-crates/wallet_electrum/src/main.rs @@ -14,6 +14,7 @@ use bdk_wallet::bitcoin::{Address, Amount}; use bdk_wallet::chain::collections::HashSet; use bdk_wallet::{bitcoin::Network, Wallet}; use bdk_wallet::{KeychainKind, SignOptions}; +use rand::thread_rng; fn main() -> Result<(), anyhow::Error> { let db_path = std::env::temp_dir().join("bdk-electrum-example"); @@ -96,7 +97,7 @@ fn main() -> Result<(), anyhow::Error> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let mut psbt = tx_builder.finish()?; + let mut psbt = tx_builder.finish_with_aux_rand(&mut thread_rng())?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); diff --git a/example-crates/wallet_esplora_async/Cargo.toml b/example-crates/wallet_esplora_async/Cargo.toml index 2a71622ca..5c1745e41 100644 --- a/example-crates/wallet_esplora_async/Cargo.toml +++ b/example-crates/wallet_esplora_async/Cargo.toml @@ -11,3 +11,4 @@ bdk_esplora = { path = "../../crates/esplora", features = ["async-https"] } bdk_sqlite = { path = "../../crates/sqlite" } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } anyhow = "1" +rand = "0.8.0" diff --git a/example-crates/wallet_esplora_async/src/main.rs b/example-crates/wallet_esplora_async/src/main.rs index 0fd82b985..6b97af7fc 100644 --- a/example-crates/wallet_esplora_async/src/main.rs +++ b/example-crates/wallet_esplora_async/src/main.rs @@ -5,6 +5,7 @@ use bdk_wallet::{ bitcoin::{Address, Amount, Network, Script}, KeychainKind, SignOptions, Wallet, }; +use rand::thread_rng; use bdk_sqlite::{rusqlite::Connection, Store}; @@ -103,7 +104,7 @@ async fn main() -> Result<(), anyhow::Error> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let mut psbt = tx_builder.finish()?; + let mut psbt = tx_builder.finish_with_aux_rand(&mut thread_rng())?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); diff --git a/example-crates/wallet_esplora_blocking/Cargo.toml b/example-crates/wallet_esplora_blocking/Cargo.toml index 857660acf..88f71cdb1 100644 --- a/example-crates/wallet_esplora_blocking/Cargo.toml +++ b/example-crates/wallet_esplora_blocking/Cargo.toml @@ -11,3 +11,4 @@ bdk_wallet = { path = "../../crates/wallet" } bdk_esplora = { path = "../../crates/esplora", features = ["blocking"] } bdk_file_store = { path = "../../crates/file_store" } anyhow = "1" +rand = "0.8.0" diff --git a/example-crates/wallet_esplora_blocking/src/main.rs b/example-crates/wallet_esplora_blocking/src/main.rs index 32211b04b..056ed59f4 100644 --- a/example-crates/wallet_esplora_blocking/src/main.rs +++ b/example-crates/wallet_esplora_blocking/src/main.rs @@ -11,6 +11,7 @@ use bdk_wallet::{ bitcoin::{Address, Amount, Network}, KeychainKind, SignOptions, Wallet, }; +use rand::thread_rng; fn main() -> Result<(), anyhow::Error> { let db_path = std::env::temp_dir().join("bdk-esplora-example"); @@ -80,7 +81,7 @@ fn main() -> Result<(), anyhow::Error> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let mut psbt = tx_builder.finish()?; + let mut psbt = tx_builder.finish_with_aux_rand(&mut thread_rng())?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized);