From 853d3617514edebd0d7b6542a78b5874225a5473 Mon Sep 17 00:00:00 2001 From: Daniela Brozzoni Date: Wed, 21 Jun 2023 17:59:34 +0200 Subject: [PATCH 01/12] Update bdk_chain to bitcoin 0.30.0 --- crates/chain/Cargo.toml | 4 +- crates/chain/src/chain_data.rs | 2 +- crates/chain/src/descriptor_ext.rs | 2 + crates/chain/src/keychain/txout_index.rs | 2 +- crates/chain/src/spk_iter.rs | 27 ++++---- crates/chain/src/spk_txout_index.rs | 16 ++--- crates/chain/tests/common/mod.rs | 2 +- crates/chain/tests/test_indexed_tx_graph.rs | 28 +++++---- .../chain/tests/test_keychain_txout_index.rs | 51 +++++++++------ crates/chain/tests/test_spk_txout_index.rs | 16 ++--- crates/chain/tests/test_tx_graph.rs | 62 +++++++++---------- 11 files changed, 115 insertions(+), 97 deletions(-) diff --git a/crates/chain/Cargo.toml b/crates/chain/Cargo.toml index c25dd712..8aeca3f7 100644 --- a/crates/chain/Cargo.toml +++ b/crates/chain/Cargo.toml @@ -14,13 +14,13 @@ readme = "README.md" [dependencies] # For no-std, remember to enable the bitcoin/no-std feature -bitcoin = { version = "0.29", default-features = false } +bitcoin = { version = "0.30.0", default-features = false } serde_crate = { package = "serde", version = "1", optional = true, features = ["derive"] } # Use hashbrown as a feature flag to have HashSet and HashMap from it. # note version 0.13 breaks outs MSRV. hashbrown = { version = "0.11", optional = true, features = ["serde"] } -miniscript = { version = "9.0.0", optional = true, default-features = false } +miniscript = { version = "10.0.0", optional = true, default-features = false } [dev-dependencies] rand = "0.8" diff --git a/crates/chain/src/chain_data.rs b/crates/chain/src/chain_data.rs index bd174c2e..16877637 100644 --- a/crates/chain/src/chain_data.rs +++ b/crates/chain/src/chain_data.rs @@ -104,7 +104,7 @@ impl Default for BlockId { fn default() -> Self { Self { height: Default::default(), - hash: BlockHash::from_inner([0u8; 32]), + hash: BlockHash::all_zeros(), } } } diff --git a/crates/chain/src/descriptor_ext.rs b/crates/chain/src/descriptor_ext.rs index a3565195..4c77c160 100644 --- a/crates/chain/src/descriptor_ext.rs +++ b/crates/chain/src/descriptor_ext.rs @@ -3,12 +3,14 @@ use crate::miniscript::{Descriptor, DescriptorPublicKey}; /// A trait to extend the functionality of a miniscript descriptor. pub trait DescriptorExt { /// Returns the minimum value (in satoshis) at which an output is broadcastable. + /// Panics if the descriptor wildcard is hardened. fn dust_value(&self) -> u64; } impl DescriptorExt for Descriptor { fn dust_value(&self) -> u64 { self.at_derivation_index(0) + .expect("descriptor can't have hardened derivation") .script_pubkey() .dust_value() .to_sat() diff --git a/crates/chain/src/keychain/txout_index.rs b/crates/chain/src/keychain/txout_index.rs index 8c16afc0..2c5d8d1c 100644 --- a/crates/chain/src/keychain/txout_index.rs +++ b/crates/chain/src/keychain/txout_index.rs @@ -313,7 +313,7 @@ impl KeychainTxOutIndex { self.inner .all_spks() .range((keychain.clone(), u32::MIN)..(keychain.clone(), next_index)) - .map(|((_, derivation_index), spk)| (*derivation_index, spk)) + .map(|((_, derivation_index), spk)| (*derivation_index, spk.as_script())) } /// Get the next derivation index for `keychain`. The next index is the index after the last revealed diff --git a/crates/chain/src/spk_iter.rs b/crates/chain/src/spk_iter.rs index 97c81441..1e09df36 100644 --- a/crates/chain/src/spk_iter.rs +++ b/crates/chain/src/spk_iter.rs @@ -1,5 +1,5 @@ use crate::{ - bitcoin::{secp256k1::Secp256k1, Script}, + bitcoin::{secp256k1::Secp256k1, ScriptBuf}, miniscript::{Descriptor, DescriptorPublicKey}, }; use core::{borrow::Borrow, ops::Bound, ops::RangeBounds}; @@ -22,9 +22,9 @@ pub const BIP32_MAX_INDEX: u32 = (1 << 31) - 1; /// # use std::str::FromStr; /// # let secp = bitcoin::secp256k1::Secp256k1::signing_only(); /// # let (descriptor, _) = Descriptor::::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap(); -/// # let external_spk_0 = descriptor.at_derivation_index(0).script_pubkey(); -/// # let external_spk_3 = descriptor.at_derivation_index(3).script_pubkey(); -/// # let external_spk_4 = descriptor.at_derivation_index(4).script_pubkey(); +/// # let external_spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey(); +/// # let external_spk_3 = descriptor.at_derivation_index(3).unwrap().script_pubkey(); +/// # let external_spk_4 = descriptor.at_derivation_index(4).unwrap().script_pubkey(); /// /// // Creates a new script pubkey iterator starting at 0 from a descriptor. /// let mut spk_iter = SpkIterator::new(&descriptor); @@ -84,7 +84,7 @@ impl Iterator for SpkIterator where D: Borrow>, { - type Item = (u32, Script); + type Item = (u32, ScriptBuf); fn next(&mut self) -> Option { // For non-wildcard descriptors, we expect the first element to be Some((0, spk)), then None after. @@ -96,8 +96,7 @@ where let script = self .descriptor .borrow() - .at_derivation_index(self.next_index) - .derived_descriptor(&self.secp) + .derived_descriptor(&self.secp, self.next_index) .expect("the descriptor cannot need hardened derivation") .script_pubkey(); let output = (self.next_index, script); @@ -149,15 +148,14 @@ mod test { #[test] #[allow(clippy::iter_nth_zero)] + #[rustfmt::skip] fn test_spkiterator_wildcard() { let (_, external_desc, _) = init_txout_index(); - let external_spk_0 = external_desc.at_derivation_index(0).script_pubkey(); - let external_spk_16 = external_desc.at_derivation_index(16).script_pubkey(); - let external_spk_20 = external_desc.at_derivation_index(20).script_pubkey(); - let external_spk_21 = external_desc.at_derivation_index(21).script_pubkey(); - let external_spk_max = external_desc - .at_derivation_index(BIP32_MAX_INDEX) - .script_pubkey(); + let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey(); + let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey(); + let external_spk_20 = external_desc.at_derivation_index(20).unwrap().script_pubkey(); + let external_spk_21 = external_desc.at_derivation_index(21).unwrap().script_pubkey(); + let external_spk_max = external_desc.at_derivation_index(BIP32_MAX_INDEX).unwrap().script_pubkey(); let mut external_spk = SpkIterator::new(&external_desc); let max_index = BIP32_MAX_INDEX - 22; @@ -187,6 +185,7 @@ mod test { let (no_wildcard_descriptor, _) = Descriptor::::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap(); let external_spk_0 = no_wildcard_descriptor .at_derivation_index(0) + .unwrap() .script_pubkey(); let mut external_spk = SpkIterator::new(&no_wildcard_descriptor); diff --git a/crates/chain/src/spk_txout_index.rs b/crates/chain/src/spk_txout_index.rs index 31fd7883..cf862fb8 100644 --- a/crates/chain/src/spk_txout_index.rs +++ b/crates/chain/src/spk_txout_index.rs @@ -5,7 +5,7 @@ use crate::{ indexed_tx_graph::Indexer, ForEachTxOut, }; -use bitcoin::{self, OutPoint, Script, Transaction, TxOut, Txid}; +use bitcoin::{self, OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid}; /// An index storing [`TxOut`]s that have a script pubkey that matches those in a list. /// @@ -30,9 +30,9 @@ use bitcoin::{self, OutPoint, Script, Transaction, TxOut, Txid}; #[derive(Clone, Debug)] pub struct SpkTxOutIndex { /// script pubkeys ordered by index - spks: BTreeMap, + spks: BTreeMap, /// A reverse lookup from spk to spk index - spk_indices: HashMap, + spk_indices: HashMap, /// The set of unused indexes. unused: BTreeSet, /// Lookup index and txout by outpoint. @@ -152,11 +152,11 @@ impl SpkTxOutIndex { use bitcoin::hashes::Hash; use core::ops::Bound::*; let min_op = OutPoint { - txid: Txid::from_inner([0x00; 32]), + txid: Txid::all_zeros(), vout: u32::MIN, }; let max_op = OutPoint { - txid: Txid::from_inner([0xff; 32]), + txid: Txid::from_byte_array([0xff; Txid::LEN]), vout: u32::MAX, }; @@ -188,18 +188,18 @@ impl SpkTxOutIndex { /// /// If that index hasn't been inserted yet, it will return `None`. pub fn spk_at_index(&self, index: &I) -> Option<&Script> { - self.spks.get(index) + self.spks.get(index).map(|s| s.as_script()) } /// The script pubkeys that are being tracked by the index. - pub fn all_spks(&self) -> &BTreeMap { + pub fn all_spks(&self) -> &BTreeMap { &self.spks } /// Adds a script pubkey to scan for. Returns `false` and does nothing if spk already exists in the map /// /// the index will look for outputs spending to this spk whenever it scans new data. - pub fn insert_spk(&mut self, index: I, spk: Script) -> bool { + pub fn insert_spk(&mut self, index: I, spk: ScriptBuf) -> bool { match self.spk_indices.entry(spk.clone()) { Entry::Vacant(value) => { value.insert(index.clone()); diff --git a/crates/chain/tests/common/mod.rs b/crates/chain/tests/common/mod.rs index a32d9c55..2573fd96 100644 --- a/crates/chain/tests/common/mod.rs +++ b/crates/chain/tests/common/mod.rs @@ -56,7 +56,7 @@ macro_rules! changeset { pub fn new_tx(lt: u32) -> bitcoin::Transaction { bitcoin::Transaction { version: 0x00, - lock_time: bitcoin::PackedLockTime(lt), + lock_time: bitcoin::absolute::LockTime::from_consensus(lt), input: vec![], output: vec![], } diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index b7b62016..59032e65 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -10,7 +10,9 @@ use bdk_chain::{ tx_graph::Additions, BlockId, ChainPosition, ConfirmationHeightAnchor, }; -use bitcoin::{secp256k1::Secp256k1, BlockHash, OutPoint, Script, Transaction, TxIn, TxOut}; +use bitcoin::{ + secp256k1::Secp256k1, BlockHash, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut, +}; use miniscript::Descriptor; /// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented @@ -25,8 +27,8 @@ fn insert_relevant_txs() { const DESCRIPTOR: &str = "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)"; let (descriptor, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), DESCRIPTOR) .expect("must be valid"); - let spk_0 = descriptor.at_derivation_index(0).script_pubkey(); - let spk_1 = descriptor.at_derivation_index(9).script_pubkey(); + let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey(); + let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey(); let mut graph = IndexedTxGraph::>::default(); graph.index.add_keychain((), descriptor); @@ -127,21 +129,21 @@ fn test_list_owned_txouts() { // Get trusted and untrusted addresses - let mut trusted_spks = Vec::new(); - let mut untrusted_spks = Vec::new(); + let mut trusted_spks: Vec = Vec::new(); + let mut untrusted_spks: Vec = Vec::new(); { // we need to scope here to take immutanble reference of the graph for _ in 0..10 { let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_1".to_string()); // TODO Assert indexes - trusted_spks.push(script.clone()); + trusted_spks.push(script.to_owned()); } } { for _ in 0..10 { let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_2".to_string()); - untrusted_spks.push(script.clone()); + untrusted_spks.push(script.to_owned()); } } @@ -155,7 +157,7 @@ fn test_list_owned_txouts() { }], output: vec![TxOut { value: 70000, - script_pubkey: trusted_spks[0].clone(), + script_pubkey: trusted_spks[0].to_owned(), }], ..common::new_tx(0) }; @@ -164,7 +166,7 @@ fn test_list_owned_txouts() { let tx2 = Transaction { output: vec![TxOut { value: 30000, - script_pubkey: untrusted_spks[0].clone(), + script_pubkey: untrusted_spks[0].to_owned(), }], ..common::new_tx(0) }; @@ -177,7 +179,7 @@ fn test_list_owned_txouts() { }], output: vec![TxOut { value: 10000, - script_pubkey: trusted_spks[1].clone(), + script_pubkey: trusted_spks[1].to_owned(), }], ..common::new_tx(0) }; @@ -186,7 +188,7 @@ fn test_list_owned_txouts() { let tx4 = Transaction { output: vec![TxOut { value: 20000, - script_pubkey: untrusted_spks[1].clone(), + script_pubkey: untrusted_spks[1].to_owned(), }], ..common::new_tx(0) }; @@ -195,7 +197,7 @@ fn test_list_owned_txouts() { let tx5 = Transaction { output: vec![TxOut { value: 15000, - script_pubkey: trusted_spks[2].clone(), + script_pubkey: trusted_spks[2].to_owned(), }], ..common::new_tx(0) }; @@ -258,7 +260,7 @@ fn test_list_owned_txouts() { &local_chain, chain_tip, graph.index.outpoints().iter().cloned(), - |_, spk: &Script| trusted_spks.contains(spk), + |_, spk: &Script| trusted_spks.contains(&spk.to_owned()), ); assert_eq!(txouts.len(), 5); diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index a92e7448..d6c66c35 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -8,7 +8,7 @@ use bdk_chain::{ Append, }; -use bitcoin::{secp256k1::Secp256k1, OutPoint, Script, Transaction, TxOut}; +use bitcoin::{secp256k1::Secp256k1, OutPoint, ScriptBuf, Transaction, TxOut}; use miniscript::{Descriptor, DescriptorPublicKey}; #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)] @@ -34,7 +34,7 @@ fn init_txout_index() -> ( (txout_index, external_descriptor, internal_descriptor) } -fn spk_at_index(descriptor: &Descriptor, index: u32) -> Script { +fn spk_at_index(descriptor: &Descriptor, index: u32) -> ScriptBuf { descriptor .derived_descriptor(&Secp256k1::verification_only(), index) .expect("must derive") @@ -177,12 +177,14 @@ fn test_lookahead() { TxOut { script_pubkey: external_desc .at_derivation_index(external_index) + .unwrap() .script_pubkey(), value: 10_000, }, TxOut { script_pubkey: internal_desc .at_derivation_index(internal_index) + .unwrap() .script_pubkey(), value: 10_000, }, @@ -223,9 +225,17 @@ fn test_scan_with_lookahead() { let (mut txout_index, external_desc, _) = init_txout_index(); txout_index.set_lookahead_for_all(10); - let spks: BTreeMap = [0, 10, 20, 30] + let spks: BTreeMap = [0, 10, 20, 30] .into_iter() - .map(|i| (i, external_desc.at_derivation_index(i).script_pubkey())) + .map(|i| { + ( + i, + external_desc + .at_derivation_index(i) + .unwrap() + .script_pubkey(), + ) + }) .collect(); for (&spk_i, spk) in &spks { @@ -251,7 +261,10 @@ fn test_scan_with_lookahead() { } // now try with index 41 (lookahead surpassed), we expect that the txout to not be indexed - let spk_41 = external_desc.at_derivation_index(41).script_pubkey(); + let spk_41 = external_desc + .at_derivation_index(41) + .unwrap() + .script_pubkey(); let op = OutPoint::new(h!("fake tx"), 41); let txout = TxOut { script_pubkey: spk_41, @@ -262,12 +275,13 @@ fn test_scan_with_lookahead() { } #[test] +#[rustfmt::skip] fn test_wildcard_derivations() { let (mut txout_index, external_desc, _) = init_txout_index(); - let external_spk_0 = external_desc.at_derivation_index(0).script_pubkey(); - let external_spk_16 = external_desc.at_derivation_index(16).script_pubkey(); - let external_spk_26 = external_desc.at_derivation_index(26).script_pubkey(); - let external_spk_27 = external_desc.at_derivation_index(27).script_pubkey(); + let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey(); + let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey(); + let external_spk_26 = external_desc.at_derivation_index(26).unwrap().script_pubkey(); + let external_spk_27 = external_desc.at_derivation_index(27).unwrap().script_pubkey(); // - nothing is derived // - unused list is also empty @@ -277,10 +291,10 @@ fn test_wildcard_derivations() { // - next_unused() == ((0, ), DerivationAdditions:is_empty()) assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true)); let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); - assert_eq!(spk, (0_u32, &external_spk_0)); + assert_eq!(spk, (0_u32, external_spk_0.as_script())); assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 0)].into()); let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); - assert_eq!(spk, (0_u32, &external_spk_0)); + assert_eq!(spk, (0_u32, external_spk_0.as_script())); assert_eq!(changeset.as_inner(), &[].into()); // - derived till 25 @@ -300,12 +314,12 @@ fn test_wildcard_derivations() { assert_eq!(txout_index.next_index(&TestKeychain::External), (26, true)); let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); - assert_eq!(spk, (26, &external_spk_26)); + assert_eq!(spk, (26, external_spk_26.as_script())); assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 26)].into()); let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); - assert_eq!(spk, (16, &external_spk_16)); + assert_eq!(spk, (16, external_spk_16.as_script())); assert_eq!(changeset.as_inner(), &[].into()); // - Use all the derived till 26. @@ -315,7 +329,7 @@ fn test_wildcard_derivations() { }); let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); - assert_eq!(spk, (27, &external_spk_27)); + assert_eq!(spk, (27, external_spk_27.as_script())); assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 27)].into()); } @@ -327,6 +341,7 @@ fn test_non_wildcard_derivations() { let (no_wildcard_descriptor, _) = Descriptor::::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap(); let external_spk = no_wildcard_descriptor .at_derivation_index(0) + .unwrap() .script_pubkey(); txout_index.add_keychain(TestKeychain::External, no_wildcard_descriptor); @@ -339,11 +354,11 @@ fn test_non_wildcard_derivations() { // - when we get the next unused script, script @ index 0 assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true)); let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); - assert_eq!(spk, (0, &external_spk)); + assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 0)].into()); let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); - assert_eq!(spk, (0, &external_spk)); + assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(changeset.as_inner(), &[].into()); // given: @@ -356,11 +371,11 @@ fn test_non_wildcard_derivations() { txout_index.mark_used(&TestKeychain::External, 0); let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); - assert_eq!(spk, (0, &external_spk)); + assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(changeset.as_inner(), &[].into()); let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); - assert_eq!(spk, (0, &external_spk)); + assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(changeset.as_inner(), &[].into()); let (revealed_spks, revealed_additions) = txout_index.reveal_to_target(&TestKeychain::External, 200); diff --git a/crates/chain/tests/test_spk_txout_index.rs b/crates/chain/tests/test_spk_txout_index.rs index ada5a197..099b4ca8 100644 --- a/crates/chain/tests/test_spk_txout_index.rs +++ b/crates/chain/tests/test_spk_txout_index.rs @@ -1,10 +1,10 @@ use bdk_chain::SpkTxOutIndex; -use bitcoin::{hashes::hex::FromHex, OutPoint, PackedLockTime, Script, Transaction, TxIn, TxOut}; +use bitcoin::{absolute, OutPoint, ScriptBuf, Transaction, TxIn, TxOut}; #[test] fn spk_txout_sent_and_received() { - let spk1 = Script::from_hex("001404f1e52ce2bab3423c6a8c63b7cd730d8f12542c").unwrap(); - let spk2 = Script::from_hex("00142b57404ae14f08c3a0c903feb2af7830605eb00f").unwrap(); + let spk1 = ScriptBuf::from_hex("001404f1e52ce2bab3423c6a8c63b7cd730d8f12542c").unwrap(); + let spk2 = ScriptBuf::from_hex("00142b57404ae14f08c3a0c903feb2af7830605eb00f").unwrap(); let mut index = SpkTxOutIndex::default(); index.insert_spk(0, spk1.clone()); @@ -12,7 +12,7 @@ fn spk_txout_sent_and_received() { let tx1 = Transaction { version: 0x02, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 42_000, @@ -31,7 +31,7 @@ fn spk_txout_sent_and_received() { let tx2 = Transaction { version: 0x1, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { txid: tx1.txid(), @@ -57,8 +57,8 @@ fn spk_txout_sent_and_received() { #[test] fn mark_used() { - let spk1 = Script::from_hex("001404f1e52ce2bab3423c6a8c63b7cd730d8f12542c").unwrap(); - let spk2 = Script::from_hex("00142b57404ae14f08c3a0c903feb2af7830605eb00f").unwrap(); + let spk1 = ScriptBuf::from_hex("001404f1e52ce2bab3423c6a8c63b7cd730d8f12542c").unwrap(); + let spk2 = ScriptBuf::from_hex("00142b57404ae14f08c3a0c903feb2af7830605eb00f").unwrap(); let mut spk_index = SpkTxOutIndex::default(); spk_index.insert_spk(1, spk1.clone()); @@ -74,7 +74,7 @@ fn mark_used() { let tx1 = Transaction { version: 0x02, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 42_000, diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 41b446e7..1a05844f 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -7,7 +7,7 @@ use bdk_chain::{ Anchor, Append, BlockId, ChainPosition, ConfirmationHeightAnchor, }; use bitcoin::{ - hashes::Hash, BlockHash, OutPoint, PackedLockTime, Script, Transaction, TxIn, TxOut, Txid, + absolute, hashes::Hash, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, }; use core::iter; use std::vec; @@ -20,14 +20,14 @@ fn insert_txouts() { OutPoint::new(h!("tx1"), 1), TxOut { value: 10_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, ), ( OutPoint::new(h!("tx1"), 2), TxOut { value: 20_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, ), ]; @@ -37,21 +37,21 @@ fn insert_txouts() { OutPoint::new(h!("tx2"), 0), TxOut { value: 20_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, )]; // One full transaction to be included in the update let update_txs = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() }], output: vec![TxOut { value: 30_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }], }; @@ -161,14 +161,14 @@ fn insert_txouts() { 1u32, &TxOut { value: 10_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), } ), ( 2u32, &TxOut { value: 20_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), } ) ] @@ -181,7 +181,7 @@ fn insert_txouts() { 0u32, &TxOut { value: 30_000, - script_pubkey: Script::new() + script_pubkey: ScriptBuf::new() } )] .into() @@ -192,7 +192,7 @@ fn insert_txouts() { fn insert_tx_graph_doesnt_count_coinbase_as_spent() { let tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() @@ -210,7 +210,7 @@ fn insert_tx_graph_doesnt_count_coinbase_as_spent() { fn insert_tx_graph_keeps_track_of_spend() { let tx1 = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut::default()], }; @@ -222,7 +222,7 @@ fn insert_tx_graph_keeps_track_of_spend() { let tx2 = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: op, ..Default::default() @@ -251,7 +251,7 @@ fn insert_tx_graph_keeps_track_of_spend() { fn insert_tx_can_retrieve_full_tx_from_graph() { let tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() @@ -269,11 +269,11 @@ fn insert_tx_displaces_txouts() { let mut tx_graph = TxGraph::<()>::default(); let tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 42_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }], }; @@ -284,7 +284,7 @@ fn insert_tx_displaces_txouts() { }, TxOut { value: 1_337_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }, ); @@ -295,7 +295,7 @@ fn insert_tx_displaces_txouts() { }, TxOut { value: 1_000_000_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }, ); @@ -325,11 +325,11 @@ fn insert_txout_does_not_displace_tx() { let mut tx_graph = TxGraph::<()>::default(); let tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 42_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }], }; @@ -342,7 +342,7 @@ fn insert_txout_does_not_displace_tx() { }, TxOut { value: 1_337_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }, ); @@ -353,7 +353,7 @@ fn insert_txout_does_not_displace_tx() { }, TxOut { value: 1_000_000_000, - script_pubkey: Script::default(), + script_pubkey: ScriptBuf::default(), }, ); @@ -381,7 +381,7 @@ fn test_calculate_fee() { let mut graph = TxGraph::<()>::default(); let intx1 = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 100, @@ -390,7 +390,7 @@ fn test_calculate_fee() { }; let intx2 = Transaction { version: 0x02, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 200, @@ -415,7 +415,7 @@ fn test_calculate_fee() { let mut tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![ TxIn { previous_output: OutPoint { @@ -464,7 +464,7 @@ fn test_calculate_fee() { fn test_calculate_fee_on_coinbase() { let tx = Transaction { version: 0x01, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() @@ -636,11 +636,11 @@ fn test_chain_spends() { output: vec![ TxOut { value: 10_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, TxOut { value: 20_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, ], ..common::new_tx(0) @@ -655,11 +655,11 @@ fn test_chain_spends() { output: vec![ TxOut { value: 5_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, TxOut { value: 5_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, ], ..common::new_tx(0) @@ -674,11 +674,11 @@ fn test_chain_spends() { output: vec![ TxOut { value: 10_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, TxOut { value: 10_000, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, ], ..common::new_tx(0) From f4e3ba3265fc61bf61ffb54486abfe005ce236d7 Mon Sep 17 00:00:00 2001 From: Daniela Brozzoni Date: Wed, 19 Jul 2023 15:27:48 +0200 Subject: [PATCH 02/12] Update bdk to bitcoin 0.30.0 --- crates/bdk/Cargo.toml | 8 +- crates/bdk/README.md | 4 +- .../bdk/examples/mnemonic_to_descriptors.rs | 2 +- crates/bdk/src/descriptor/dsl.rs | 25 +- crates/bdk/src/descriptor/error.rs | 12 +- crates/bdk/src/descriptor/mod.rs | 92 +++--- crates/bdk/src/descriptor/policy.rs | 42 ++- crates/bdk/src/descriptor/template.rs | 64 ++-- crates/bdk/src/error.rs | 8 +- crates/bdk/src/keys/bip39.rs | 6 +- crates/bdk/src/keys/mod.rs | 22 +- crates/bdk/src/psbt/mod.rs | 2 +- crates/bdk/src/types.rs | 10 +- crates/bdk/src/wallet/coin_selection.rs | 84 +++--- crates/bdk/src/wallet/export.rs | 2 +- crates/bdk/src/wallet/hardwaresigner.rs | 6 +- crates/bdk/src/wallet/mod.rs | 63 ++-- crates/bdk/src/wallet/signer.rs | 135 ++++++--- crates/bdk/src/wallet/tx_builder.rs | 65 +++-- crates/bdk/src/wallet/utils.rs | 10 +- crates/bdk/tests/common.rs | 2 +- crates/bdk/tests/psbt.rs | 2 +- crates/bdk/tests/wallet.rs | 276 +++++++++++------- 23 files changed, 562 insertions(+), 380 deletions(-) diff --git a/crates/bdk/Cargo.toml b/crates/bdk/Cargo.toml index 344fb3e5..dc38fdd6 100644 --- a/crates/bdk/Cargo.toml +++ b/crates/bdk/Cargo.toml @@ -15,14 +15,14 @@ rust-version = "1.57" [dependencies] log = "0.4" rand = "^0.8" -miniscript = { version = "9", features = ["serde"], default-features = false } -bitcoin = { version = "0.29", features = ["serde", "base64", "rand"], default-features = false } +miniscript = { version = "10.0.0", features = ["serde"], default-features = false } +bitcoin = { version = "0.30.0", features = ["serde", "base64", "rand-std"], default-features = false } serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } bdk_chain = { path = "../chain", version = "0.5.0", features = ["miniscript", "serde"], default-features = false } # Optional dependencies -hwi = { version = "0.5", optional = true, features = [ "use-miniscript"] } +hwi = { version = "0.7.0", optional = true, features = [ "miniscript"] } bip39 = { version = "1.0.1", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -46,8 +46,6 @@ dev-getrandom-wasm = ["getrandom/js"] [dev-dependencies] lazy_static = "1.4" env_logger = "0.7" -# Move back to importing from rust-bitcoin once https://github.com/rust-bitcoin/rust-bitcoin/pull/1342 is released -base64 = "^0.13" assert_matches = "1.5.0" [package.metadata.docs.rs] diff --git a/crates/bdk/README.md b/crates/bdk/README.md index 9a5bd998..ddd67df1 100644 --- a/crates/bdk/README.md +++ b/crates/bdk/README.md @@ -137,7 +137,7 @@ fn main() { - + @@ -174,7 +174,7 @@ fn main() { - + diff --git a/crates/bdk/examples/mnemonic_to_descriptors.rs b/crates/bdk/examples/mnemonic_to_descriptors.rs index 0a560a52..7d2dd601 100644 --- a/crates/bdk/examples/mnemonic_to_descriptors.rs +++ b/crates/bdk/examples/mnemonic_to_descriptors.rs @@ -6,8 +6,8 @@ // You may not use this file except in accordance with one or both of these // licenses. +use bdk::bitcoin::bip32::DerivationPath; use bdk::bitcoin::secp256k1::Secp256k1; -use bdk::bitcoin::util::bip32::DerivationPath; use bdk::bitcoin::Network; use bdk::descriptor; use bdk::descriptor::IntoWalletDescriptor; diff --git a/crates/bdk/src/descriptor/dsl.rs b/crates/bdk/src/descriptor/dsl.rs index 60fac19e..50cd978f 100644 --- a/crates/bdk/src/descriptor/dsl.rs +++ b/crates/bdk/src/descriptor/dsl.rs @@ -516,13 +516,14 @@ macro_rules! descriptor { use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey}; $crate::impl_top_level_pk!(Pkh, $crate::miniscript::Legacy, $key) + .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c))) .map(|(a, b, c)| (Descriptor::::Pkh(a), b, c)) }); ( wpkh ( $key:expr ) ) => ({ use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey}; $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key) - .and_then(|(a, b, c)| Ok((a?, b, c))) + .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c))) .map(|(a, b, c)| (Descriptor::::Wpkh(a), b, c)) }); ( sh ( wpkh ( $key:expr ) ) ) => ({ @@ -532,7 +533,7 @@ macro_rules! descriptor { use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, Sh}; $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key) - .and_then(|(a, b, c)| Ok((a?, b, c))) + .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c))) .and_then(|(a, b, c)| Ok((Descriptor::::Sh(Sh::new_wpkh(a.into_inner())?), b, c))) }); ( sh ( $( $minisc:tt )* ) ) => ({ @@ -702,7 +703,7 @@ macro_rules! fragment { $crate::keys::make_pkh($key, &secp) }); ( after ( $value:expr ) ) => ({ - $crate::impl_leaf_opcode_value!(After, $crate::bitcoin::PackedLockTime($value)) // TODO!! https://github.com/rust-bitcoin/rust-bitcoin/issues/1302 + $crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value)) }); ( older ( $value:expr ) ) => ({ $crate::impl_leaf_opcode_value!(Older, $crate::bitcoin::Sequence($value)) // TODO!! @@ -796,7 +797,6 @@ macro_rules! fragment { #[cfg(test)] mod test { use alloc::string::ToString; - use bitcoin::hashes::hex::ToHex; use bitcoin::secp256k1::Secp256k1; use miniscript::descriptor::{DescriptorPublicKey, KeyMap}; use miniscript::{Descriptor, Legacy, Segwitv0}; @@ -805,8 +805,8 @@ mod test { use crate::descriptor::{DescriptorError, DescriptorMeta}; use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks}; + use bitcoin::bip32; use bitcoin::network::constants::Network::{Bitcoin, Regtest, Signet, Testnet}; - use bitcoin::util::bip32; use bitcoin::PrivateKey; // test the descriptor!() macro @@ -822,18 +822,15 @@ mod test { assert_eq!(desc.is_witness(), is_witness); assert_eq!(!desc.has_wildcard(), is_fixed); for i in 0..expected.len() { - let index = i as u32; - let child_desc = if !desc.has_wildcard() { - desc.at_derivation_index(0) - } else { - desc.at_derivation_index(index) - }; + let child_desc = desc + .at_derivation_index(i as u32) + .expect("i is not hardened"); let address = child_desc.address(Regtest); if let Ok(address) = address { assert_eq!(address.to_string(), *expected.get(i).unwrap()); } else { let script = child_desc.script_pubkey(); - assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap()); + assert_eq!(script.to_hex_string(), *expected.get(i).unwrap()); } } } @@ -1178,9 +1175,7 @@ mod test { } #[test] - #[should_panic( - expected = "Miniscript(ContextError(CompressedOnly(\"04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4\")))" - )] + #[should_panic(expected = "Miniscript(ContextError(UncompressedKeysNotAllowed))")] fn test_dsl_miniscript_checks() { let mut uncompressed_pk = PrivateKey::from_wif("L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6").unwrap(); diff --git a/crates/bdk/src/descriptor/error.rs b/crates/bdk/src/descriptor/error.rs index 5b0f1930..8731b5bf 100644 --- a/crates/bdk/src/descriptor/error.rs +++ b/crates/bdk/src/descriptor/error.rs @@ -32,11 +32,11 @@ pub enum Error { InvalidDescriptorCharacter(u8), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + Bip32(bitcoin::bip32::Error), /// Error during base58 decoding - Base58(bitcoin::util::base58::Error), + Base58(bitcoin::base58::Error), /// Key-related error - Pk(bitcoin::util::key::Error), + Pk(bitcoin::key::Error), /// Miniscript error Miniscript(miniscript::Error), /// Hex decoding error @@ -81,9 +81,9 @@ impl fmt::Display for Error { #[cfg(feature = "std")] impl std::error::Error for Error {} -impl_error!(bitcoin::util::bip32::Error, Bip32); -impl_error!(bitcoin::util::base58::Error, Base58); -impl_error!(bitcoin::util::key::Error, Pk); +impl_error!(bitcoin::bip32::Error, Bip32); +impl_error!(bitcoin::base58::Error, Base58); +impl_error!(bitcoin::key::Error, Pk); impl_error!(miniscript::Error, Miniscript); impl_error!(bitcoin::hashes::hex::Error, Hex); impl_error!(crate::descriptor::policy::PolicyError, Policy); diff --git a/crates/bdk/src/descriptor/mod.rs b/crates/bdk/src/descriptor/mod.rs index 9a6dc2b0..e139f7bd 100644 --- a/crates/bdk/src/descriptor/mod.rs +++ b/crates/bdk/src/descriptor/mod.rs @@ -18,17 +18,17 @@ use crate::collections::BTreeMap; use alloc::string::String; use alloc::vec::Vec; -use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource}; -use bitcoin::util::{psbt, taproot}; -use bitcoin::{secp256k1, PublicKey, XOnlyPublicKey}; +use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource}; +use bitcoin::{key::XOnlyPublicKey, secp256k1, PublicKey}; +use bitcoin::{psbt, taproot}; use bitcoin::{Network, TxOut}; use miniscript::descriptor::{ - DefiniteDescriptorKey, DescriptorSecretKey, DescriptorType, InnerXKey, SinglePubKey, + DefiniteDescriptorKey, DescriptorMultiXKey, DescriptorSecretKey, DescriptorType, + DescriptorXKey, InnerXKey, KeyMap, SinglePubKey, Wildcard, }; pub use miniscript::{ - descriptor::DescriptorXKey, descriptor::KeyMap, descriptor::Wildcard, Descriptor, - DescriptorPublicKey, Legacy, Miniscript, ScriptContext, Segwitv0, + Descriptor, DescriptorPublicKey, Legacy, Miniscript, ScriptContext, Segwitv0, }; use miniscript::{ForEachKey, MiniscriptKey, TranslatePk}; @@ -59,16 +59,16 @@ pub type DerivedDescriptor = Descriptor; /// Alias for the type of maps that represent derivation paths in a [`psbt::Input`] or /// [`psbt::Output`] /// -/// [`psbt::Input`]: bitcoin::util::psbt::Input -/// [`psbt::Output`]: bitcoin::util::psbt::Output +/// [`psbt::Input`]: bitcoin::psbt::Input +/// [`psbt::Output`]: bitcoin::psbt::Output pub type HdKeyPaths = BTreeMap; /// Alias for the type of maps that represent taproot key origins in a [`psbt::Input`] or /// [`psbt::Output`] /// -/// [`psbt::Input`]: bitcoin::util::psbt::Input -/// [`psbt::Output`]: bitcoin::util::psbt::Output -pub type TapKeyOrigins = BTreeMap, KeySource)>; +/// [`psbt::Input`]: bitcoin::psbt::Input +/// [`psbt::Output`]: bitcoin::psbt::Output +pub type TapKeyOrigins = BTreeMap, KeySource)>; /// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`] pub trait IntoWalletDescriptor { @@ -136,14 +136,10 @@ impl IntoWalletDescriptor for (ExtendedDescriptor, KeyMap) { network: Network, } - impl<'s, 'd> - miniscript::Translator + impl<'s, 'd> miniscript::Translator for Translator<'s, 'd> { - fn pk( - &mut self, - pk: &DescriptorPublicKey, - ) -> Result { + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result { let secp = &self.secp; let (_, _, networks) = if self.descriptor.is_taproot() { @@ -161,7 +157,7 @@ impl IntoWalletDescriptor for (ExtendedDescriptor, KeyMap) { }; if networks.contains(&self.network) { - Ok(miniscript::DummyKey) + Ok(Default::default()) } else { Err(DescriptorError::Key(KeyError::InvalidNetwork)) } @@ -169,35 +165,40 @@ impl IntoWalletDescriptor for (ExtendedDescriptor, KeyMap) { fn sha256( &mut self, _sha256: &::Sha256, - ) -> Result { + ) -> Result { Ok(Default::default()) } fn hash256( &mut self, _hash256: &::Hash256, - ) -> Result { + ) -> Result { Ok(Default::default()) } fn ripemd160( &mut self, _ripemd160: &::Ripemd160, - ) -> Result { + ) -> Result { Ok(Default::default()) } fn hash160( &mut self, _hash160: &::Hash160, - ) -> Result { + ) -> Result { Ok(Default::default()) } } // check the network for the keys - self.0.translate_pk(&mut Translator { + use miniscript::TranslateErr; + match self.0.translate_pk(&mut Translator { secp, network, descriptor: &self.0, - })?; + }) { + Ok(_) => {} + Err(TranslateErr::TranslatorErr(e)) => return Err(e), + Err(TranslateErr::OuterError(e)) => return Err(e.into()), + } Ok(self) } @@ -251,7 +252,12 @@ impl IntoWalletDescriptor for DescriptorTemplateOut { } // fixup the network for keys that need it in the descriptor - let translated = desc.translate_pk(&mut Translator { network })?; + use miniscript::TranslateErr; + let translated = match desc.translate_pk(&mut Translator { network }) { + Ok(descriptor) => descriptor, + Err(TranslateErr::TranslatorErr(e)) => return Err(e), + Err(TranslateErr::OuterError(e)) => return Err(e.into()), + }; // ...and in the key map let fixed_keymap = keymap .into_iter() @@ -340,6 +346,18 @@ pub(crate) trait XKeyUtils { fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint; } +impl XKeyUtils for DescriptorMultiXKey +where + T: InnerXKey, +{ + fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint { + match self.origin { + Some((fingerprint, _)) => fingerprint, + None => self.xkey.xkey_fingerprint(secp), + } + } +} + impl XKeyUtils for DescriptorXKey where T: InnerXKey, @@ -494,7 +512,10 @@ impl DescriptorMeta for ExtendedDescriptor { false }); - path_found.map(|path| self.at_derivation_index(path)) + path_found.map(|path| { + self.at_derivation_index(path) + .expect("We ignore hardened wildcards") + }) } fn derive_from_hd_keypaths( @@ -545,7 +566,7 @@ impl DescriptorMeta for ExtendedDescriptor { return None; } - let descriptor = self.at_derivation_index(0); + let descriptor = self.at_derivation_index(0).expect("0 is not hardened"); match descriptor.desc_type() { // TODO: add pk() here DescriptorType::Pkh @@ -585,11 +606,10 @@ mod test { use core::str::FromStr; use assert_matches::assert_matches; - use bitcoin::consensus::encode::deserialize; use bitcoin::hashes::hex::FromHex; use bitcoin::secp256k1::Secp256k1; - use bitcoin::util::{bip32, psbt}; - use bitcoin::Script; + use bitcoin::ScriptBuf; + use bitcoin::{bip32, psbt::Psbt}; use super::*; use crate::psbt::PsbtUtils; @@ -600,7 +620,7 @@ mod test { "wpkh(02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737)", ) .unwrap(); - let psbt: psbt::PartiallySignedTransaction = deserialize( + let psbt = Psbt::deserialize( &Vec::::from_hex( "70736274ff010052010000000162307be8e431fbaff807cdf9cdc3fde44d7402\ 11bc8342c31ffd6ec11fe35bcc0100000000ffffffff01328601000000000016\ @@ -623,7 +643,7 @@ mod test { "pkh([0f056943/44h/0h/0h]tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/10/*)", ) .unwrap(); - let psbt: psbt::PartiallySignedTransaction = deserialize( + let psbt = Psbt::deserialize( &Vec::::from_hex( "70736274ff010053010000000145843b86be54a3cd8c9e38444e1162676c00df\ e7964122a70df491ea12fd67090100000000ffffffff01c19598000000000017\ @@ -654,7 +674,7 @@ mod test { "wsh(and_v(v:pk(03b6633fef2397a0a9de9d7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14),older(6)))", ) .unwrap(); - let psbt: psbt::PartiallySignedTransaction = deserialize( + let psbt = Psbt::deserialize( &Vec::::from_hex( "70736274ff01005302000000011c8116eea34408ab6529223c9a176606742207\ 67a1ff1d46a6e3c4a88243ea6e01000000000600000001109698000000000017\ @@ -678,7 +698,7 @@ mod test { "sh(and_v(v:pk(021403881a5587297818fcaf17d239cefca22fce84a45b3b1d23e836c4af671dbb),after(630000)))", ) .unwrap(); - let psbt: psbt::PartiallySignedTransaction = deserialize( + let psbt = Psbt::deserialize( &Vec::::from_hex( "70736274ff0100530100000001bc8c13df445dfadcc42afa6dc841f85d22b01d\ a6270ebf981740f4b7b1d800390000000000feffffff01ba9598000000000017\ @@ -861,9 +881,9 @@ mod test { let (descriptor, _) = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet).unwrap(); - let descriptor = descriptor.at_derivation_index(0); + let descriptor = descriptor.at_derivation_index(0).unwrap(); - let script = Script::from_str("5321022f533b667e2ea3b36e21961c9fe9dca340fbe0af5210173a83ae0337ab20a57621026bb53a98e810bd0ee61a0ed1164ba6c024786d76554e793e202dc6ce9c78c4ea2102d5b8a7d66a41ffdb6f4c53d61994022e886b4f45001fb158b95c9164d45f8ca3210324b75eead2c1f9c60e8adeb5e7009fec7a29afcdb30d829d82d09562fe8bae8521032d34f8932200833487bd294aa219dcbe000b9f9b3d824799541430009f0fa55121037468f8ea99b6c64788398b5ad25480cad08f4b0d65be54ce3a55fd206b5ae4722103f72d3d96663b0ea99b0aeb0d7f273cab11a8de37885f1dddc8d9112adb87169357ae").unwrap(); + let script = ScriptBuf::from_hex("5321022f533b667e2ea3b36e21961c9fe9dca340fbe0af5210173a83ae0337ab20a57621026bb53a98e810bd0ee61a0ed1164ba6c024786d76554e793e202dc6ce9c78c4ea2102d5b8a7d66a41ffdb6f4c53d61994022e886b4f45001fb158b95c9164d45f8ca3210324b75eead2c1f9c60e8adeb5e7009fec7a29afcdb30d829d82d09562fe8bae8521032d34f8932200833487bd294aa219dcbe000b9f9b3d824799541430009f0fa55121037468f8ea99b6c64788398b5ad25480cad08f4b0d65be54ce3a55fd206b5ae4722103f72d3d96663b0ea99b0aeb0d7f273cab11a8de37885f1dddc8d9112adb87169357ae").unwrap(); let mut psbt_input = psbt::Input::default(); psbt_input diff --git a/crates/bdk/src/descriptor/policy.rs b/crates/bdk/src/descriptor/policy.rs index 5de20ae7..14b2459e 100644 --- a/crates/bdk/src/descriptor/policy.rs +++ b/crates/bdk/src/descriptor/policy.rs @@ -45,9 +45,9 @@ use core::fmt; use serde::ser::SerializeMap; use serde::{Serialize, Serializer}; +use bitcoin::bip32::Fingerprint; use bitcoin::hashes::{hash160, ripemd160, sha256}; -use bitcoin::util::bip32::Fingerprint; -use bitcoin::{LockTime, PublicKey, Sequence, XOnlyPublicKey}; +use bitcoin::{absolute, key::XOnlyPublicKey, PublicKey, Sequence}; use miniscript::descriptor::{ DescriptorPublicKey, ShInner, SinglePub, SinglePubKey, SortedMultiVec, WshInner, @@ -68,7 +68,7 @@ use crate::wallet::utils::{After, Older, SecpCtx}; use super::checksum::calc_checksum; use super::error::Error; use super::XKeyUtils; -use bitcoin::util::psbt::{Input as PsbtInput, PartiallySignedTransaction as Psbt}; +use bitcoin::psbt::{self, Psbt}; use miniscript::psbt::PsbtInputSatisfier; /// A unique identifier for a key @@ -95,6 +95,9 @@ impl PkOrF { .. }) => PkOrF::XOnlyPubkey(*pk), DescriptorPublicKey::XPub(xpub) => PkOrF::Fingerprint(xpub.root_fingerprint(secp)), + DescriptorPublicKey::MultiXPub(multi) => { + PkOrF::Fingerprint(multi.root_fingerprint(secp)) + } } } } @@ -131,7 +134,7 @@ pub enum SatisfiableItem { /// Absolute timeclock timestamp AbsoluteTimelock { /// The timelock value - value: LockTime, + value: absolute::LockTime, }, /// Relative timelock locktime RelativeTimelock { @@ -451,11 +454,14 @@ pub struct Condition { pub csv: Option, /// Optional timelock condition #[serde(skip_serializing_if = "Option::is_none")] - pub timelock: Option, + pub timelock: Option, } impl Condition { - fn merge_nlocktime(a: LockTime, b: LockTime) -> Result { + fn merge_nlocktime( + a: absolute::LockTime, + b: absolute::LockTime, + ) -> Result { if !a.is_same_unit(b) { Err(PolicyError::MixedTimelockUnits) } else if a > b { @@ -749,6 +755,7 @@ fn signer_id(key: &DescriptorPublicKey, secp: &SecpCtx) -> SignerId { .. }) => pk.to_pubkeyhash(SigType::Ecdsa).into(), DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint(secp).into(), + DescriptorPublicKey::MultiXPub(xpub) => xpub.root_fingerprint(secp).into(), } } @@ -786,9 +793,9 @@ fn make_generic_signature SatisfiableItem, F: Fn(&Psbt) -> bool>( fn generic_sig_in_psbt< // C is for "check", it's a closure we use to *check* if a psbt input contains the signature // for a specific key - C: Fn(&PsbtInput, &SinglePubKey) -> bool, + C: Fn(&psbt::Input, &SinglePubKey) -> bool, // E is for "extract", it extracts a key from the bip32 derivations found in the psbt input - E: Fn(&PsbtInput, Fingerprint) -> Option, + E: Fn(&psbt::Input, Fingerprint) -> Option, >( psbt: &Psbt, key: &DescriptorPublicKey, @@ -806,6 +813,13 @@ fn generic_sig_in_psbt< None => false, } } + DescriptorPublicKey::MultiXPub(xpub) => { + //TODO check actual derivation matches + match extract(input, xpub.root_fingerprint(secp)) { + Some(pubkey) => check(input, &pubkey), + None => false, + } + } }) } @@ -911,12 +925,12 @@ impl ExtractPolicy for Miniscript { let mut policy: Policy = SatisfiableItem::AbsoluteTimelock { - value: value.into(), + value: (*value).into(), } .into(); policy.contribution = Satisfaction::Complete { condition: Condition { - timelock: Some(value.into()), + timelock: Some((*value).into()), csv: None, }, }; @@ -928,9 +942,9 @@ impl ExtractPolicy for Miniscript::check_after(&after, value.into()); + Satisfier::::check_after(&after, (*value).into()); let inputs_sat = psbt_inputs_sat(psbt).all(|sat| { - Satisfier::::check_after(&sat, value.into()) + Satisfier::::check_after(&sat, (*value).into()) }); if after_sat && inputs_sat { policy.satisfaction = policy.contribution.clone(); @@ -1156,8 +1170,8 @@ mod test { use crate::wallet::signer::SignersContainer; use alloc::{string::ToString, sync::Arc}; use assert_matches::assert_matches; + use bitcoin::bip32; use bitcoin::secp256k1::Secp256k1; - use bitcoin::util::bip32; use bitcoin::Network; use core::str::FromStr; @@ -1575,6 +1589,7 @@ mod test { let addr = wallet_desc .at_derivation_index(0) + .unwrap() .address(Network::Testnet) .unwrap(); assert_eq!( @@ -1641,6 +1656,7 @@ mod test { let addr = wallet_desc .at_derivation_index(0) + .unwrap() .address(Network::Testnet) .unwrap(); assert_eq!( diff --git a/crates/bdk/src/descriptor/template.rs b/crates/bdk/src/descriptor/template.rs index 599cf69e..c5e8b31c 100644 --- a/crates/bdk/src/descriptor/template.rs +++ b/crates/bdk/src/descriptor/template.rs @@ -14,7 +14,7 @@ //! This module contains the definition of various common script templates that are ready to be //! used. See the documentation of each template for an example. -use bitcoin::util::bip32; +use bitcoin::bip32; use bitcoin::Network; use miniscript::{Legacy, Segwitv0, Tap}; @@ -195,7 +195,7 @@ impl> DescriptorTemplate for P2TR { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip44; /// -/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip44(key.clone(), KeychainKind::External), /// Some(Bip44(key, KeychainKind::Internal)), @@ -232,8 +232,8 @@ impl> DescriptorTemplate for Bip44 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip44Public; /// -/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; -/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; +/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; +/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip44Public(key.clone(), fingerprint, KeychainKind::External), /// Some(Bip44Public(key, fingerprint, KeychainKind::Internal)), @@ -270,7 +270,7 @@ impl> DescriptorTemplate for Bip44Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip49; /// -/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip49(key.clone(), KeychainKind::External), /// Some(Bip49(key, KeychainKind::Internal)), @@ -307,8 +307,8 @@ impl> DescriptorTemplate for Bip49 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip49Public; /// -/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; -/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; +/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; +/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip49Public(key.clone(), fingerprint, KeychainKind::External), /// Some(Bip49Public(key, fingerprint, KeychainKind::Internal)), @@ -345,7 +345,7 @@ impl> DescriptorTemplate for Bip49Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip84; /// -/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip84(key.clone(), KeychainKind::External), /// Some(Bip84(key, KeychainKind::Internal)), @@ -382,8 +382,8 @@ impl> DescriptorTemplate for Bip84 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip84Public; /// -/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; -/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; +/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; +/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip84Public(key.clone(), fingerprint, KeychainKind::External), /// Some(Bip84Public(key, fingerprint, KeychainKind::Internal)), @@ -420,7 +420,7 @@ impl> DescriptorTemplate for Bip84Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip86; /// -/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip86(key.clone(), KeychainKind::External), /// Some(Bip86(key, KeychainKind::Internal)), @@ -457,8 +457,8 @@ impl> DescriptorTemplate for Bip86 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip86Public; /// -/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; -/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?; +/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; +/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip86Public(key.clone(), fingerprint, KeychainKind::External), /// Some(Bip86Public(key, fingerprint, KeychainKind::Internal)), @@ -565,30 +565,30 @@ mod test { // BIP44 `pkh(key/44'/{0,1}'/0'/{0,1}/*)` #[test] fn test_bip44_template_cointype() { - use bitcoin::util::bip32::ChildNumber::{self, Hardened}; + use bitcoin::bip32::ChildNumber::{self, Hardened}; - let xprvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap(); + let xprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap(); assert_eq!(Network::Bitcoin, xprvkey.network); let xdesc = Bip44(xprvkey, KeychainKind::Internal) .build(Network::Bitcoin) .unwrap(); if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 { - let path: Vec = pkh.into_inner().full_derivation_path().into(); + let path: Vec = pkh.into_inner().full_derivation_path().unwrap().into(); let purpose = path.get(0).unwrap(); assert_matches!(purpose, Hardened { index: 44 }); let coin_type = path.get(1).unwrap(); assert_matches!(coin_type, Hardened { index: 0 }); } - let tprvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let tprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); assert_eq!(Network::Testnet, tprvkey.network); let tdesc = Bip44(tprvkey, KeychainKind::Internal) .build(Network::Testnet) .unwrap(); if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 { - let path: Vec = pkh.into_inner().full_derivation_path().into(); + let path: Vec = pkh.into_inner().full_derivation_path().unwrap().into(); let purpose = path.get(0).unwrap(); assert_matches!(purpose, Hardened { index: 44 }); let coin_type = path.get(1).unwrap(); @@ -612,9 +612,9 @@ mod test { for i in 0..expected.len() { let index = i as u32; let child_desc = if !desc.has_wildcard() { - desc.at_derivation_index(0) + desc.at_derivation_index(0).unwrap() } else { - desc.at_derivation_index(index) + desc.at_derivation_index(index).unwrap() }; let address = child_desc.address(network).unwrap(); assert_eq!(address.to_string(), *expected.get(i).unwrap()); @@ -740,7 +740,7 @@ mod test { // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)` #[test] fn test_bip44_template() { - let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip44(prvkey, KeychainKind::External).build(Network::Bitcoin), false, @@ -770,8 +770,8 @@ mod test { // BIP44 public `pkh(key/{0,1}/*)` #[test] fn test_bip44_public_template() { - let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); - let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); + let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip44Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), false, @@ -801,7 +801,7 @@ mod test { // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))` #[test] fn test_bip49_template() { - let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip49(prvkey, KeychainKind::External).build(Network::Bitcoin), true, @@ -831,8 +831,8 @@ mod test { // BIP49 public `sh(wpkh(key/{0,1}/*))` #[test] fn test_bip49_public_template() { - let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); - let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); + let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip49Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), true, @@ -862,7 +862,7 @@ mod test { // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)` #[test] fn test_bip84_template() { - let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip84(prvkey, KeychainKind::External).build(Network::Bitcoin), true, @@ -892,8 +892,8 @@ mod test { // BIP84 public `wpkh(key/{0,1}/*)` #[test] fn test_bip84_public_template() { - let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); - let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap(); + let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); + let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip84Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), true, @@ -924,7 +924,7 @@ mod test { // Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki #[test] fn test_bip86_template() { - let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap(); + let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap(); check( Bip86(prvkey, KeychainKind::External).build(Network::Bitcoin), false, @@ -955,8 +955,8 @@ mod test { // Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki #[test] fn test_bip86_public_template() { - let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap(); - let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("73c5da0a").unwrap(); + let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap(); + let fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap(); check( Bip86Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), false, diff --git a/crates/bdk/src/error.rs b/crates/bdk/src/error.rs index 22817a3e..fcb5a6f7 100644 --- a/crates/bdk/src/error.rs +++ b/crates/bdk/src/error.rs @@ -84,9 +84,9 @@ pub enum Error { /// Miniscript PSBT error MiniscriptPsbt(MiniscriptPsbtError), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + Bip32(bitcoin::bip32::Error), /// Partially signed bitcoin transaction error - Psbt(bitcoin::util::psbt::Error), + Psbt(bitcoin::psbt::Error), } /// Errors returned by miniscript when updating inconsistent PSBTs @@ -197,5 +197,5 @@ impl From for Error { impl_error!(miniscript::Error, Miniscript); impl_error!(MiniscriptPsbtError, MiniscriptPsbt); -impl_error!(bitcoin::util::bip32::Error, Bip32); -impl_error!(bitcoin::util::psbt::Error, Psbt); +impl_error!(bitcoin::bip32::Error, Bip32); +impl_error!(bitcoin::psbt::Error, Psbt); diff --git a/crates/bdk/src/keys/bip39.rs b/crates/bdk/src/keys/bip39.rs index 78f54493..8b09ac28 100644 --- a/crates/bdk/src/keys/bip39.rs +++ b/crates/bdk/src/keys/bip39.rs @@ -15,7 +15,7 @@ // something that should be fairly simple to re-implement. use alloc::string::String; -use bitcoin::util::bip32; +use bitcoin::bip32; use bitcoin::Network; use miniscript::ScriptContext; @@ -142,7 +142,7 @@ impl GeneratableKey for Mnemonic { (word_count, language): Self::Options, entropy: Self::Entropy, ) -> Result, Self::Error> { - let entropy = &entropy.as_ref()[..(word_count as usize / 8)]; + let entropy = &entropy[..(word_count as usize / 8)]; let mnemonic = Mnemonic::from_entropy_in(language, entropy)?; Ok(GeneratedKey::new(mnemonic, any_network())) @@ -154,7 +154,7 @@ mod test { use alloc::string::ToString; use core::str::FromStr; - use bitcoin::util::bip32; + use bitcoin::bip32; use bip39::{Language, Mnemonic}; diff --git a/crates/bdk/src/keys/mod.rs b/crates/bdk/src/keys/mod.rs index b4cfb6de..c9162593 100644 --- a/crates/bdk/src/keys/mod.rs +++ b/crates/bdk/src/keys/mod.rs @@ -22,8 +22,8 @@ use core::str::FromStr; use bitcoin::secp256k1::{self, Secp256k1, Signing}; -use bitcoin::util::bip32; -use bitcoin::{Network, PrivateKey, PublicKey, XOnlyPublicKey}; +use bitcoin::bip32; +use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey}; use miniscript::descriptor::{Descriptor, DescriptorXKey, Wildcard}; pub use miniscript::descriptor::{ @@ -388,12 +388,12 @@ impl From for ExtendedKey { /// /// ``` /// use bdk::bitcoin; -/// use bdk::bitcoin::util::bip32; +/// use bdk::bitcoin::bip32; /// use bdk::keys::{DerivableKey, ExtendedKey, KeyError, ScriptContext}; /// /// struct MyCustomKeyType { /// key_data: bitcoin::PrivateKey, -/// chain_code: Vec, +/// chain_code: [u8; 32], /// network: bitcoin::Network, /// } /// @@ -404,7 +404,7 @@ impl From for ExtendedKey { /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, -/// chain_code: bip32::ChainCode::from(self.chain_code.as_ref()), +/// chain_code: bip32::ChainCode::from(&self.chain_code), /// child_number: bip32::ChildNumber::Normal { index: 0 }, /// }; /// @@ -419,14 +419,14 @@ impl From for ExtendedKey { /// /// ``` /// use bdk::bitcoin; -/// use bdk::bitcoin::util::bip32; +/// use bdk::bitcoin::bip32; /// use bdk::keys::{ /// any_network, DerivableKey, DescriptorKey, ExtendedKey, KeyError, ScriptContext, /// }; /// /// struct MyCustomKeyType { /// key_data: bitcoin::PrivateKey, -/// chain_code: Vec, +/// chain_code: [u8; 32], /// } /// /// impl DerivableKey for MyCustomKeyType { @@ -436,7 +436,7 @@ impl From for ExtendedKey { /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, -/// chain_code: bip32::ChainCode::from(self.chain_code.as_ref()), +/// chain_code: bip32::ChainCode::from(&self.chain_code), /// child_number: bip32::ChildNumber::Normal { index: 0 }, /// }; /// @@ -927,13 +927,13 @@ pub enum KeyError { Message(String), /// BIP32 error - Bip32(bitcoin::util::bip32::Error), + Bip32(bitcoin::bip32::Error), /// Miniscript error Miniscript(miniscript::Error), } impl_error!(miniscript::Error, Miniscript, KeyError); -impl_error!(bitcoin::util::bip32::Error, Bip32, KeyError); +impl_error!(bitcoin::bip32::Error, Bip32, KeyError); impl fmt::Display for KeyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -953,7 +953,7 @@ impl std::error::Error for KeyError {} #[cfg(test)] pub mod test { - use bitcoin::util::bip32; + use bitcoin::bip32; use super::*; diff --git a/crates/bdk/src/psbt/mod.rs b/crates/bdk/src/psbt/mod.rs index 87243236..bc6ce858 100644 --- a/crates/bdk/src/psbt/mod.rs +++ b/crates/bdk/src/psbt/mod.rs @@ -13,7 +13,7 @@ use crate::FeeRate; use alloc::vec::Vec; -use bitcoin::util::psbt::PartiallySignedTransaction as Psbt; +use bitcoin::psbt::PartiallySignedTransaction as Psbt; use bitcoin::TxOut; // TODO upstream the functions here to `rust-bitcoin`? diff --git a/crates/bdk/src/types.rs b/crates/bdk/src/types.rs index e21bef90..1b96ef0f 100644 --- a/crates/bdk/src/types.rs +++ b/crates/bdk/src/types.rs @@ -15,7 +15,7 @@ use core::ops::Sub; use bdk_chain::ConfirmationTime; use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; -use bitcoin::{hash_types::Txid, util::psbt}; +use bitcoin::{hash_types::Txid, psbt, Weight}; use serde::{Deserialize, Serialize}; @@ -99,8 +99,8 @@ impl FeeRate { } /// Calculate fee rate from `fee` and weight units (`wu`). - pub fn from_wu(fee: u64, wu: usize) -> FeeRate { - Self::from_vb(fee, wu.vbytes()) + pub fn from_wu(fee: u64, wu: Weight) -> FeeRate { + Self::from_vb(fee, wu.to_vbytes_ceil() as usize) } /// Calculate fee rate from `fee` and `vbytes`. @@ -120,8 +120,8 @@ impl FeeRate { } /// Calculate absolute fee in Satoshis using size in weight units. - pub fn fee_wu(&self, wu: usize) -> u64 { - self.fee_vb(wu.vbytes()) + pub fn fee_wu(&self, wu: Weight) -> u64 { + self.fee_vb(wu.to_vbytes_ceil() as usize) } /// Calculate absolute fee in Satoshis using size in virtual bytes. diff --git a/crates/bdk/src/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs index e7927cab..6f30fd14 100644 --- a/crates/bdk/src/wallet/coin_selection.rs +++ b/crates/bdk/src/wallet/coin_selection.rs @@ -38,12 +38,12 @@ //! &self, //! required_utxos: Vec, //! optional_utxos: Vec, -//! fee_rate: FeeRate, +//! fee_rate: bdk::FeeRate, //! target_amount: u64, //! drain_script: &Script, //! ) -> Result { //! let mut selected_amount = 0; -//! let mut additional_weight = 0; +//! let mut additional_weight = Weight::ZERO; //! let all_utxos_selected = required_utxos //! .into_iter() //! .chain(optional_utxos) @@ -51,7 +51,9 @@ //! (&mut selected_amount, &mut additional_weight), //! |(selected_amount, additional_weight), weighted_utxo| { //! **selected_amount += weighted_utxo.utxo.txout().value; -//! **additional_weight += TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight; +//! **additional_weight += Weight::from_wu( +//! (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64, +//! ); //! Some(weighted_utxo.utxo) //! }, //! ) @@ -80,7 +82,10 @@ //! # let mut wallet = doctest_wallet!(); //! // create wallet, sync, ... //! -//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); +//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt") +//! .unwrap() +//! .require_network(Network::Testnet) +//! .unwrap(); //! let (psbt, details) = { //! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything); //! builder.add_recipient(to_address.script_pubkey(), 50_000); @@ -99,7 +104,7 @@ use crate::{error::Error, Utxo}; use alloc::vec::Vec; use bitcoin::consensus::encode::serialize; -use bitcoin::Script; +use bitcoin::{Script, Weight}; use core::convert::TryInto; use rand::seq::SliceRandom; @@ -302,8 +307,9 @@ fn select_sorted_utxos( (&mut selected_amount, &mut fee_amount), |(selected_amount, fee_amount), (must_use, weighted_utxo)| { if must_use || **selected_amount < target_amount + **fee_amount { - **fee_amount += - fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight); + **fee_amount += fee_rate.fee_wu(Weight::from_wu( + (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64, + )); **selected_amount += weighted_utxo.utxo.txout().value; log::debug!( @@ -351,7 +357,9 @@ struct OutputGroup { impl OutputGroup { fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self { - let fee = fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight); + let fee = fee_rate.fee_wu(Weight::from_wu( + (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64, + )); let effective_value = weighted_utxo.utxo.txout().value as i64 - fee as i64; OutputGroup { weighted_utxo, @@ -681,7 +689,7 @@ mod test { use core::str::FromStr; use bdk_chain::ConfirmationTime; - use bitcoin::{OutPoint, Script, TxOut}; + use bitcoin::{OutPoint, ScriptBuf, TxOut}; use super::*; use crate::types::*; @@ -710,7 +718,7 @@ mod test { outpoint, txout: TxOut { value, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, is_spent: false, @@ -773,7 +781,7 @@ mod test { .unwrap(), txout: TxOut { value: rng.gen_range(0..200000000), - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, is_spent: false, @@ -802,7 +810,7 @@ mod test { .unwrap(), txout: TxOut { value: utxos_value, - script_pubkey: Script::new(), + script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, is_spent: false, @@ -825,7 +833,7 @@ mod test { #[test] fn test_largest_first_coin_selection_success() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 250_000 + FEE_AMOUNT; let result = LargestFirstCoinSelection::default() @@ -846,7 +854,7 @@ mod test { #[test] fn test_largest_first_coin_selection_use_all() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; let result = LargestFirstCoinSelection::default() @@ -867,7 +875,7 @@ mod test { #[test] fn test_largest_first_coin_selection_use_only_necessary() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; let result = LargestFirstCoinSelection::default() @@ -889,7 +897,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_largest_first_coin_selection_insufficient_funds() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 500_000 + FEE_AMOUNT; LargestFirstCoinSelection::default() @@ -907,7 +915,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_largest_first_coin_selection_insufficient_funds_high_fees() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 250_000 + FEE_AMOUNT; LargestFirstCoinSelection::default() @@ -924,7 +932,7 @@ mod test { #[test] fn test_oldest_first_coin_selection_success() { let utxos = get_oldest_first_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 180_000 + FEE_AMOUNT; let result = OldestFirstCoinSelection::default() @@ -945,7 +953,7 @@ mod test { #[test] fn test_oldest_first_coin_selection_use_all() { let utxos = get_oldest_first_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; let result = OldestFirstCoinSelection::default() @@ -966,7 +974,7 @@ mod test { #[test] fn test_oldest_first_coin_selection_use_only_necessary() { let utxos = get_oldest_first_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; let result = OldestFirstCoinSelection::default() @@ -988,7 +996,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_oldest_first_coin_selection_insufficient_funds() { let utxos = get_oldest_first_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 600_000 + FEE_AMOUNT; OldestFirstCoinSelection::default() @@ -1008,7 +1016,7 @@ mod test { let utxos = get_oldest_first_test_utxos(); let target_amount: u64 = utxos.iter().map(|wu| wu.utxo.txout().value).sum::() - 50; - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); OldestFirstCoinSelection::default() .coin_select( @@ -1027,7 +1035,7 @@ mod test { // select three outputs let utxos = generate_same_value_utxos(100_000, 20); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 250_000 + FEE_AMOUNT; @@ -1049,7 +1057,7 @@ mod test { #[test] fn test_bnb_coin_selection_required_are_enough() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; let result = BranchAndBoundCoinSelection::default() @@ -1070,7 +1078,7 @@ mod test { #[test] fn test_bnb_coin_selection_optional_are_enough() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 299756 + FEE_AMOUNT; let result = BranchAndBoundCoinSelection::default() @@ -1106,7 +1114,7 @@ mod test { assert_eq!(amount, 100_000); let amount: u64 = optional.iter().map(|u| u.utxo.txout().value).sum(); assert!(amount > 150_000); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 150_000 + FEE_AMOUNT; @@ -1129,7 +1137,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_bnb_coin_selection_insufficient_funds() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 500_000 + FEE_AMOUNT; BranchAndBoundCoinSelection::default() @@ -1147,7 +1155,7 @@ mod test { #[should_panic(expected = "InsufficientFunds")] fn test_bnb_coin_selection_insufficient_funds_high_fees() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 250_000 + FEE_AMOUNT; BranchAndBoundCoinSelection::default() @@ -1164,7 +1172,7 @@ mod test { #[test] fn test_bnb_coin_selection_check_fee_rate() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 99932; // first utxo's effective value let result = BranchAndBoundCoinSelection::new(0) @@ -1192,7 +1200,7 @@ mod test { for _i in 0..200 { let mut optional_utxos = generate_random_utxos(&mut rng, 16); let target_amount = sum_random_utxos(&mut rng, &mut optional_utxos); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let result = BranchAndBoundCoinSelection::new(0) .coin_select( vec![], @@ -1220,7 +1228,7 @@ mod test { let size_of_change = 31; let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let target_amount = 20_000 + FEE_AMOUNT; BranchAndBoundCoinSelection::new(size_of_change) .bnb( @@ -1251,7 +1259,7 @@ mod test { let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb(); let target_amount = 20_000 + FEE_AMOUNT; - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); BranchAndBoundCoinSelection::new(size_of_change) .bnb( @@ -1287,7 +1295,7 @@ mod test { // cost_of_change + 5. let target_amount = 2 * 50_000 - 2 * 67 - cost_of_change.ceil() as i64 + 5; - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let result = BranchAndBoundCoinSelection::new(size_of_change) .bnb( @@ -1327,7 +1335,7 @@ mod test { let target_amount = optional_utxos[3].effective_value + optional_utxos[23].effective_value; - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let result = BranchAndBoundCoinSelection::new(0) .bnb( @@ -1358,7 +1366,7 @@ mod test { .map(|u| OutputGroup::new(u, fee_rate)) .collect(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let result = BranchAndBoundCoinSelection::default().single_random_draw( vec![], @@ -1376,7 +1384,7 @@ mod test { #[test] fn test_bnb_exclude_negative_effective_value() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let selection = BranchAndBoundCoinSelection::default().coin_select( vec![], @@ -1398,7 +1406,7 @@ mod test { #[test] fn test_bnb_include_negative_effective_value_when_required() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let (required, optional) = utxos .into_iter() @@ -1424,7 +1432,7 @@ mod test { #[test] fn test_bnb_sum_of_effective_value_negative() { let utxos = get_test_utxos(); - let drain_script = Script::default(); + let drain_script = ScriptBuf::default(); let selection = BranchAndBoundCoinSelection::default().coin_select( utxos, diff --git a/crates/bdk/src/wallet/export.rs b/crates/bdk/src/wallet/export.rs index a4d93976..270d7340 100644 --- a/crates/bdk/src/wallet/export.rs +++ b/crates/bdk/src/wallet/export.rs @@ -232,7 +232,7 @@ mod test { input: vec![], output: vec![], version: 0, - lock_time: bitcoin::PackedLockTime::ZERO, + lock_time: bitcoin::absolute::LockTime::ZERO, }; wallet .insert_checkpoint(BlockId { diff --git a/crates/bdk/src/wallet/hardwaresigner.rs b/crates/bdk/src/wallet/hardwaresigner.rs index dce1da8b..aec49297 100644 --- a/crates/bdk/src/wallet/hardwaresigner.rs +++ b/crates/bdk/src/wallet/hardwaresigner.rs @@ -19,7 +19,7 @@ //! # use bdk::wallet::hardwaresigner::HWISigner; //! # use bdk::wallet::AddressIndex::New; //! # use bdk::{FeeRate, KeychainKind, SignOptions, Wallet}; -//! # use hwi::{types::HWIChain, HWIClient}; +//! # use hwi::HWIClient; //! # use std::sync::Arc; //! # //! # fn main() -> Result<(), Box> { @@ -28,7 +28,7 @@ //! panic!("No devices found!"); //! } //! let first_device = devices.remove(0)?; -//! let custom_signer = HWISigner::from_device(&first_device, HWIChain::Test)?; +//! let custom_signer = HWISigner::from_device(&first_device, Network::Testnet.into())?; //! //! # let mut wallet = Wallet::new_no_persist( //! # "", @@ -47,9 +47,9 @@ //! # } //! ``` +use bitcoin::bip32::Fingerprint; use bitcoin::psbt::PartiallySignedTransaction; use bitcoin::secp256k1::{All, Secp256k1}; -use bitcoin::util::bip32::Fingerprint; use hwi::error::Error; use hwi::types::{HWIChain, HWIDevice}; diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index 5eeea45a..2ef69f31 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -29,11 +29,12 @@ use bdk_chain::{ IndexedTxGraph, Persist, PersistBackend, }; use bitcoin::consensus::encode::serialize; +use bitcoin::psbt; use bitcoin::secp256k1::Secp256k1; -use bitcoin::util::psbt; +use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::{ - Address, EcdsaSighashType, LockTime, Network, OutPoint, SchnorrSighashType, Script, Sequence, - Transaction, TxOut, Txid, Witness, + absolute, Address, Network, OutPoint, Script, ScriptBuf, Sequence, Transaction, TxOut, Txid, + Weight, Witness, }; use core::fmt; use core::ops::Deref; @@ -322,11 +323,11 @@ impl Wallet { let (index, spk, additions) = match address_index { AddressIndex::New => { let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain); - (index, spk.clone(), Some(index_additions)) + (index, spk.into(), Some(index_additions)) } AddressIndex::LastUnused => { let ((index, spk), index_additions) = txout_index.next_unused_spk(&keychain); - (index, spk.clone(), Some(index_additions)) + (index, spk.into(), Some(index_additions)) } AddressIndex::Peek(index) => { let (index, spk) = txout_index @@ -396,7 +397,7 @@ impl Wallet { /// script pubkeys the wallet is storing internally). pub fn spks_of_all_keychains( &self, - ) -> BTreeMap + Clone> { + ) -> BTreeMap + Clone> { self.indexed_graph.index.spks_of_all_keychains() } @@ -408,7 +409,7 @@ impl Wallet { pub fn spks_of_keychain( &self, keychain: KeychainKind, - ) -> impl Iterator + Clone { + ) -> impl Iterator + Clone { self.indexed_graph.index.spks_of_keychain(&keychain) } @@ -599,7 +600,7 @@ impl Wallet { /// # use bdk::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); - /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); + /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// let (psbt, details) = { /// let mut builder = wallet.build_tx(); /// builder @@ -716,7 +717,7 @@ impl Wallet { None => self .chain .tip() - .map(|cp| LockTime::from_height(cp.height()).expect("Invalid height")), + .map(|cp| absolute::LockTime::from_height(cp.height()).expect("Invalid height")), h => h, }; @@ -726,7 +727,7 @@ impl Wallet { // Fee sniping can be partially prevented by setting the timelock // to current_height. If we don't know the current_height, // we default to 0. - let fee_sniping_height = current_height.unwrap_or(LockTime::ZERO); + let fee_sniping_height = current_height.unwrap_or(absolute::LockTime::ZERO); // We choose the biggest between the required nlocktime and the fee sniping // height @@ -734,7 +735,7 @@ impl Wallet { // No requirement, just use the fee_sniping_height None => fee_sniping_height, // There's a block-based requirement, but the value is lower than the fee_sniping_height - Some(value @ LockTime::Blocks(_)) if value < fee_sniping_height => fee_sniping_height, + Some(value @ absolute::LockTime::Blocks(_)) if value < fee_sniping_height => fee_sniping_height, // There's a time-based requirement or a block-based requirement greater // than the fee_sniping_height use that value Some(value) => value, @@ -750,7 +751,9 @@ impl Wallet { let n_sequence = match (params.rbf, requirements.csv) { // No RBF or CSV but there's an nLockTime, so the nSequence cannot be final - (None, None) if lock_time != LockTime::ZERO => Sequence::ENABLE_LOCKTIME_NO_RBF, + (None, None) if lock_time != absolute::LockTime::ZERO => { + Sequence::ENABLE_LOCKTIME_NO_RBF + } // No RBF, CSV or nLockTime, make the transaction final (None, None) => Sequence::MAX, @@ -813,7 +816,7 @@ impl Wallet { let mut tx = Transaction { version, - lock_time: lock_time.into(), + lock_time, input: vec![], output: vec![], }; @@ -861,7 +864,7 @@ impl Wallet { // end up with a transaction with a slightly higher fee rate than the requested one. // If, instead, we undershoot, we may end up with a feerate lower than the requested one // - we might come up with non broadcastable txs! - fee_amount += fee_rate.fee_wu(2); + fee_amount += fee_rate.fee_wu(Weight::from_wu(2)); if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeAllowed && internal_descriptor.is_none() @@ -878,7 +881,7 @@ impl Wallet { params.drain_wallet, params.manually_selected_only, params.bumping_fee.is_some(), // we mandate confirmed transactions if we're bumping the fee - current_height.map(LockTime::to_consensus_u32), + current_height.map(absolute::LockTime::to_consensus_u32), ); // get drain script @@ -888,7 +891,7 @@ impl Wallet { let change_keychain = self.map_keychain(KeychainKind::Internal); let ((index, spk), index_additions) = self.indexed_graph.index.next_unused_spk(&change_keychain); - let spk = spk.clone(); + let spk = spk.into(); self.indexed_graph.index.mark_used(&change_keychain, index); self.persist .stage(ChangeSet::from(IndexedAdditions::from(index_additions))); @@ -912,7 +915,7 @@ impl Wallet { .iter() .map(|u| bitcoin::TxIn { previous_output: u.outpoint(), - script_sig: Script::default(), + script_sig: ScriptBuf::default(), sequence: n_sequence, witness: Witness::new(), }) @@ -1000,7 +1003,7 @@ impl Wallet { /// # use bdk::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); - /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); + /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// let (mut psbt, _) = { /// let mut builder = wallet.build_tx(); /// builder @@ -1014,7 +1017,7 @@ impl Wallet { /// let (mut psbt, _) = { /// let mut builder = wallet.build_fee_bump(tx.txid())?; /// builder - /// .fee_rate(FeeRate::from_sat_per_vb(5.0)); + /// .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0)); /// builder.finish()? /// }; /// @@ -1078,6 +1081,7 @@ impl Wallet { let weighted_utxo = match txout_index.index_of_spk(&txout.script_pubkey) { Some(&(keychain, derivation_index)) => { + #[allow(deprecated)] let satisfaction_weight = self .get_descriptor_for_keychain(keychain) .max_satisfaction_weight() @@ -1170,7 +1174,7 @@ impl Wallet { /// # use bdk::*; /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); - /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); + /// # 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(), 50_000); @@ -1207,8 +1211,8 @@ impl Wallet { && !psbt.inputs.iter().all(|i| { i.sighash_type.is_none() || i.sighash_type == Some(EcdsaSighashType::All.into()) - || i.sighash_type == Some(SchnorrSighashType::All.into()) - || i.sighash_type == Some(SchnorrSighashType::Default.into()) + || i.sighash_type == Some(TapSighashType::All.into()) + || i.sighash_type == Some(TapSighashType::Default.into()) }) { return Err(Error::Signer(signer::SignerError::NonStandardSighash)); @@ -1403,13 +1407,14 @@ impl Wallet { .index .index_of_spk(&txout.script_pubkey)?; let descriptor = self.get_descriptor_for_keychain(keychain); - Some(descriptor.at_derivation_index(child)) + descriptor.at_derivation_index(child).ok() } fn get_available_utxos(&self) -> Vec<(LocalUtxo, usize)> { self.list_unspent() .map(|utxo| { let keychain = utxo.keychain; + #[allow(deprecated)] ( utxo, self.get_descriptor_for_keychain(keychain) @@ -1620,7 +1625,9 @@ impl Wallet { }; let desc = self.get_descriptor_for_keychain(keychain); - let derived_descriptor = desc.at_derivation_index(child); + let derived_descriptor = desc + .at_derivation_index(child) + .expect("child can't be hardened"); psbt_input .update_with_descriptor_unchecked(&derived_descriptor) @@ -1669,7 +1676,9 @@ impl Wallet { ); let desc = self.get_descriptor_for_keychain(keychain); - let desc = desc.at_derivation_index(child); + let desc = desc + .at_derivation_index(child) + .expect("child can't be hardened"); if is_input { psbt.update_input_with_descriptor(index, &desc) @@ -1871,7 +1880,7 @@ fn new_tx_details( /// Macro for getting a wallet for use in a doctest macro_rules! doctest_wallet { () => {{ - use $crate::bitcoin::{BlockHash, Transaction, PackedLockTime, TxOut, Network, hashes::Hash}; + use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash}; use $crate::chain::{ConfirmationTime, BlockId}; use $crate::wallet::{AddressIndex, Wallet}; let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)"; @@ -1886,7 +1895,7 @@ macro_rules! doctest_wallet { let address = wallet.get_address(AddressIndex::New).address; let tx = Transaction { version: 1, - lock_time: PackedLockTime(0), + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 500_000, diff --git a/crates/bdk/src/wallet/signer.rs b/crates/bdk/src/wallet/signer.rs index 68dc4645..68b2ecb1 100644 --- a/crates/bdk/src/wallet/signer.rs +++ b/crates/bdk/src/wallet/signer.rs @@ -19,7 +19,7 @@ //! # use core::str::FromStr; //! # use bitcoin::secp256k1::{Secp256k1, All}; //! # use bitcoin::*; -//! # use bitcoin::util::psbt; +//! # use bitcoin::psbt; //! # use bdk::signer::*; //! # use bdk::*; //! # #[derive(Debug)] @@ -86,18 +86,17 @@ use core::cmp::Ordering; use core::fmt; use core::ops::{Bound::Included, Deref}; -use bitcoin::blockdata::opcodes; -use bitcoin::blockdata::script::Builder as ScriptBuilder; -use bitcoin::hashes::{hash160, Hash}; +use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint}; +use bitcoin::hashes::hash160; use bitcoin::secp256k1::Message; -use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint}; -use bitcoin::util::{ecdsa, psbt, schnorr, sighash, taproot}; -use bitcoin::{secp256k1, XOnlyPublicKey}; -use bitcoin::{EcdsaSighashType, PrivateKey, PublicKey, SchnorrSighashType, Script}; +use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType}; +use bitcoin::{ecdsa, psbt, sighash, taproot}; +use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1}; +use bitcoin::{PrivateKey, PublicKey}; use miniscript::descriptor::{ - Descriptor, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, KeyMap, SinglePriv, - SinglePubKey, + Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, + InnerXKey, KeyMap, SinglePriv, SinglePubKey, }; use miniscript::{Legacy, Segwitv0, SigType, Tap, ToPublicKey}; @@ -130,7 +129,7 @@ impl From for SignerId { } /// Signing error -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug)] pub enum SignerError { /// The private key is missing for the required public key MissingKey, @@ -383,6 +382,48 @@ impl InputSigner for SignerWrapper> { } } +fn multikey_to_xkeys( + multikey: DescriptorMultiXKey, +) -> Vec> { + multikey + .derivation_paths + .into_paths() + .into_iter() + .map(|derivation_path| DescriptorXKey { + origin: multikey.origin.clone(), + xkey: multikey.xkey.clone(), + derivation_path, + wildcard: multikey.wildcard, + }) + .collect() +} + +impl SignerCommon for SignerWrapper> { + fn id(&self, secp: &SecpCtx) -> SignerId { + SignerId::from(self.root_fingerprint(secp)) + } + + fn descriptor_secret_key(&self) -> Option { + Some(DescriptorSecretKey::MultiXPrv(self.signer.clone())) + } +} + +impl InputSigner for SignerWrapper> { + fn sign_input( + &self, + psbt: &mut psbt::PartiallySignedTransaction, + input_index: usize, + sign_options: &SignOptions, + secp: &SecpCtx, + ) -> Result<(), SignerError> { + let xkeys = multikey_to_xkeys(self.signer.clone()); + for xkey in xkeys { + SignerWrapper::new(xkey, self.ctx).sign_input(psbt, input_index, sign_options, secp)? + } + Ok(()) + } +} + impl SignerCommon for SignerWrapper { fn id(&self, secp: &SecpCtx) -> SignerId { SignerId::from(self.public_key(secp).to_pubkeyhash(SigType::Ecdsa)) @@ -477,8 +518,16 @@ impl InputSigner for SignerWrapper { } let (hash, hash_ty) = match self.ctx { - SignerContext::Segwitv0 => Segwitv0::sighash(psbt, input_index, ())?, - SignerContext::Legacy => Legacy::sighash(psbt, input_index, ())?, + SignerContext::Segwitv0 => { + let (h, t) = Segwitv0::sighash(psbt, input_index, ())?; + let h = h.to_raw_hash(); + (h, t) + } + SignerContext::Legacy => { + let (h, t) = Legacy::sighash(psbt, input_index, ())?; + let h = h.to_raw_hash(); + (h, t) + } _ => return Ok(()), // handled above }; sign_psbt_ecdsa( @@ -499,12 +548,12 @@ fn sign_psbt_ecdsa( secret_key: &secp256k1::SecretKey, pubkey: PublicKey, psbt_input: &mut psbt::Input, - hash: bitcoin::Sighash, + hash: impl bitcoin::hashes::Hash + bitcoin::secp256k1::ThirtyTwoByteHash, hash_ty: EcdsaSighashType, secp: &SecpCtx, allow_grinding: bool, ) { - let msg = &Message::from_slice(&hash.into_inner()[..]).unwrap(); + let msg = &Message::from(hash); let sig = if allow_grinding { secp.sign_ecdsa_low_r(msg, secret_key) } else { @@ -513,7 +562,7 @@ fn sign_psbt_ecdsa( secp.verify_ecdsa(msg, &sig, &pubkey.inner) .expect("invalid or corrupted ecdsa signature"); - let final_signature = ecdsa::EcdsaSig { sig, hash_ty }; + let final_signature = ecdsa::Signature { sig, hash_ty }; psbt_input.partial_sigs.insert(pubkey, final_signature); } @@ -523,12 +572,10 @@ fn sign_psbt_schnorr( pubkey: XOnlyPublicKey, leaf_hash: Option, psbt_input: &mut psbt::Input, - hash: taproot::TapSighashHash, - hash_ty: SchnorrSighashType, + hash: TapSighash, + hash_ty: TapSighashType, secp: &SecpCtx, ) { - use schnorr::TapTweak; - let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap(); let keypair = match leaf_hash { None => keypair @@ -537,12 +584,12 @@ fn sign_psbt_schnorr( Some(_) => keypair, // no tweak for script spend }; - let msg = &Message::from_slice(&hash.into_inner()[..]).unwrap(); + let msg = &Message::from(hash); let sig = secp.sign_schnorr(msg, &keypair); secp.verify_schnorr(&sig, msg, &XOnlyPublicKey::from_keypair(&keypair).0) .expect("invalid or corrupted schnorr signature"); - let final_signature = schnorr::SchnorrSig { sig, hash_ty }; + let final_signature = taproot::Signature { sig, hash_ty }; if let Some(lh) = leaf_hash { psbt_input @@ -632,6 +679,11 @@ impl SignersContainer { SignerOrdering::default(), Arc::new(SignerWrapper::new(xprv, ctx)), ), + DescriptorSecretKey::MultiXPrv(xprv) => container.add_external( + SignerId::from(xprv.root_fingerprint(secp)), + SignerOrdering::default(), + Arc::new(SignerWrapper::new(xprv, ctx)), + ), }; } @@ -802,7 +854,7 @@ pub(crate) trait ComputeSighash { impl ComputeSighash for Legacy { type Extra = (); - type Sighash = bitcoin::Sighash; + type Sighash = sighash::LegacySighash; type SighashType = EcdsaSighashType; fn sighash( @@ -849,19 +901,9 @@ impl ComputeSighash for Legacy { } } -fn p2wpkh_script_code(script: &Script) -> Script { - ScriptBuilder::new() - .push_opcode(opcodes::all::OP_DUP) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&script[2..]) - .push_opcode(opcodes::all::OP_EQUALVERIFY) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script() -} - impl ComputeSighash for Segwitv0 { type Extra = (); - type Sighash = bitcoin::Sighash; + type Sighash = sighash::SegwitV0Sighash; type SighashType = EcdsaSighashType; fn sighash( @@ -908,14 +950,21 @@ impl ComputeSighash for Segwitv0 { Some(ref witness_script) => witness_script.clone(), None => { if utxo.script_pubkey.is_v0_p2wpkh() { - p2wpkh_script_code(&utxo.script_pubkey) + utxo.script_pubkey + .p2wpkh_script_code() + .expect("We check above that the spk is a p2wpkh") } else if psbt_input .redeem_script .as_ref() - .map(Script::is_v0_p2wpkh) + .map(|s| s.is_v0_p2wpkh()) .unwrap_or(false) { - p2wpkh_script_code(psbt_input.redeem_script.as_ref().unwrap()) + psbt_input + .redeem_script + .as_ref() + .unwrap() + .p2wpkh_script_code() + .expect("We check above that the spk is a p2wpkh") } else { return Err(SignerError::MissingWitnessScript); } @@ -936,14 +985,14 @@ impl ComputeSighash for Segwitv0 { impl ComputeSighash for Tap { type Extra = Option; - type Sighash = taproot::TapSighashHash; - type SighashType = SchnorrSighashType; + type Sighash = TapSighash; + type SighashType = TapSighashType; fn sighash( psbt: &psbt::PartiallySignedTransaction, input_index: usize, extra: Self::Extra, - ) -> Result<(Self::Sighash, SchnorrSighashType), SignerError> { + ) -> Result<(Self::Sighash, TapSighashType), SignerError> { if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() { return Err(SignerError::InputIndexOutOfRange); } @@ -952,8 +1001,8 @@ impl ComputeSighash for Tap { let sighash_type = psbt_input .sighash_type - .unwrap_or_else(|| SchnorrSighashType::Default.into()) - .schnorr_hash_ty() + .unwrap_or_else(|| TapSighashType::Default.into()) + .taproot_hash_ty() .map_err(|_| SignerError::InvalidSighash)?; let witness_utxos = (0..psbt.inputs.len()) .map(|i| psbt.get_utxo_for(i)) @@ -1015,8 +1064,8 @@ mod signers_container_tests { use crate::descriptor::IntoWalletDescriptor; use crate::keys::{DescriptorKey, IntoDescriptorKey}; use assert_matches::assert_matches; + use bitcoin::bip32; use bitcoin::secp256k1::{All, Secp256k1}; - use bitcoin::util::bip32; use bitcoin::Network; use core::str::FromStr; use miniscript::ScriptContext; diff --git a/crates/bdk/src/wallet/tx_builder.rs b/crates/bdk/src/wallet/tx_builder.rs index 165f01f2..d7bcd711 100644 --- a/crates/bdk/src/wallet/tx_builder.rs +++ b/crates/bdk/src/wallet/tx_builder.rs @@ -18,7 +18,7 @@ //! # use bitcoin::*; //! # use bdk::*; //! # use bdk::wallet::tx_builder::CreateTx; -//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); +//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); //! # let mut wallet = doctest_wallet!(); //! // create a TxBuilder from a wallet //! let mut tx_builder = wallet.build_tx(); @@ -27,7 +27,7 @@ //! // Create a transaction with one output to `to_address` of 50_000 satoshi //! .add_recipient(to_address.script_pubkey(), 50_000) //! // With a custom fee rate of 5.0 satoshi/vbyte -//! .fee_rate(FeeRate::from_sat_per_vb(5.0)) +//! .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0)) //! // Only spend non-change outputs //! .do_not_spend_change() //! // Turn on RBF signaling @@ -43,8 +43,8 @@ use bdk_chain::PersistBackend; use core::cell::RefCell; use core::marker::PhantomData; -use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt}; -use bitcoin::{LockTime, OutPoint, Script, Sequence, Transaction}; +use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt}; +use bitcoin::{absolute, script::PushBytes, OutPoint, ScriptBuf, Sequence, Transaction}; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; use super::ChangeSet; @@ -82,7 +82,7 @@ impl TxBuilderContext for BumpFee {} /// # use bitcoin::*; /// # use core::str::FromStr; /// # let mut wallet = doctest_wallet!(); -/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); +/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// # let addr2 = addr1.clone(); /// // chaining /// let (psbt1, details) = { @@ -129,9 +129,9 @@ pub struct TxBuilder<'a, D, Cs, Ctx> { //TODO: TxParams should eventually be exposed publicly. #[derive(Default, Debug, Clone)] pub(crate) struct TxParams { - pub(crate) recipients: Vec<(Script, u64)>, + pub(crate) recipients: Vec<(ScriptBuf, u64)>, pub(crate) drain_wallet: bool, - pub(crate) drain_to: Option