diff --git a/Cargo.toml b/Cargo.toml index 53ceb7cd4..5d2be3559 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,55 @@ members = [ [workspace.package] authors = ["Bitcoin Dev Kit Developers"] + +[patch.crates-io.electrsd] +git = "https://github.com/tcharding/electrsd" +branch = "test-bitcoin" + +[patch.crates-io.esplora-client] +git = "https://github.com/tcharding/rust-esplora-client" +branch = "test-bitcoin" + +[patch.crates-io.electrum-client] +git = "https://github.com/tcharding/rust-electrum-client" +branch = "test-bitcoin" + +[patch.crates-io.hwi] +git = "https://github.com/tcharding/rust-hwi" +branch = "test-bitcoin" + +[patch.crates-io.miniscript] +git = "https://github.com/tcharding/rust-miniscript" +branch = "test-bitcoin" + +[patch.crates-io.bitcoind] +git = "https://github.com/tcharding/bitcoind/" +branch = "test-bitcoin" + +[patch.crates-io.bitcoincore-rpc] +git = "https://github.com/tcharding/rust-bitcoincore-rpc" +branch = "test-bitcoin" + +[patch.crates-io.base58ck] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" + +[patch.crates-io.bitcoin] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" + +[patch.crates-io.bitcoin_hashes] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" + +[patch.crates-io.bitcoin-internals] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" + +[patch.crates-io.bitcoin-io] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" + +[patch.crates-io.bitcoin-units] +git = "https://github.com/rust-bitcoin/rust-bitcoin" +branch = "rc1-fixes" diff --git a/crates/bdk/Cargo.toml b/crates/bdk/Cargo.toml index 396e5675d..fa078aa3b 100644 --- a/crates/bdk/Cargo.toml +++ b/crates/bdk/Cargo.toml @@ -14,11 +14,11 @@ rust-version = "1.63" [dependencies] rand = "^0.8" -miniscript = { version = "10.0.0", features = ["serde"], default-features = false } -bitcoin = { version = "0.30.0", features = ["serde", "base64", "rand-std"], default-features = false } +miniscript = { version = "12.0.0", features = ["serde"], default-features = false } +bitcoin = { version = "0.32.0-rc1", 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.11.0", features = ["miniscript", "serde"], default-features = false } +bdk_chain = { path = "../chain", features = ["miniscript", "serde"], default-features = false } # Optional dependencies bip39 = { version = "2.0", optional = true } diff --git a/crates/bdk/src/descriptor/dsl.rs b/crates/bdk/src/descriptor/dsl.rs index 50cd978f7..bac73e8af 100644 --- a/crates/bdk/src/descriptor/dsl.rs +++ b/crates/bdk/src/descriptor/dsl.rs @@ -274,14 +274,13 @@ macro_rules! impl_sortedmulti { #[macro_export] macro_rules! parse_tap_tree { ( @merge $tree_a:expr, $tree_b:expr) => {{ - use $crate::alloc::sync::Arc; use $crate::miniscript::descriptor::TapTree; $tree_a .and_then(|tree_a| Ok((tree_a, $tree_b?))) .and_then(|((a_tree, mut a_keymap, a_networks), (b_tree, b_keymap, b_networks))| { a_keymap.extend(b_keymap.into_iter()); - Ok((TapTree::Tree(Arc::new(a_tree), Arc::new(b_tree)), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks))) + Ok((TapTree::combine(a_tree, b_tree), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks))) }) }}; @@ -703,10 +702,10 @@ macro_rules! fragment { $crate::keys::make_pkh($key, &secp) }); ( after ( $value:expr ) ) => ({ - $crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value)) + $crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value).expect("TODO: Handle error")) }); ( older ( $value:expr ) ) => ({ - $crate::impl_leaf_opcode_value!(Older, $crate::bitcoin::Sequence($value)) // TODO!! + $crate::impl_leaf_opcode_value!(Older, $crate::miniscript::RelLockTime::from_consensus($value).expect("TODO: Handle error")) }); ( sha256 ( $hash:expr ) ) => ({ $crate::impl_leaf_opcode_value!(Sha256, $hash) @@ -769,7 +768,11 @@ macro_rules! fragment { ( multi_vec ( $thresh:expr, $keys:expr ) ) => ({ let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); - $crate::keys::make_multi($thresh, $crate::miniscript::Terminal::Multi, $keys, &secp) + let fun = |k, pks| { + let thresh = $crate::miniscript::Threshold::new(k, pks).expect("TODO: Handle this error"); + $crate::miniscript::Terminal::Multi(thresh) + }; + $crate::keys::make_multi($thresh, fun, $keys, &secp) }); ( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({ $crate::group_multi_keys!( $( $key ),* ) @@ -778,7 +781,11 @@ macro_rules! fragment { ( multi_a_vec ( $thresh:expr, $keys:expr ) ) => ({ let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); - $crate::keys::make_multi($thresh, $crate::miniscript::Terminal::MultiA, $keys, &secp) + let fun = |k, pks| { + let thresh = $crate::miniscript::Threshold::new(k, pks).expect("TODO: Handle this error"); + $crate::miniscript::Terminal::MultiA(thresh) + }; + $crate::keys::make_multi($thresh, fun, $keys, &secp) }); ( multi_a ( $thresh:expr $(, $key:expr )+ ) ) => ({ $crate::group_multi_keys!( $( $key ),* ) @@ -806,7 +813,7 @@ 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::Network::{Bitcoin, Regtest, Signet, Testnet}; use bitcoin::PrivateKey; // test the descriptor!() macro @@ -936,7 +943,7 @@ mod test { #[test] fn test_bip32_legacy_descriptors() { - let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path = bip32::DerivationPath::from_str("m/0").unwrap(); let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap(); @@ -981,7 +988,7 @@ mod test { #[test] fn test_bip32_segwitv0_descriptors() { - let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path = bip32::DerivationPath::from_str("m/0").unwrap(); let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap(); @@ -1038,10 +1045,10 @@ mod test { #[test] fn test_dsl_sortedmulti() { - let key_1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path_1 = bip32::DerivationPath::from_str("m/0").unwrap(); - let key_2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap(); + let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap(); let path_2 = bip32::DerivationPath::from_str("m/1").unwrap(); let desc_key1 = (key_1, path_1); @@ -1097,7 +1104,7 @@ mod test { // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor #[test] fn test_valid_networks() { - let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path = bip32::DerivationPath::from_str("m/0").unwrap(); let desc_key = (xprv, path).into_descriptor_key().unwrap(); @@ -1107,7 +1114,7 @@ mod test { [Testnet, Regtest, Signet].iter().cloned().collect() ); - let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap(); + let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap(); let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap(); let desc_key = (xprv, path).into_descriptor_key().unwrap(); @@ -1120,15 +1127,15 @@ mod test { fn test_key_maps_merged() { let secp = Secp256k1::new(); - let xprv1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let xprv1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path1 = bip32::DerivationPath::from_str("m/0").unwrap(); let desc_key1 = (xprv1, path1.clone()).into_descriptor_key().unwrap(); - let xprv2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap(); + let xprv2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap(); let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap(); let desc_key2 = (xprv2, path2.clone()).into_descriptor_key().unwrap(); - let xprv3 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap(); + let xprv3 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap(); let path3 = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap(); let desc_key3 = (xprv3, path3.clone()).into_descriptor_key().unwrap(); @@ -1152,7 +1159,7 @@ mod test { #[test] fn test_script_context_validation() { // this compiles - let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let path = bip32::DerivationPath::from_str("m/0").unwrap(); let desc_key: DescriptorKey = (xprv, path).into_descriptor_key().unwrap(); diff --git a/crates/bdk/src/descriptor/error.rs b/crates/bdk/src/descriptor/error.rs index b36e69e63..54db9889d 100644 --- a/crates/bdk/src/descriptor/error.rs +++ b/crates/bdk/src/descriptor/error.rs @@ -37,11 +37,11 @@ pub enum Error { /// Error during base58 decoding Base58(bitcoin::base58::Error), /// Key-related error - Pk(bitcoin::key::Error), + Pk(bitcoin::key::ParsePublicKeyError), /// Miniscript error Miniscript(miniscript::Error), /// Hex decoding error - Hex(bitcoin::hashes::hex::Error), + Hex(bitcoin::hex::HexToBytesError), } impl From for Error { @@ -98,8 +98,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: bitcoin::key::Error) -> Self { +impl From for Error { + fn from(err: bitcoin::key::ParsePublicKeyError) -> Self { Error::Pk(err) } } @@ -110,8 +110,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: bitcoin::hashes::hex::Error) -> Self { +impl From for Error { + fn from(err: bitcoin::hex::HexToBytesError) -> Self { Error::Hex(err) } } diff --git a/crates/bdk/src/descriptor/mod.rs b/crates/bdk/src/descriptor/mod.rs index 153ade254..0d3948104 100644 --- a/crates/bdk/src/descriptor/mod.rs +++ b/crates/bdk/src/descriptor/mod.rs @@ -18,7 +18,7 @@ use crate::collections::BTreeMap; use alloc::string::String; use alloc::vec::Vec; -use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource}; +use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, KeySource, Xpub}; use bitcoin::{key::XOnlyPublicKey, secp256k1, PublicKey}; use bitcoin::{psbt, taproot}; use bitcoin::{Network, TxOut}; @@ -229,7 +229,7 @@ impl IntoWalletDescriptor for DescriptorTemplateOut { let pk = match pk { DescriptorPublicKey::XPub(ref xpub) => { let mut xpub = xpub.clone(); - xpub.xkey.network = self.network; + xpub.xkey.network = self.network.into(); DescriptorPublicKey::XPub(xpub) } @@ -264,11 +264,11 @@ impl IntoWalletDescriptor for DescriptorTemplateOut { .map(|(mut k, mut v)| { match (&mut k, &mut v) { (DescriptorPublicKey::XPub(xpub), DescriptorSecretKey::XPrv(xprv)) => { - xpub.xkey.network = network; - xprv.xkey.network = network; + xpub.xkey.network = network.into(); + xprv.xkey.network = network.into(); } (_, DescriptorSecretKey::Single(key)) => { - key.key.network = network; + key.key.network = network.into(); } _ => {} } @@ -377,7 +377,7 @@ where pub(crate) trait DescriptorMeta { fn is_witness(&self) -> bool; fn is_taproot(&self) -> bool; - fn get_extended_keys(&self) -> Vec>; + fn get_extended_keys(&self) -> Vec>; fn derive_from_hd_keypaths( &self, hd_keypaths: &HdKeyPaths, @@ -418,7 +418,7 @@ impl DescriptorMeta for ExtendedDescriptor { self.desc_type() == DescriptorType::Tr } - fn get_extended_keys(&self) -> Vec> { + fn get_extended_keys(&self) -> Vec> { let mut answer = Vec::new(); self.for_each_key(|pk| { @@ -438,21 +438,20 @@ impl DescriptorMeta for ExtendedDescriptor { secp: &SecpCtx, ) -> Option { // Ensure that deriving `xpub` with `path` yields `expected` - let verify_key = |xpub: &DescriptorXKey, - path: &DerivationPath, - expected: &SinglePubKey| { - let derived = xpub - .xkey - .derive_pub(secp, path) - .expect("The path should never contain hardened derivation steps") - .public_key; - - match expected { - SinglePubKey::FullKey(pk) if &PublicKey::new(derived) == pk => true, - SinglePubKey::XOnly(pk) if &XOnlyPublicKey::from(derived) == pk => true, - _ => false, - } - }; + let verify_key = + |xpub: &DescriptorXKey, path: &DerivationPath, expected: &SinglePubKey| { + let derived = xpub + .xkey + .derive_pub(secp, path) + .expect("The path should never contain hardened derivation steps") + .public_key; + + match expected { + SinglePubKey::FullKey(pk) if &PublicKey::new(derived) == pk => true, + SinglePubKey::XOnly(pk) if &XOnlyPublicKey::from(derived) == pk => true, + _ => false, + } + }; let mut path_found = None; @@ -605,10 +604,10 @@ mod test { use core::str::FromStr; use assert_matches::assert_matches; - use bitcoin::hashes::hex::FromHex; + use bitcoin::hex::FromHex; use bitcoin::secp256k1::Secp256k1; - use bitcoin::ScriptBuf; - use bitcoin::{bip32, psbt::Psbt}; + use bitcoin::{bip32, Psbt}; + use bitcoin::{NetworkKind, ScriptBuf}; use super::*; use crate::psbt::PsbtUtils; @@ -727,7 +726,7 @@ mod test { let secp = Secp256k1::new(); - let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3c3gF1DUWpWNr2SG2XrG8oYPpqYh7hoWsJy9NjabErnzriJPpnGHyKz5NgdXmq1KVbqS1r4NXdCoKitWg5e86zqXHa8kxyB").unwrap(); + let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3c3gF1DUWpWNr2SG2XrG8oYPpqYh7hoWsJy9NjabErnzriJPpnGHyKz5NgdXmq1KVbqS1r4NXdCoKitWg5e86zqXHa8kxyB").unwrap(); let path = bip32::DerivationPath::from_str("m/0").unwrap(); // here `to_descriptor_key` will set the valid networks for the key to only mainnet, since @@ -744,9 +743,9 @@ mod test { .unwrap(); let mut xprv_testnet = xprv; - xprv_testnet.network = Network::Testnet; + xprv_testnet.network = NetworkKind::Test; - let xpub_testnet = bip32::ExtendedPubKey::from_priv(&secp, &xprv_testnet); + let xpub_testnet = bip32::Xpub::from_priv(&secp, &xprv_testnet); let desc_pubkey = DescriptorPublicKey::XPub(DescriptorXKey { xkey: xpub_testnet, origin: None, @@ -836,7 +835,7 @@ mod test { fn test_descriptor_from_str_from_output_of_macro() { let secp = Secp256k1::new(); - let tpub = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap(); + let tpub = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap(); let path = bip32::DerivationPath::from_str("m/1/2").unwrap(); let key = (tpub, path).into_descriptor_key().unwrap(); @@ -895,7 +894,7 @@ mod test { .update_with_descriptor_unchecked(&descriptor) .unwrap(); - assert_eq!(psbt_input.redeem_script, Some(script.to_v0_p2wsh())); + assert_eq!(psbt_input.redeem_script, Some(script.to_p2wsh())); assert_eq!(psbt_input.witness_script, Some(script)); } } diff --git a/crates/bdk/src/descriptor/policy.rs b/crates/bdk/src/descriptor/policy.rs index 523e94b40..e036a673a 100644 --- a/crates/bdk/src/descriptor/policy.rs +++ b/crates/bdk/src/descriptor/policy.rs @@ -54,8 +54,9 @@ use miniscript::descriptor::{ DescriptorPublicKey, ShInner, SinglePub, SinglePubKey, SortedMultiVec, WshInner, }; use miniscript::hash256; +use miniscript::miniscript::limits::{MAX_PUBKEYS_IN_CHECKSIGADD, MAX_PUBKEYS_PER_MULTISIG}; use miniscript::{ - Descriptor, Miniscript, Satisfier, ScriptContext, SigType, Terminal, ToPublicKey, + Descriptor, Miniscript, Satisfier, ScriptContext, SigType, Terminal, Threshold, ToPublicKey, }; use crate::descriptor::ExtractPolicy; @@ -586,30 +587,78 @@ impl Policy { Ok(Some(policy)) } - fn make_multisig( - keys: &[DescriptorPublicKey], + fn make_multi( + threshold: &Threshold, signers: &SignersContainer, build_sat: BuildSatisfaction, - threshold: usize, sorted: bool, secp: &SecpCtx, ) -> Result, PolicyError> { - if threshold == 0 { - return Ok(None); + let parsed_keys = threshold.iter().map(|k| PkOrF::from_key(k, secp)).collect(); + + let mut contribution = Satisfaction::Partial { + n: threshold.n(), + m: threshold.k(), + items: vec![], + conditions: Default::default(), + sorted: Some(sorted), + }; + let mut satisfaction = contribution.clone(); + + for (index, key) in threshold.iter().enumerate() { + if signers.find(signer_id(key, secp)).is_some() { + contribution.add( + &Satisfaction::Complete { + condition: Default::default(), + }, + index, + )?; + } + + if let Some(psbt) = build_sat.psbt() { + if Ctx::find_signature(psbt, key, secp) { + satisfaction.add( + &Satisfaction::Complete { + condition: Default::default(), + }, + index, + )?; + } + } + } + satisfaction.finalize(); + contribution.finalize(); + + let mut policy: Policy = SatisfiableItem::Multisig { + keys: parsed_keys, + threshold: threshold.k(), } + .into(); + policy.contribution = contribution; + policy.satisfaction = satisfaction; + + Ok(Some(policy)) + } - let parsed_keys = keys.iter().map(|k| PkOrF::from_key(k, secp)).collect(); + fn make_multi_a( + threshold: &Threshold, + signers: &SignersContainer, + build_sat: BuildSatisfaction, + sorted: bool, + secp: &SecpCtx, + ) -> Result, PolicyError> { + let parsed_keys = threshold.iter().map(|k| PkOrF::from_key(k, secp)).collect(); let mut contribution = Satisfaction::Partial { - n: keys.len(), - m: threshold, + n: threshold.n(), + m: threshold.k(), items: vec![], conditions: Default::default(), sorted: Some(sorted), }; let mut satisfaction = contribution.clone(); - for (index, key) in keys.iter().enumerate() { + for (index, key) in threshold.iter().enumerate() { if signers.find(signer_id(key, secp)).is_some() { contribution.add( &Satisfaction::Complete { @@ -635,7 +684,7 @@ impl Policy { let mut policy: Policy = SatisfiableItem::Multisig { keys: parsed_keys, - threshold, + threshold: threshold.k(), } .into(); policy.contribution = contribution; @@ -952,11 +1001,14 @@ impl ExtractPolicy for Miniscript { - let mut policy: Policy = SatisfiableItem::RelativeTimelock { value: *value }.into(); + let mut policy: Policy = SatisfiableItem::RelativeTimelock { + value: ((*value).into()), + } + .into(); policy.contribution = Satisfaction::Complete { condition: Condition { timelock: None, - csv: Some(*value), + csv: Some(Sequence::from(*value)), }, }; if let BuildSatisfaction::PsbtTimelocks { @@ -966,9 +1018,11 @@ impl ExtractPolicy for Miniscript::check_older(&older, *value); - let inputs_sat = psbt_inputs_sat(psbt) - .all(|sat| Satisfier::::check_older(&sat, *value)); + let older_sat = + Satisfier::::check_older(&older, (*value).into()); + let inputs_sat = psbt_inputs_sat(psbt).all(|sat| { + Satisfier::::check_older(&sat, (*value).into()) + }); if older_sat && inputs_sat { policy.satisfaction = policy.contribution.clone(); } @@ -986,8 +1040,11 @@ impl ExtractPolicy for Miniscript { Some(SatisfiableItem::Hash160Preimage { hash: *hash }.into()) } - Terminal::Multi(k, pks) | Terminal::MultiA(k, pks) => { - Policy::make_multisig::(pks, signers, build_sat, *k, false, secp)? + Terminal::Multi(ref thresh) => { + Policy::make_multi::(thresh, signers, build_sat, false, secp)? + } + Terminal::MultiA(ref thresh) => { + Policy::make_multi_a::(thresh, signers, build_sat, false, secp)? } // Identities Terminal::Alt(inner) @@ -1087,13 +1144,10 @@ impl ExtractPolicy for Descriptor { build_sat: BuildSatisfaction, secp: &SecpCtx, ) -> Result, Error> { - Ok(Policy::make_multisig::( - keys.pks.as_ref(), - signers, - build_sat, - keys.k, - true, - secp, + let thresh = + Threshold::new(keys.k(), keys.pks().to_vec()).expect("TODO: Handle this error"); + Ok(Policy::make_multi::( + &thresh, signers, build_sat, true, secp, )?) } @@ -1137,7 +1191,7 @@ impl ExtractPolicy for Descriptor { let key_spend_sig = miniscript::Tap::make_signature(tr.internal_key(), signers, build_sat, secp); - if tr.taptree().is_none() { + if tr.tap_tree().is_none() { Ok(Some(key_spend_sig)) } else { let mut items = vec![key_spend_sig]; @@ -1184,8 +1238,8 @@ mod test { secp: &SecpCtx, ) -> (DescriptorKey, DescriptorKey, Fingerprint) { let path = bip32::DerivationPath::from_str(path).unwrap(); - let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap(); - let tpub = bip32::ExtendedPubKey::from_priv(secp, &tprv); + let tprv = bip32::Xpriv::from_str(tprv).unwrap(); + let tpub = bip32::Xpub::from_priv(secp, &tprv); let fingerprint = tprv.fingerprint(secp); let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap(); let pubkey = (tpub, path).into_descriptor_key().unwrap(); diff --git a/crates/bdk/src/descriptor/template.rs b/crates/bdk/src/descriptor/template.rs index 2773795a8..84227a70d 100644 --- a/crates/bdk/src/descriptor/template.rs +++ b/crates/bdk/src/descriptor/template.rs @@ -195,7 +195,7 @@ impl> DescriptorTemplate for P2TR { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip44; /// -/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip44(key.clone(), KeychainKind::External), /// Some(Bip44(key, KeychainKind::Internal)), @@ -232,7 +232,7 @@ impl> DescriptorTemplate for Bip44 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip44Public; /// -/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; +/// let key = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?; /// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip44Public(key.clone(), fingerprint, KeychainKind::External), @@ -270,7 +270,7 @@ impl> DescriptorTemplate for Bip44Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip49; /// -/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip49(key.clone(), KeychainKind::External), /// Some(Bip49(key, KeychainKind::Internal)), @@ -307,7 +307,7 @@ impl> DescriptorTemplate for Bip49 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip49Public; /// -/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; +/// let key = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?; /// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip49Public(key.clone(), fingerprint, KeychainKind::External), @@ -345,7 +345,7 @@ impl> DescriptorTemplate for Bip49Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip84; /// -/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip84(key.clone(), KeychainKind::External), /// Some(Bip84(key, KeychainKind::Internal)), @@ -382,7 +382,7 @@ impl> DescriptorTemplate for Bip84 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip84Public; /// -/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; +/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; /// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip84Public(key.clone(), fingerprint, KeychainKind::External), @@ -420,7 +420,7 @@ impl> DescriptorTemplate for Bip84Public { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip86; /// -/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; +/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?; /// let mut wallet = Wallet::new_no_persist( /// Bip86(key.clone(), KeychainKind::External), /// Some(Bip86(key, KeychainKind::Internal)), @@ -457,7 +457,7 @@ impl> DescriptorTemplate for Bip86 { /// # use bdk::wallet::AddressIndex::New; /// use bdk::template::Bip86Public; /// -/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; +/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?; /// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?; /// let mut wallet = Wallet::new_no_persist( /// Bip86Public(key.clone(), fingerprint, KeychainKind::External), @@ -559,6 +559,7 @@ mod test { use crate::descriptor::{DescriptorError, DescriptorMeta}; use crate::keys::ValidNetworks; use assert_matches::assert_matches; + use bitcoin::NetworkKind; use miniscript::descriptor::{DescriptorPublicKey, KeyMap}; use miniscript::Descriptor; @@ -567,8 +568,8 @@ mod test { fn test_bip44_template_cointype() { use bitcoin::bip32::ChildNumber::{self, Hardened}; - let xprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap(); - assert_eq!(Network::Bitcoin, xprvkey.network); + let xprvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap(); + assert_eq!(NetworkKind::Main, xprvkey.network); let xdesc = Bip44(xprvkey, KeychainKind::Internal) .build(Network::Bitcoin) .unwrap(); @@ -581,8 +582,8 @@ mod test { assert_matches!(coin_type, Hardened { index: 0 }); } - let tprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); - assert_eq!(Network::Testnet, tprvkey.network); + let tprvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + assert_eq!(NetworkKind::Test, tprvkey.network); let tdesc = Bip44(tprvkey, KeychainKind::Internal) .build(Network::Testnet) .unwrap(); @@ -740,7 +741,7 @@ mod test { // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)` #[test] fn test_bip44_template() { - let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip44(prvkey, KeychainKind::External).build(Network::Bitcoin), false, @@ -770,7 +771,7 @@ mod test { // BIP44 public `pkh(key/{0,1}/*)` #[test] fn test_bip44_public_template() { - let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); + let pubkey = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap(); let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip44Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), @@ -801,7 +802,7 @@ mod test { // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))` #[test] fn test_bip49_template() { - let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip49(prvkey, KeychainKind::External).build(Network::Bitcoin), true, @@ -831,7 +832,7 @@ mod test { // BIP49 public `sh(wpkh(key/{0,1}/*))` #[test] fn test_bip49_public_template() { - let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); + let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap(); let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip49Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), @@ -862,7 +863,7 @@ mod test { // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)` #[test] fn test_bip84_template() { - let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); check( Bip84(prvkey, KeychainKind::External).build(Network::Bitcoin), true, @@ -892,7 +893,7 @@ mod test { // BIP84 public `wpkh(key/{0,1}/*)` #[test] fn test_bip84_public_template() { - let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); + let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap(); let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap(); check( Bip84Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), @@ -924,7 +925,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::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap(); + let prvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap(); check( Bip86(prvkey, KeychainKind::External).build(Network::Bitcoin), false, @@ -955,7 +956,7 @@ 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::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap(); + let pubkey = bitcoin::bip32::Xpub::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap(); let fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap(); check( Bip86Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin), diff --git a/crates/bdk/src/keys/bip39.rs b/crates/bdk/src/keys/bip39.rs index 8b09ac287..7158505f3 100644 --- a/crates/bdk/src/keys/bip39.rs +++ b/crates/bdk/src/keys/bip39.rs @@ -57,7 +57,7 @@ pub type MnemonicWithPassphrase = (Mnemonic, Option); #[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))] impl DerivableKey for Seed { fn into_extended_key(self) -> Result, KeyError> { - Ok(bip32::ExtendedPrivKey::new_master(Network::Bitcoin, &self[..])?.into()) + Ok(bip32::Xpriv::new_master(Network::Bitcoin, &self[..])?.into()) } fn into_descriptor_key( diff --git a/crates/bdk/src/keys/mod.rs b/crates/bdk/src/keys/mod.rs index 541d439a6..53dbf5f58 100644 --- a/crates/bdk/src/keys/mod.rs +++ b/crates/bdk/src/keys/mod.rs @@ -23,15 +23,15 @@ use core::str::FromStr; use bitcoin::secp256k1::{self, Secp256k1, Signing}; use bitcoin::bip32; -use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey}; +use bitcoin::{key::XOnlyPublicKey, Network, NetworkKind, PrivateKey, PublicKey}; use miniscript::descriptor::{Descriptor, DescriptorXKey, Wildcard}; pub use miniscript::descriptor::{ DescriptorPublicKey, DescriptorSecretKey, KeyMap, SinglePriv, SinglePub, SinglePubKey, SortedMultiVec, }; -pub use miniscript::ScriptContext; use miniscript::{Miniscript, Terminal}; +pub use miniscript::{ScriptContext, Threshold}; use crate::descriptor::{CheckMiniscript, DescriptorError}; use crate::wallet::utils::SecpCtx; @@ -110,7 +110,7 @@ impl DescriptorKey { Ok((public, KeyMap::default(), valid_networks)) } DescriptorKey::Secret(secret, valid_networks, _) => { - let mut key_map = KeyMap::with_capacity(1); + let mut key_map = KeyMap::new(); let public = secret .to_public(secp) @@ -309,15 +309,15 @@ pub trait IntoDescriptorKey: Sized { /// Enum for extended keys that can be either `xprv` or `xpub` /// -/// An instance of [`ExtendedKey`] can be constructed from an [`ExtendedPrivKey`](bip32::ExtendedPrivKey) -/// or an [`ExtendedPubKey`](bip32::ExtendedPubKey) by using the `From` trait. +/// An instance of [`ExtendedKey`] can be constructed from an [`Xpriv`](bip32::Xpriv) +/// or an [`Xpub`](bip32::Xpub) by using the `From` trait. /// /// Defaults to the [`Legacy`](miniscript::Legacy) context. pub enum ExtendedKey { /// A private extended key, aka an `xprv` - Private((bip32::ExtendedPrivKey, PhantomData)), + Private((bip32::Xpriv, PhantomData)), /// A public extended key, aka an `xpub` - Public((bip32::ExtendedPubKey, PhantomData)), + Public((bip32::Xpub, PhantomData)), } impl ExtendedKey { @@ -329,43 +329,43 @@ impl ExtendedKey { } } - /// Transform the [`ExtendedKey`] into an [`ExtendedPrivKey`](bip32::ExtendedPrivKey) for the + /// Transform the [`ExtendedKey`] into an [`Xpriv`](bip32::Xpriv) for the /// given [`Network`], if the key contains the private data - pub fn into_xprv(self, network: Network) -> Option { + pub fn into_xprv(self, network: Network) -> Option { match self { ExtendedKey::Private((mut xprv, _)) => { - xprv.network = network; + xprv.network = network.into(); Some(xprv) } ExtendedKey::Public(_) => None, } } - /// Transform the [`ExtendedKey`] into an [`ExtendedPubKey`](bip32::ExtendedPubKey) for the + /// Transform the [`ExtendedKey`] into an [`Xpub`](bip32::Xpub) for the /// given [`Network`] pub fn into_xpub( self, network: bitcoin::Network, secp: &Secp256k1, - ) -> bip32::ExtendedPubKey { + ) -> bip32::Xpub { let mut xpub = match self { - ExtendedKey::Private((xprv, _)) => bip32::ExtendedPubKey::from_priv(secp, &xprv), + ExtendedKey::Private((xprv, _)) => bip32::Xpub::from_priv(secp, &xprv), ExtendedKey::Public((xpub, _)) => xpub, }; - xpub.network = network; + xpub.network = network.into(); xpub } } -impl From for ExtendedKey { - fn from(xpub: bip32::ExtendedPubKey) -> Self { +impl From for ExtendedKey { + fn from(xpub: bip32::Xpub) -> Self { ExtendedKey::Public((xpub, PhantomData)) } } -impl From for ExtendedKey { - fn from(xprv: bip32::ExtendedPrivKey) -> Self { +impl From for ExtendedKey { + fn from(xprv: bip32::Xpriv) -> Self { ExtendedKey::Private((xprv, PhantomData)) } } @@ -383,8 +383,8 @@ impl From for ExtendedKey { /// /// ## Examples /// -/// Key types that can be directly converted into an [`ExtendedPrivKey`] or -/// an [`ExtendedPubKey`] can implement only the required `into_extended_key()` method. +/// Key types that can be directly converted into an [`Xpriv`] or +/// an [`Xpub`] can implement only the required `into_extended_key()` method. /// /// ``` /// use bdk::bitcoin; @@ -399,8 +399,8 @@ impl From for ExtendedKey { /// /// impl DerivableKey for MyCustomKeyType { /// fn into_extended_key(self) -> Result, KeyError> { -/// let xprv = bip32::ExtendedPrivKey { -/// network: self.network, +/// let xprv = bip32::Xpriv { +/// network: self.network.into(), /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, @@ -415,7 +415,7 @@ impl From for ExtendedKey { /// /// Types that don't internally encode the [`Network`] in which they are valid need some extra /// steps to override the set of valid networks, otherwise only the network specified in the -/// [`ExtendedPrivKey`] or [`ExtendedPubKey`] will be considered valid. +/// [`Xpriv`] or [`Xpub`] will be considered valid. /// /// ``` /// use bdk::bitcoin; @@ -431,8 +431,8 @@ impl From for ExtendedKey { /// /// impl DerivableKey for MyCustomKeyType { /// fn into_extended_key(self) -> Result, KeyError> { -/// let xprv = bip32::ExtendedPrivKey { -/// network: bitcoin::Network::Bitcoin, // pick an arbitrary network here +/// let xprv = bip32::Xpriv { +/// network: bitcoin::NetworkKind::Main, // pick an arbitrary network here /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, @@ -459,8 +459,8 @@ impl From for ExtendedKey { /// ``` /// /// [`DerivationPath`]: (bip32::DerivationPath) -/// [`ExtendedPrivKey`]: (bip32::ExtendedPrivKey) -/// [`ExtendedPubKey`]: (bip32::ExtendedPubKey) +/// [`Xpriv`]: (bip32::Xpriv) +/// [`Xpub`]: (bip32::Xpub) pub trait DerivableKey: Sized { /// Consume `self` and turn it into an [`ExtendedKey`] #[cfg_attr( @@ -520,13 +520,13 @@ impl DerivableKey for ExtendedKey { } } -impl DerivableKey for bip32::ExtendedPubKey { +impl DerivableKey for bip32::Xpub { fn into_extended_key(self) -> Result, KeyError> { Ok(self.into()) } } -impl DerivableKey for bip32::ExtendedPrivKey { +impl DerivableKey for bip32::Xpriv { fn into_extended_key(self) -> Result, KeyError> { Ok(self.into()) } @@ -670,7 +670,7 @@ where { } -impl GeneratableKey for bip32::ExtendedPrivKey { +impl GeneratableKey for bip32::Xpriv { type Entropy = [u8; 32]; type Options = (); @@ -681,7 +681,7 @@ impl GeneratableKey for bip32::ExtendedPrivKey { entropy: Self::Entropy, ) -> Result, Self::Error> { // pick a arbitrary network here, but say that we support all of them - let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, entropy.as_ref())?; + let xprv = bip32::Xpriv::new_master(Network::Bitcoin, entropy.as_ref())?; Ok(GeneratedKey::new(xprv, any_network())) } } @@ -715,7 +715,7 @@ impl GeneratableKey for PrivateKey { let inner = secp256k1::SecretKey::from_slice(&entropy)?; let private_key = PrivateKey { compressed: options.compressed, - network: Network::Bitcoin, + network: NetworkKind::Main, inner, }; @@ -846,7 +846,7 @@ impl IntoDescriptorKey for DescriptorPublicKey { let networks = match self { DescriptorPublicKey::Single(_) => any_network(), DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. }) - if xkey.network == Network::Bitcoin => + if xkey.network == NetworkKind::Main => { mainnet_network() } @@ -880,11 +880,11 @@ impl IntoDescriptorKey for XOnlyPublicKey { impl IntoDescriptorKey for DescriptorSecretKey { fn into_descriptor_key(self) -> Result, KeyError> { let networks = match &self { - DescriptorSecretKey::Single(sk) if sk.key.network == Network::Bitcoin => { + DescriptorSecretKey::Single(sk) if sk.key.network == NetworkKind::Main => { mainnet_network() } DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. }) - if xkey.network == Network::Bitcoin => + if xkey.network == NetworkKind::Main => { mainnet_network() } @@ -971,7 +971,7 @@ pub mod test { #[test] fn test_keys_generate_xprv() { let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> = - bip32::ExtendedPrivKey::generate_with_entropy_default(TEST_ENTROPY).unwrap(); + bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap(); assert_eq!(generated_xprv.valid_networks, any_network()); assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q"); @@ -1001,6 +1001,6 @@ pub mod test { .unwrap(); let xprv = xkey.into_xprv(Network::Testnet).unwrap(); - assert_eq!(xprv.network, Network::Testnet); + assert_eq!(xprv.network, NetworkKind::Test); } } diff --git a/crates/bdk/src/psbt/mod.rs b/crates/bdk/src/psbt/mod.rs index 260669175..7a66989e9 100644 --- a/crates/bdk/src/psbt/mod.rs +++ b/crates/bdk/src/psbt/mod.rs @@ -9,12 +9,12 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Additional functions on the `rust-bitcoin` `PartiallySignedTransaction` structure. +//! Additional functions on the `rust-bitcoin` `Psbt` structure. use alloc::vec::Vec; -use bitcoin::psbt::PartiallySignedTransaction as Psbt; use bitcoin::Amount; use bitcoin::FeeRate; +use bitcoin::Psbt; use bitcoin::TxOut; // TODO upstream the functions here to `rust-bitcoin`? @@ -29,7 +29,7 @@ pub trait PsbtUtils { fn fee_amount(&self) -> Option; /// The transaction's fee rate. This value will only be accurate if calculated AFTER the - /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the + /// `Psbt` is finalized and all witness/signature data is added to the /// transaction. /// If the PSBT is missing a TxOut for an input returns None. fn fee_rate(&self) -> Option; @@ -54,8 +54,13 @@ impl PsbtUtils for Psbt { let utxos: Option> = (0..tx.input.len()).map(|i| self.get_utxo_for(i)).collect(); utxos.map(|inputs| { - let input_amount: u64 = inputs.iter().map(|i| i.value).sum(); - let output_amount: u64 = self.unsigned_tx.output.iter().map(|o| o.value).sum(); + let input_amount: u64 = inputs.iter().map(|i| i.value.to_sat()).sum(); + let output_amount: u64 = self + .unsigned_tx + .output + .iter() + .map(|o| o.value.to_sat()) + .sum(); input_amount .checked_sub(output_amount) .expect("input amount must be greater than output amount") @@ -64,9 +69,7 @@ impl PsbtUtils for Psbt { fn fee_rate(&self) -> Option { let fee_amount = self.fee_amount(); - fee_amount.map(|fee| { - let weight = self.clone().extract_tx().weight(); - Amount::from_sat(fee) / weight - }) + let weight = self.clone().extract_tx().ok()?.weight(); + fee_amount.map(|fee| Amount::from_sat(fee) / weight) } } diff --git a/crates/bdk/src/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs index b5bcecabb..5511c1023 100644 --- a/crates/bdk/src/wallet/coin_selection.rs +++ b/crates/bdk/src/wallet/coin_selection.rs @@ -52,9 +52,10 @@ //! .scan( //! (&mut selected_amount, &mut additional_weight), //! |(selected_amount, additional_weight), weighted_utxo| { -//! **selected_amount += weighted_utxo.utxo.txout().value; +//! **selected_amount += weighted_utxo.utxo.txout().value.to_sat(); //! **additional_weight += Weight::from_wu( -//! (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight) +//! (TxIn::default().segwit_weight().to_wu() +//! + weighted_utxo.satisfaction_weight as u64) //! as u64, //! ); //! Some(weighted_utxo.utxo) @@ -192,7 +193,7 @@ pub struct CoinSelectionResult { impl CoinSelectionResult { /// The total value of the inputs selected. pub fn selected_amount(&self) -> u64 { - self.selected.iter().map(|u| u.txout().value).sum() + self.selected.iter().map(|u| u.txout().value.to_sat()).sum() } /// The total value of the inputs selected from the local wallet. @@ -200,7 +201,7 @@ impl CoinSelectionResult { self.selected .iter() .filter_map(|u| match u { - Utxo::Local(_) => Some(u.txout().value), + Utxo::Local(_) => Some(u.txout().value.to_sat()), _ => None, }) .sum() @@ -315,7 +316,7 @@ pub fn decide_change(remaining_amount: u64, fee_rate: FeeRate, drain_script: &Sc let drain_val = remaining_amount.saturating_sub(change_fee); if drain_val.is_dust(drain_script) { - let dust_threshold = drain_script.dust_value().to_sat(); + let dust_threshold = drain_script.minimal_non_dust().to_sat(); Excess::NoChange { dust_threshold, change_fee, @@ -344,11 +345,11 @@ fn select_sorted_utxos( if must_use || **selected_amount < target_amount + **fee_amount { **fee_amount += (fee_rate * Weight::from_wu( - (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight) - as u64, + TxIn::default().segwit_weight().to_wu() + + weighted_utxo.satisfaction_weight as u64, )) .to_sat(); - **selected_amount += weighted_utxo.utxo.txout().value; + **selected_amount += weighted_utxo.utxo.txout().value.to_sat(); Some(weighted_utxo.utxo) } else { None @@ -390,10 +391,10 @@ impl OutputGroup { fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self { let fee = (fee_rate * Weight::from_wu( - (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight) as u64, + TxIn::default().segwit_weight().to_wu() + weighted_utxo.satisfaction_weight as u64, )) .to_sat(); - let effective_value = weighted_utxo.utxo.txout().value as i64 - fee as i64; + let effective_value = weighted_utxo.utxo.txout().value.to_sat() as i64 - fee as i64; OutputGroup { weighted_utxo, fee, @@ -484,7 +485,7 @@ impl CoinSelectionAlgorithm for BranchAndBoundCoinSelection { .chain(optional_utxos.iter()) .fold((0, 0), |(mut fees, mut value), utxo| { fees += utxo.fee; - value += utxo.weighted_utxo.utxo.txout().value; + value += utxo.weighted_utxo.utxo.txout().value.to_sat(); (fees, value) }); @@ -588,7 +589,7 @@ impl BranchAndBoundCoinSelection { // If we found a solution better than the previous one, or if there wasn't previous // solution, update the best solution if best_selection_value.is_none() || curr_value < best_selection_value.unwrap() { - best_selection = current_selection.clone(); + best_selection.clone_from(¤t_selection); best_selection_value = Some(curr_value); } @@ -742,7 +743,7 @@ mod test { use core::str::FromStr; use bdk_chain::ConfirmationTime; - use bitcoin::{Amount, OutPoint, ScriptBuf, TxIn, TxOut}; + use bitcoin::{Amount, ScriptBuf, TxIn, TxOut}; use super::*; use crate::types::*; @@ -770,7 +771,7 @@ mod test { utxo: Utxo::Local(LocalOutput { outpoint, txout: TxOut { - value, + value: Amount::from_sat(value), script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, @@ -834,7 +835,7 @@ mod test { )) .unwrap(), txout: TxOut { - value: rng.gen_range(0..200000000), + value: Amount::from_sat(rng.gen_range(0..200000000)), script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, @@ -865,7 +866,7 @@ mod test { )) .unwrap(), txout: TxOut { - value: utxos_value, + value: Amount::from_sat(utxos_value), script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, @@ -882,7 +883,7 @@ mod test { utxos.shuffle(&mut rng); utxos[..utxos_picked_len] .iter() - .map(|u| u.utxo.txout().value) + .map(|u| u.utxo.txout().value.to_sat()) .sum() } @@ -1071,7 +1072,11 @@ mod test { fn test_oldest_first_coin_selection_insufficient_funds_high_fees() { let utxos = get_oldest_first_test_utxos(); - let target_amount: u64 = utxos.iter().map(|wu| wu.utxo.txout().value).sum::() - 50; + let target_amount: u64 = utxos + .iter() + .map(|wu| wu.utxo.txout().value.to_sat()) + .sum::() + - 50; let drain_script = ScriptBuf::default(); OldestFirstCoinSelection @@ -1166,9 +1171,9 @@ mod test { )); // Defensive assertions, for sanity and in case someone changes the test utxos vector. - let amount: u64 = required.iter().map(|u| u.utxo.txout().value).sum(); + let amount: u64 = required.iter().map(|u| u.utxo.txout().value.to_sat()).sum(); assert_eq!(amount, 100_000); - let amount: u64 = optional.iter().map(|u| u.utxo.txout().value).sum(); + let amount: u64 = optional.iter().map(|u| u.utxo.txout().value.to_sat()).sum(); assert!(amount > 150_000); let drain_script = ScriptBuf::default(); @@ -1238,7 +1243,8 @@ mod test { assert_eq!(result.selected.len(), 1); assert_eq!(result.selected_amount(), 100_000); - let input_weight = (TxIn::default().segwit_weight() + P2WPKH_SATISFACTION_SIZE) as u64; + let input_weight = + TxIn::default().segwit_weight().to_wu() + P2WPKH_SATISFACTION_SIZE as u64; // the final fee rate should be exactly the same as the fee rate given let result_feerate = Amount::from_sat(result.fee_amount) / Weight::from_wu(input_weight); assert_eq!(result_feerate, feerate); @@ -1460,9 +1466,9 @@ mod test { let utxos = get_test_utxos(); let drain_script = ScriptBuf::default(); - let (required, optional) = utxos - .into_iter() - .partition(|u| matches!(u, WeightedUtxo { utxo, .. } if utxo.txout().value < 1000)); + let (required, optional) = utxos.into_iter().partition( + |u| matches!(u, WeightedUtxo { utxo, .. } if utxo.txout().value.to_sat() < 1000), + ); let selection = BranchAndBoundCoinSelection::default().coin_select( required, @@ -1511,7 +1517,7 @@ mod test { utxo: Utxo::Local(LocalOutput { outpoint: OutPoint::new(bitcoin::hashes::Hash::hash(txid.as_bytes()), 0), txout: TxOut { - value, + value: Amount::from_sat(value), script_pubkey: ScriptBuf::new(), }, keychain: KeychainKind::External, diff --git a/crates/bdk/src/wallet/export.rs b/crates/bdk/src/wallet/export.rs index f2d656891..08aa78dbf 100644 --- a/crates/bdk/src/wallet/export.rs +++ b/crates/bdk/src/wallet/export.rs @@ -166,7 +166,7 @@ impl FullyNodedExport { fn check_ms( terminal: &Terminal, ) -> Result<(), &'static str> { - if let Terminal::Multi(_, _) = terminal { + if let Terminal::Multi(_) = terminal { Ok(()) } else { Err("The descriptor contains operators not supported by Bitcoin Core") @@ -216,7 +216,7 @@ mod test { use bdk_chain::{BlockId, ConfirmationTime}; use bitcoin::hashes::Hash; - use bitcoin::{BlockHash, Network, Transaction}; + use bitcoin::{transaction, BlockHash, Network, Transaction}; use super::*; use crate::wallet::Wallet; @@ -230,7 +230,7 @@ mod test { let transaction = Transaction { input: vec![], output: vec![], - version: 0, + version: transaction::Version::non_standard(0), lock_time: bitcoin::absolute::LockTime::ZERO, }; wallet diff --git a/crates/bdk/src/wallet/hardwaresigner.rs b/crates/bdk/src/wallet/hardwaresigner.rs index 8b11e784a..5a210f64c 100644 --- a/crates/bdk/src/wallet/hardwaresigner.rs +++ b/crates/bdk/src/wallet/hardwaresigner.rs @@ -48,8 +48,8 @@ //! ``` use bitcoin::bip32::Fingerprint; -use bitcoin::psbt::PartiallySignedTransaction; use bitcoin::secp256k1::{All, Secp256k1}; +use bitcoin::Psbt; use hwi::error::Error; use hwi::types::{HWIChain, HWIDevice}; @@ -87,7 +87,7 @@ impl SignerCommon for HWISigner { impl TransactionSigner for HWISigner { fn sign_transaction( &self, - psbt: &mut PartiallySignedTransaction, + psbt: &mut Psbt, _sign_options: &crate::SignOptions, _secp: &crate::wallet::utils::SecpCtx, ) -> Result<(), SignerError> { diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index db252d3ae..ae4831eee 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -30,14 +30,14 @@ use bdk_chain::{ Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut, IndexedTxGraph, Persist, PersistBackend, }; +use bitcoin::constants::genesis_block; use bitcoin::secp256k1::{All, Secp256k1}; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::{ - absolute, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence, Transaction, - TxOut, Txid, Weight, Witness, + absolute, psbt, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence, + Transaction, TxOut, Txid, Witness, }; -use bitcoin::{consensus::encode::serialize, BlockHash}; -use bitcoin::{constants::genesis_block, psbt}; +use bitcoin::{consensus::encode::serialize, transaction, Amount, BlockHash, Psbt}; use core::fmt; use core::ops::Deref; use descriptor::error::Error as DescriptorError; @@ -945,11 +945,11 @@ impl Wallet { /// ``` /// /// ```rust, no_run - /// # use bitcoin::psbt::PartiallySignedTransaction; + /// # use bitcoin::Psbt; /// # use bdk::Wallet; /// # let mut wallet: Wallet<()> = todo!(); - /// # let mut psbt: PartiallySignedTransaction = todo!(); - /// let tx = &psbt.clone().extract_tx(); + /// # let mut psbt: Psbt = todo!(); + /// let tx = &psbt.clone().extract_tx().expect("tx"); /// let fee = wallet.calculate_fee(tx).expect("fee"); /// ``` /// [`insert_txout`]: Self::insert_txout @@ -976,12 +976,12 @@ impl Wallet { /// ``` /// /// ```rust, no_run - /// # use bitcoin::psbt::PartiallySignedTransaction; + /// # use bitcoin::Psbt; /// # use bdk::Wallet; /// # let mut wallet: Wallet<()> = todo!(); - /// # let mut psbt: PartiallySignedTransaction = todo!(); - /// let tx = psbt.clone().extract_tx(); - /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate"); + /// # let mut psbt: Psbt = todo!(); + /// let tx = &psbt.clone().extract_tx().expect("tx"); + /// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate"); /// ``` /// [`insert_txout`]: Self::insert_txout pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result { @@ -1007,11 +1007,11 @@ impl Wallet { /// ``` /// /// ```rust, no_run - /// # use bitcoin::psbt::PartiallySignedTransaction; + /// # use bitcoin::Psbt; /// # use bdk::Wallet; /// # let mut wallet: Wallet<()> = todo!(); - /// # let mut psbt: PartiallySignedTransaction = todo!(); - /// let tx = &psbt.clone().extract_tx(); + /// # let mut psbt: Psbt = todo!(); + /// let tx = &psbt.clone().extract_tx().expect("tx"); /// let (sent, received) = wallet.sent_and_received(tx); /// ``` pub fn sent_and_received(&self, tx: &Transaction) -> (u64, u64) { @@ -1145,7 +1145,7 @@ impl Wallet { }; let mut changeset = ChangeSet::default(); - let txid = tx.txid(); + let txid = tx.compute_txid(); changeset.append(self.indexed_graph.insert_tx(tx).into()); if let Some(anchor) = anchor { changeset.append(self.indexed_graph.insert_anchor(txid, anchor).into()); @@ -1261,7 +1261,7 @@ impl Wallet { &mut self, coin_selection: Cs, params: TxParams, - ) -> Result> + ) -> Result> where D: PersistBackend, { @@ -1455,7 +1455,7 @@ impl Wallet { }; let mut tx = Transaction { - version, + version: transaction::Version::non_standard(version), lock_time, input: vec![], output: vec![], @@ -1471,6 +1471,7 @@ impl Wallet { let recipients = params.recipients.iter().map(|(r, v)| (r, *v)); + #[allow(deprecated)] // TODO: is_provably_unspendable - needs more thought. for (index, (script_pubkey, value)) in recipients.enumerate() { if !params.allow_dust && value.is_dust(script_pubkey) @@ -1485,7 +1486,7 @@ impl Wallet { let new_out = TxOut { script_pubkey: script_pubkey.clone(), - value, + value: Amount::from_sat(value), }; tx.output.push(new_out); @@ -1495,17 +1496,6 @@ impl Wallet { fee_amount += (fee_rate * tx.weight()).to_sat(); - // Segwit transactions' header is 2WU larger than legacy txs' header, - // as they contain a witness marker (1WU) and a witness flag (1WU) (see BIP144). - // At this point we really don't know if the resulting transaction will be segwit - // or legacy, so we just add this 2WU to the fee_amount - overshooting the fee amount - // is better than undershooting it. - // If we pass a fee_amount that is slightly higher than the final fee_amount, we - // 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 * Weight::from_wu(2)).to_sat(); - if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeAllowed && internal_descriptor.is_none() { @@ -1594,7 +1584,7 @@ impl Wallet { // create drain output let drain_output = TxOut { - value: *amount, + value: Amount::from_sat(*amount), script_pubkey: drain_script, }; @@ -1640,10 +1630,10 @@ impl Wallet { /// builder.finish()? /// }; /// let _ = wallet.sign(&mut psbt, SignOptions::default())?; - /// let tx = psbt.extract_tx(); + /// let tx = psbt.clone().extract_tx().expect("tx"); /// // broadcast tx but it's taking too long to confirm so we want to bump the fee /// let mut psbt = { - /// let mut builder = wallet.build_fee_bump(tx.txid())?; + /// let mut builder = wallet.build_fee_bump(tx.compute_txid())?; /// builder /// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate")); /// builder.finish()? @@ -1681,7 +1671,9 @@ impl Wallet { .iter() .any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD) { - return Err(BuildFeeBumpError::IrreplaceableTransaction(tx.txid())); + return Err(BuildFeeBumpError::IrreplaceableTransaction( + tx.compute_txid(), + )); } let fee = self @@ -1722,7 +1714,7 @@ impl Wallet { derivation_index, confirmation_time, }), - satisfaction_weight, + satisfaction_weight: satisfaction_weight.to_wu() as usize, } } None => { @@ -1764,11 +1756,11 @@ impl Wallet { let params = TxParams { // TODO: figure out what rbf option should be? - version: Some(tx_builder::Version(tx.version)), + version: Some(tx_builder::Version(tx.version.0)), recipients: tx .output .into_iter() - .map(|txout| (txout.script_pubkey, txout.value)) + .map(|txout| (txout.script_pubkey, txout.value.to_sat())) .collect(), utxos: original_utxos, bumping_fee: Some(tx_builder::PreviousFee { @@ -1814,11 +1806,7 @@ impl Wallet { /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?; /// assert!(finalized, "we should have signed all the inputs"); /// # Ok::<(),anyhow::Error>(()) - pub fn sign( - &self, - psbt: &mut psbt::PartiallySignedTransaction, - sign_options: SignOptions, - ) -> Result { + pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result { // This adds all the PSBT metadata for the inputs, which will help us later figure out how // to derive our keys self.update_psbt_with_descriptor(psbt) @@ -1898,7 +1886,7 @@ impl Wallet { /// The [`SignOptions`] can be used to tweak the behavior of the finalizer. pub fn finalize_psbt( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, sign_options: SignOptions, ) -> Result { let chain_tip = self.chain.tip().block_id(); @@ -2057,6 +2045,7 @@ impl Wallet { self.get_descriptor_for_keychain(keychain) .max_weight_to_satisfy() .unwrap() + .to_wu() as usize }) }) .collect() @@ -2124,7 +2113,7 @@ impl Wallet { if must_only_use_confirmed_tx && !confirmation_time.is_confirmed() { return false; } - if tx.is_coin_base() { + if tx.is_coinbase() { debug_assert!( confirmation_time.is_confirmed(), "coinbase must always be confirmed" @@ -2173,11 +2162,11 @@ impl Wallet { tx: Transaction, selected: Vec, params: TxParams, - ) -> Result> + ) -> Result> where D: PersistBackend, { - let mut psbt = psbt::PartiallySignedTransaction::from_unsigned_tx(tx)?; + let mut psbt = Psbt::from_unsigned_tx(tx)?; if params.add_global_xpubs { let all_xpubs = self @@ -2233,7 +2222,7 @@ impl Wallet { let is_taproot = foreign_psbt_input .witness_utxo .as_ref() - .map(|txout| txout.script_pubkey.is_v1_p2tr()) + .map(|txout| txout.script_pubkey.is_p2tr()) .unwrap_or(false); if !is_taproot && !params.only_witness_utxo @@ -2295,10 +2284,7 @@ impl Wallet { Ok(psbt_input) } - fn update_psbt_with_descriptor( - &self, - psbt: &mut psbt::PartiallySignedTransaction, - ) -> Result<(), MiniscriptPsbtError> { + fn update_psbt_with_descriptor(&self, psbt: &mut Psbt) -> Result<(), MiniscriptPsbtError> { // We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all // the input utxos and outputs let utxos = (0..psbt.inputs.len()) @@ -2602,11 +2588,11 @@ macro_rules! doctest_wallet { .unwrap(); let address = wallet.get_address(AddressIndex::New).address; let tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 500_000, + value: Amount::from_sat(500_000), script_pubkey: address.script_pubkey(), }], }; diff --git a/crates/bdk/src/wallet/signer.rs b/crates/bdk/src/wallet/signer.rs index 38e51dfb2..492d16b21 100644 --- a/crates/bdk/src/wallet/signer.rs +++ b/crates/bdk/src/wallet/signer.rs @@ -19,13 +19,12 @@ //! # use core::str::FromStr; //! # use bitcoin::secp256k1::{Secp256k1, All}; //! # use bitcoin::*; -//! # use bitcoin::psbt; //! # use bdk::signer::*; //! # use bdk::*; //! # #[derive(Debug)] //! # struct CustomHSM; //! # impl CustomHSM { -//! # fn hsm_sign_input(&self, _psbt: &mut psbt::PartiallySignedTransaction, _input: usize) -> Result<(), SignerError> { +//! # fn hsm_sign_input(&self, _psbt: &mut Psbt, _input: usize) -> Result<(), SignerError> { //! # Ok(()) //! # } //! # fn connect() -> Self { @@ -55,7 +54,7 @@ //! impl InputSigner for CustomSigner { //! fn sign_input( //! &self, -//! psbt: &mut psbt::PartiallySignedTransaction, +//! psbt: &mut Psbt, //! input_index: usize, //! _sign_options: &SignOptions, //! _secp: &Secp256k1, @@ -87,13 +86,13 @@ use core::cmp::Ordering; use core::fmt; use core::ops::{Bound::Included, Deref}; -use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint}; +use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv}; use bitcoin::hashes::hash160; use bitcoin::secp256k1::Message; use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType}; use bitcoin::{ecdsa, psbt, sighash, taproot}; use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1}; -use bitcoin::{PrivateKey, PublicKey}; +use bitcoin::{transaction, PrivateKey, Psbt, PublicKey}; use miniscript::descriptor::{ Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, @@ -159,8 +158,12 @@ pub enum SignerError { NonStandardSighash, /// Invalid SIGHASH for the signing context in use InvalidSighash, - /// Error while computing the hash to sign - SighashError(sighash::Error), + /// Error while computing the hash to sign a P2WPKH input. + SighashP2wpkh(sighash::P2wpkhError), + /// Error while computing the hash to sign a Taproot input. + SighashTaproot(sighash::TaprootError), + /// Error while computing the hash to sign, input index error. + SighashInputsIndex(transaction::InputsIndexError), /// Miniscript PSBT error MiniscriptPsbt(MiniscriptPsbtError), /// To be used only by external libraries implementing [`InputSigner`] or @@ -169,9 +172,21 @@ pub enum SignerError { External(String), } -impl From for SignerError { - fn from(e: sighash::Error) -> Self { - SignerError::SighashError(e) +impl From for SignerError { + fn from(e: sighash::P2wpkhError) -> Self { + Self::SighashP2wpkh(e) + } +} + +impl From for SignerError { + fn from(e: sighash::TaprootError) -> Self { + Self::SighashTaproot(e) + } +} + +impl From for SignerError { + fn from(e: transaction::InputsIndexError) -> Self { + Self::SighashInputsIndex(e) } } @@ -189,7 +204,9 @@ impl fmt::Display for SignerError { Self::MissingHdKeypath => write!(f, "Missing fingerprint and derivation path"), Self::NonStandardSighash => write!(f, "The psbt contains a non standard sighash"), Self::InvalidSighash => write!(f, "Invalid SIGHASH for the signing context in use"), - Self::SighashError(err) => write!(f, "Error while computing the hash to sign: {}", err), + Self::SighashP2wpkh(err) => write!(f, "Error while computing the hash to sign for p2wpkh input: {}", err), + Self::SighashTaproot(err) => write!(f, "Error while computing the hash to sign for taproot input: {}", err), + Self::SighashInputsIndex(err) => write!(f, "Error while computing the hash to sign, inputs index: {}", err), Self::MiniscriptPsbt(err) => write!(f, "Miniscript PSBT error: {}", err), Self::External(err) => write!(f, "{}", err), } @@ -264,7 +281,7 @@ pub trait InputSigner: SignerCommon { /// Sign a single psbt input fn sign_input( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, input_index: usize, sign_options: &SignOptions, secp: &SecpCtx, @@ -279,7 +296,7 @@ pub trait TransactionSigner: SignerCommon { /// Sign all the inputs of the psbt fn sign_transaction( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, sign_options: &SignOptions, secp: &SecpCtx, ) -> Result<(), SignerError>; @@ -288,7 +305,7 @@ pub trait TransactionSigner: SignerCommon { impl TransactionSigner for T { fn sign_transaction( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, sign_options: &SignOptions, secp: &SecpCtx, ) -> Result<(), SignerError> { @@ -300,7 +317,7 @@ impl TransactionSigner for T { } } -impl SignerCommon for SignerWrapper> { +impl SignerCommon for SignerWrapper> { fn id(&self, secp: &SecpCtx) -> SignerId { SignerId::from(self.root_fingerprint(secp)) } @@ -310,10 +327,10 @@ impl SignerCommon for SignerWrapper> { } } -impl InputSigner for SignerWrapper> { +impl InputSigner for SignerWrapper> { fn sign_input( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, input_index: usize, sign_options: &SignOptions, secp: &SecpCtx, @@ -396,7 +413,7 @@ fn multikey_to_xkeys( .collect() } -impl SignerCommon for SignerWrapper> { +impl SignerCommon for SignerWrapper> { fn id(&self, secp: &SecpCtx) -> SignerId { SignerId::from(self.root_fingerprint(secp)) } @@ -406,10 +423,10 @@ impl SignerCommon for SignerWrapper> { } } -impl InputSigner for SignerWrapper> { +impl InputSigner for SignerWrapper> { fn sign_input( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, input_index: usize, sign_options: &SignOptions, secp: &SecpCtx, @@ -438,7 +455,7 @@ impl SignerCommon for SignerWrapper { impl InputSigner for SignerWrapper { fn sign_input( &self, - psbt: &mut psbt::PartiallySignedTransaction, + psbt: &mut Psbt, input_index: usize, sign_options: &SignOptions, secp: &SecpCtx, @@ -549,21 +566,24 @@ fn sign_psbt_ecdsa( secret_key: &secp256k1::SecretKey, pubkey: PublicKey, psbt_input: &mut psbt::Input, - hash: impl bitcoin::hashes::Hash + bitcoin::secp256k1::ThirtyTwoByteHash, - hash_ty: EcdsaSighashType, + hash: impl bitcoin::hashes::Hash, + sighash_type: EcdsaSighashType, secp: &SecpCtx, allow_grinding: bool, ) { - let msg = &Message::from(hash); - let sig = if allow_grinding { + let msg = &Message::from_digest(hash.to_byte_array()); + let signature = if allow_grinding { secp.sign_ecdsa_low_r(msg, secret_key) } else { secp.sign_ecdsa(msg, secret_key) }; - secp.verify_ecdsa(msg, &sig, &pubkey.inner) + secp.verify_ecdsa(msg, &signature, &pubkey.inner) .expect("invalid or corrupted ecdsa signature"); - let final_signature = ecdsa::Signature { sig, hash_ty }; + let final_signature = ecdsa::Signature { + signature, + sighash_type, + }; psbt_input.partial_sigs.insert(pubkey, final_signature); } @@ -574,10 +594,10 @@ fn sign_psbt_schnorr( leaf_hash: Option, psbt_input: &mut psbt::Input, hash: TapSighash, - hash_ty: TapSighashType, + sighash_type: TapSighashType, secp: &SecpCtx, ) { - let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap(); + let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap(); let keypair = match leaf_hash { None => keypair .tap_tweak(secp, psbt_input.tap_merkle_root) @@ -586,11 +606,14 @@ fn sign_psbt_schnorr( }; let msg = &Message::from(hash); - let sig = secp.sign_schnorr(msg, &keypair); - secp.verify_schnorr(&sig, msg, &XOnlyPublicKey::from_keypair(&keypair).0) + let signature = secp.sign_schnorr(msg, &keypair); + secp.verify_schnorr(&signature, msg, &XOnlyPublicKey::from_keypair(&keypair).0) .expect("invalid or corrupted schnorr signature"); - let final_signature = taproot::Signature { sig, hash_ty }; + let final_signature = taproot::Signature { + signature, + sighash_type, + }; if let Some(lh) = leaf_hash { psbt_input @@ -852,7 +875,7 @@ pub(crate) trait ComputeSighash { type SighashType; fn sighash( - psbt: &psbt::PartiallySignedTransaction, + psbt: &Psbt, input_index: usize, extra: Self::Extra, ) -> Result<(Self::Sighash, Self::SighashType), SignerError>; @@ -864,7 +887,7 @@ impl ComputeSighash for Legacy { type SighashType = EcdsaSighashType; fn sighash( - psbt: &psbt::PartiallySignedTransaction, + psbt: &Psbt, input_index: usize, _extra: (), ) -> Result<(Self::Sighash, Self::SighashType), SignerError> { @@ -913,7 +936,7 @@ impl ComputeSighash for Segwitv0 { type SighashType = EcdsaSighashType; fn sighash( - psbt: &psbt::PartiallySignedTransaction, + psbt: &Psbt, input_index: usize, _extra: (), ) -> Result<(Self::Sighash, Self::SighashType), SignerError> { @@ -924,7 +947,7 @@ impl ComputeSighash for Segwitv0 { let psbt_input = &psbt.inputs[input_index]; let tx_input = &psbt.unsigned_tx.input[input_index]; - let sighash = psbt_input + let sighash_type = psbt_input .sighash_type .unwrap_or_else(|| EcdsaSighashType::All.into()) .ecdsa_hash_ty() @@ -933,7 +956,7 @@ impl ComputeSighash for Segwitv0 { // Always try first with the non-witness utxo let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo { // Check the provided prev-tx - if prev_tx.txid() != tx_input.previous_output.txid { + if prev_tx.compute_txid() != tx_input.previous_output.txid { return Err(SignerError::InvalidNonWitnessUtxo); } @@ -952,40 +975,39 @@ impl ComputeSighash for Segwitv0 { }; let value = utxo.value; - let script = match psbt_input.witness_script { - Some(ref witness_script) => witness_script.clone(), + let mut sighasher = sighash::SighashCache::new(&psbt.unsigned_tx); + + let sighash = match psbt_input.witness_script { + Some(ref witness_script) => { + sighasher.p2wsh_signature_hash(input_index, witness_script, value, sighash_type)? + } None => { - if utxo.script_pubkey.is_v0_p2wpkh() { - utxo.script_pubkey - .p2wpkh_script_code() - .expect("We check above that the spk is a p2wpkh") + if utxo.script_pubkey.is_p2wpkh() { + sighasher.p2wpkh_signature_hash( + input_index, + &utxo.script_pubkey, + value, + sighash_type, + )? } else if psbt_input .redeem_script .as_ref() - .map(|s| s.is_v0_p2wpkh()) + .map(|s| s.is_p2wpkh()) .unwrap_or(false) { - psbt_input - .redeem_script - .as_ref() - .unwrap() - .p2wpkh_script_code() - .expect("We check above that the spk is a p2wpkh") + let script_pubkey = psbt_input.redeem_script.as_ref().unwrap(); + sighasher.p2wpkh_signature_hash( + input_index, + script_pubkey, + value, + sighash_type, + )? } else { return Err(SignerError::MissingWitnessScript); } } }; - - Ok(( - sighash::SighashCache::new(&psbt.unsigned_tx).segwit_signature_hash( - input_index, - &script, - value, - sighash, - )?, - sighash, - )) + Ok((sighash, sighash_type)) } } @@ -995,7 +1017,7 @@ impl ComputeSighash for Tap { type SighashType = TapSighashType; fn sighash( - psbt: &psbt::PartiallySignedTransaction, + psbt: &Psbt, input_index: usize, extra: Self::Extra, ) -> Result<(Self::Sighash, TapSighashType), SignerError> { @@ -1166,7 +1188,7 @@ mod signers_container_tests { impl TransactionSigner for DummySigner { fn sign_transaction( &self, - _psbt: &mut psbt::PartiallySignedTransaction, + _psbt: &mut Psbt, _sign_options: &SignOptions, _secp: &SecpCtx, ) -> Result<(), SignerError> { @@ -1184,8 +1206,8 @@ mod signers_container_tests { ) -> (DescriptorKey, DescriptorKey, Fingerprint) { let secp: Secp256k1 = Secp256k1::new(); let path = bip32::DerivationPath::from_str(PATH).unwrap(); - let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap(); - let tpub = bip32::ExtendedPubKey::from_priv(&secp, &tprv); + let tprv = bip32::Xpriv::from_str(tprv).unwrap(); + let tpub = bip32::Xpub::from_priv(&secp, &tprv); let fingerprint = tprv.fingerprint(&secp); let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap(); let pubkey = (tpub, path).into_descriptor_key().unwrap(); diff --git a/crates/bdk/src/wallet/tx_builder.rs b/crates/bdk/src/wallet/tx_builder.rs index 74bc081c5..1f9b3fe2e 100644 --- a/crates/bdk/src/wallet/tx_builder.rs +++ b/crates/bdk/src/wallet/tx_builder.rs @@ -46,7 +46,7 @@ use core::fmt; use core::marker::PhantomData; use bdk_chain::PersistBackend; -use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt}; +use bitcoin::psbt::{self, Psbt}; use bitcoin::script::PushBytes; use bitcoin::{absolute, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid}; @@ -316,7 +316,7 @@ impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> { let descriptor = wallet.get_descriptor_for_keychain(utxo.keychain); let satisfaction_weight = descriptor.max_weight_to_satisfy().unwrap(); self.params.utxos.push(WeightedUtxo { - satisfaction_weight, + satisfaction_weight: satisfaction_weight.to_wu() as usize, utxo: Utxo::Local(utxo), }); } @@ -404,9 +404,9 @@ impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> { if psbt_input.witness_utxo.is_none() { match psbt_input.non_witness_utxo.as_ref() { Some(tx) => { - if tx.txid() != outpoint.txid { + if tx.compute_txid() != outpoint.txid { return Err(AddForeignUtxoError::InvalidTxid { - input_txid: tx.txid(), + input_txid: tx.compute_txid(), foreign_utxo: outpoint, }); } @@ -927,7 +927,8 @@ mod test { use bdk_chain::ConfirmationTime; use bitcoin::consensus::deserialize; - use bitcoin::hashes::hex::FromHex; + use bitcoin::hex::FromHex; + use bitcoin::TxOut; use super::*; @@ -998,7 +999,7 @@ mod test { .unwrap() ); - assert_eq!(tx.output[0].value, 800); + assert_eq!(tx.output[0].value.to_sat(), 800); assert_eq!(tx.output[1].script_pubkey, ScriptBuf::from(vec![0xAA])); assert_eq!( tx.output[2].script_pubkey, @@ -1015,7 +1016,7 @@ mod test { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), vout: 0, }, - txout: Default::default(), + txout: TxOut::NULL, keychain: KeychainKind::External, is_spent: false, confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 }, @@ -1026,7 +1027,7 @@ mod test { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), vout: 1, }, - txout: Default::default(), + txout: TxOut::NULL, keychain: KeychainKind::Internal, is_spent: false, confirmation_time: ConfirmationTime::Confirmed { diff --git a/crates/bdk/src/wallet/utils.rs b/crates/bdk/src/wallet/utils.rs index 71e24950b..402361134 100644 --- a/crates/bdk/src/wallet/utils.rs +++ b/crates/bdk/src/wallet/utils.rs @@ -10,7 +10,7 @@ // licenses. use bitcoin::secp256k1::{All, Secp256k1}; -use bitcoin::{absolute, Script, Sequence}; +use bitcoin::{absolute, relative, Script, Sequence}; use miniscript::{MiniscriptKey, Satisfier, ToPublicKey}; @@ -26,7 +26,7 @@ pub trait IsDust { impl IsDust for u64 { fn is_dust(&self, script: &Script) -> bool { - *self < script.dust_value().to_sat() + *self < script.minimal_non_dust().to_sat() } } @@ -95,7 +95,7 @@ impl Older { } impl Satisfier for Older { - fn check_older(&self, n: Sequence) -> bool { + fn check_older(&self, n: relative::LockTime) -> bool { if let Some(current_height) = self.current_height { // TODO: test >= / > current_height @@ -138,7 +138,7 @@ mod test { .require_network(Network::Bitcoin) .unwrap() .script_pubkey(); - assert!(script_p2wpkh.is_v0_p2wpkh()); + assert!(script_p2wpkh.is_p2wpkh()); assert!(293.is_dust(&script_p2wpkh)); assert!(!294.is_dust(&script_p2wpkh)); } diff --git a/crates/bdk/tests/common.rs b/crates/bdk/tests/common.rs index b4012286b..562e7b17e 100644 --- a/crates/bdk/tests/common.rs +++ b/crates/bdk/tests/common.rs @@ -4,7 +4,10 @@ use bdk::{wallet::AddressIndex, KeychainKind, LocalOutput, Wallet}; use bdk_chain::indexed_tx_graph::Indexer; use bdk_chain::{BlockId, ConfirmationTime}; use bitcoin::hashes::Hash; -use bitcoin::{Address, BlockHash, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut, Txid}; +use bitcoin::{ + transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut, + Txid, +}; use std::str::FromStr; // Return a fake wallet that appears to be funded for testing. @@ -24,7 +27,7 @@ pub fn get_funded_wallet_with_change( .unwrap(); let tx0 = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: bitcoin::absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { @@ -36,17 +39,17 @@ pub fn get_funded_wallet_with_change( witness: Default::default(), }], output: vec![TxOut { - value: 76_000, + value: Amount::from_sat(76_000), script_pubkey: change_address.script_pubkey(), }], }; let tx1 = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: bitcoin::absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { - txid: tx0.txid(), + txid: tx0.compute_txid(), vout: 0, }, script_sig: Default::default(), @@ -55,11 +58,11 @@ pub fn get_funded_wallet_with_change( }], output: vec![ TxOut { - value: 50_000, + value: Amount::from_sat(50_000), script_pubkey: change_address.script_pubkey(), }, TxOut { - value: 25_000, + value: Amount::from_sat(25_000), script_pubkey: sendto_address.script_pubkey(), }, ], @@ -96,7 +99,7 @@ pub fn get_funded_wallet_with_change( ) .unwrap(); - (wallet, tx1.txid()) + (wallet, tx1.compute_txid()) } // Return a fake wallet that appears to be funded for testing. diff --git a/crates/bdk/tests/psbt.rs b/crates/bdk/tests/psbt.rs index e7dd64426..24dc38c1f 100644 --- a/crates/bdk/tests/psbt.rs +++ b/crates/bdk/tests/psbt.rs @@ -1,9 +1,7 @@ -use bdk::bitcoin::FeeRate; -use bdk::bitcoin::TxIn; +use bdk::bitcoin::{Amount, FeeRate, Psbt, TxIn}; use bdk::wallet::AddressIndex; use bdk::wallet::AddressIndex::New; use bdk::{psbt, SignOptions}; -use bitcoin::psbt::PartiallySignedTransaction as Psbt; use core::str::FromStr; mod common; use common::*; @@ -163,7 +161,7 @@ fn test_psbt_multiple_internalkey_signers() { use bdk::signer::{SignerContext, SignerOrdering, SignerWrapper}; use bdk::KeychainKind; use bitcoin::key::TapTweak; - use bitcoin::secp256k1::{schnorr, KeyPair, Message, Secp256k1, XOnlyPublicKey}; + use bitcoin::secp256k1::{schnorr, Keypair, Message, Secp256k1, XOnlyPublicKey}; use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType}; use bitcoin::{PrivateKey, TxOut}; use std::sync::Arc; @@ -172,7 +170,7 @@ fn test_psbt_multiple_internalkey_signers() { let wif = "cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG"; let desc = format!("tr({})", wif); let prv = PrivateKey::from_wif(wif).unwrap(); - let keypair = KeyPair::from_secret_key(&secp, &prv.inner); + let keypair = Keypair::from_secret_key(&secp, &prv.inner); let (mut wallet, _) = get_funded_wallet(&desc); let to_spend = wallet.get_balance().total(); @@ -205,7 +203,7 @@ fn test_psbt_multiple_internalkey_signers() { // the prevout we're spending let prevouts = &[TxOut { script_pubkey: send_to.script_pubkey(), - value: to_spend, + value: Amount::from_sat(to_spend), }]; let prevouts = Prevouts::All(prevouts); let input_index = 0; diff --git a/crates/bdk/tests/wallet.rs b/crates/bdk/tests/wallet.rs index 49c1bc9c3..8a656883d 100644 --- a/crates/bdk/tests/wallet.rs +++ b/crates/bdk/tests/wallet.rs @@ -18,8 +18,8 @@ use bitcoin::script::PushBytesBuf; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::taproot::TapNodeHash; use bitcoin::{ - absolute, Address, Amount, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, Sequence, - Transaction, TxIn, TxOut, Txid, Weight, + absolute, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, + Sequence, Transaction, TxIn, TxOut, Txid, Weight, }; mod common; @@ -27,19 +27,19 @@ use common::*; fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) -> OutPoint { let tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { script_pubkey: wallet.get_address(LastUnused).script_pubkey(), - value, + value: Amount::from_sat(value), }], }; wallet.insert_tx(tx.clone(), height).unwrap(); OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, } } @@ -208,7 +208,12 @@ fn test_get_funded_wallet_sent_and_received() { let mut tx_amounts: Vec<(Txid, (u64, u64))> = wallet .transactions() - .map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node))) + .map(|ct| { + ( + ct.tx_node.txid, + wallet.sent_and_received(ct.tx_node.tx.as_ref()), + ) + }) .collect(); tx_amounts.sort_by(|a1, a2| a1.0.cmp(&a2.0)); @@ -265,10 +270,10 @@ fn test_list_output() { assert_eq!(txos.len(), 2); for (op, txo) in txos { if op.txid == txid { - assert_eq!(txo.txout.value, 50_000); + assert_eq!(txo.txout.value.to_sat(), 50_000); assert!(!txo.is_spent); } else { - assert_eq!(txo.txout.value, 76_000); + assert_eq!(txo.txout.value.to_sat(), 76_000); assert!(txo.is_spent); } } @@ -278,7 +283,7 @@ macro_rules! assert_fee_rate { ($psbt:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({ let psbt = $psbt.clone(); #[allow(unused_mut)] - let mut tx = $psbt.clone().extract_tx(); + let mut tx = $psbt.clone().extract_tx().expect("failed to extract tx"); $( $( $add_signature )* for txin in &mut tx.input { @@ -297,12 +302,12 @@ macro_rules! assert_fee_rate { let fee_amount = psbt .inputs .iter() - .fold(0, |acc, i| acc + i.witness_utxo.as_ref().unwrap().value) + .fold(0, |acc, i| acc + i.witness_utxo.as_ref().unwrap().value.to_sat()) - psbt .unsigned_tx .output .iter() - .fold(0, |acc, o| acc + o.value); + .fold(0, |acc, o| acc + o.value.to_sat()); assert_eq!(fee_amount, $fees); @@ -383,7 +388,7 @@ fn test_create_tx_custom_version() { .version(42); let psbt = builder.finish().unwrap(); - assert_eq!(psbt.unsigned_tx.version, 42); + assert_eq!(psbt.unsigned_tx.version.0, 42); } #[test] @@ -570,7 +575,7 @@ fn test_create_tx_change_policy_no_internal() { macro_rules! check_fee { ($wallet:expr, $psbt: expr) => {{ - let tx = $psbt.clone().extract_tx(); + let tx = $psbt.clone().extract_tx().expect("failed to extract tx"); let tx_fee = $wallet.calculate_fee(&tx).ok(); assert_eq!(tx_fee, $psbt.fee_amount()); tx_fee @@ -587,7 +592,10 @@ fn test_create_tx_drain_wallet_and_drain_to() { let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); + assert_eq!( + psbt.unsigned_tx.output[0].value.to_sat(), + 50_000 - fee.unwrap_or(0) + ); } #[test] @@ -615,8 +623,8 @@ fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() { .iter() .find(|x| x.script_pubkey == drain_addr.script_pubkey()) .unwrap(); - assert_eq!(main_output.value, 20_000,); - assert_eq!(drain_output.value, 30_000 - fee.unwrap_or(0)); + assert_eq!(main_output.value.to_sat(), 20_000,); + assert_eq!(drain_output.value.to_sat(), 30_000 - fee.unwrap_or(0)); } #[test] @@ -633,7 +641,10 @@ fn test_create_tx_drain_to_and_utxos() { let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); + assert_eq!( + psbt.unsigned_tx.output[0].value.to_sat(), + 50_000 - fee.unwrap_or(0) + ); } #[test] @@ -686,7 +697,10 @@ fn test_create_tx_absolute_fee() { assert_eq!(fee.unwrap_or(0), 100); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); + assert_eq!( + psbt.unsigned_tx.output[0].value.to_sat(), + 50_000 - fee.unwrap_or(0) + ); } #[test] @@ -703,7 +717,10 @@ fn test_create_tx_absolute_zero_fee() { assert_eq!(fee.unwrap_or(0), 0); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); + assert_eq!( + psbt.unsigned_tx.output[0].value.to_sat(), + 50_000 - fee.unwrap_or(0) + ); } #[test] @@ -733,8 +750,11 @@ fn test_create_tx_add_change() { let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 2); - assert_eq!(psbt.unsigned_tx.output[0].value, 25_000); - assert_eq!(psbt.unsigned_tx.output[1].value, 25_000 - fee.unwrap_or(0)); + assert_eq!(psbt.unsigned_tx.output[0].value.to_sat(), 25_000); + assert_eq!( + psbt.unsigned_tx.output[1].value.to_sat(), + 25_000 - fee.unwrap_or(0) + ); } #[test] @@ -747,7 +767,7 @@ fn test_create_tx_skip_change_dust() { let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!(psbt.unsigned_tx.output[0].value, 49_800); + assert_eq!(psbt.unsigned_tx.output[0].value.to_sat(), 49_800); assert_eq!(fee.unwrap_or(0), 200); } @@ -778,9 +798,12 @@ fn test_create_tx_ordering_respected() { let fee = check_fee!(wallet, psbt); assert_eq!(psbt.unsigned_tx.output.len(), 3); - assert_eq!(psbt.unsigned_tx.output[0].value, 10_000 - fee.unwrap_or(0)); - assert_eq!(psbt.unsigned_tx.output[1].value, 10_000); - assert_eq!(psbt.unsigned_tx.output[2].value, 30_000); + assert_eq!( + psbt.unsigned_tx.output[0].value.to_sat(), + 10_000 - fee.unwrap_or(0) + ); + assert_eq!(psbt.unsigned_tx.output[1].value.to_sat(), 10_000); + assert_eq!(psbt.unsigned_tx.output[2].value.to_sat(), 30_000); } #[test] @@ -856,7 +879,7 @@ fn test_create_tx_output_hd_keypaths() { #[test] fn test_create_tx_set_redeem_script_p2sh() { - use bitcoin::hashes::hex::FromHex; + use bitcoin::hex::FromHex; let (mut wallet, _) = get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); @@ -879,7 +902,7 @@ fn test_create_tx_set_redeem_script_p2sh() { #[test] fn test_create_tx_set_witness_script_p2wsh() { - use bitcoin::hashes::hex::FromHex; + use bitcoin::hex::FromHex; let (mut wallet, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); @@ -914,7 +937,7 @@ fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() { ) .unwrap(); - assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_v0_p2wsh())); + assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_p2wsh())); assert_eq!(psbt.inputs[0].witness_script, Some(script)); } @@ -978,10 +1001,10 @@ fn test_create_tx_add_utxo() { let small_output_tx = Transaction { input: vec![], output: vec![TxOut { - value: 25_000, + value: Amount::from_sat(25_000), script_pubkey: wallet.get_address(New).address.script_pubkey(), }], - version: 0, + version: transaction::Version::non_standard(0), lock_time: absolute::LockTime::ZERO, }; wallet @@ -998,12 +1021,13 @@ fn test_create_tx_add_utxo() { builder .add_recipient(addr.script_pubkey(), 30_000) .add_utxo(OutPoint { - txid: small_output_tx.txid(), + txid: small_output_tx.compute_txid(), vout: 0, }) .unwrap(); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); assert_eq!( psbt.unsigned_tx.input.len(), @@ -1023,10 +1047,10 @@ fn test_create_tx_manually_selected_insufficient() { let small_output_tx = Transaction { input: vec![], output: vec![TxOut { - value: 25_000, + value: Amount::from_sat(25_000), script_pubkey: wallet.get_address(New).address.script_pubkey(), }], - version: 0, + version: transaction::Version::non_standard(0), lock_time: absolute::LockTime::ZERO, }; @@ -1044,7 +1068,7 @@ fn test_create_tx_manually_selected_insufficient() { builder .add_recipient(addr.script_pubkey(), 30_000) .add_utxo(OutPoint { - txid: small_output_tx.txid(), + txid: small_output_tx.compute_txid(), vout: 0, }) .unwrap() @@ -1071,11 +1095,11 @@ fn test_create_tx_policy_path_no_csv() { let mut wallet = Wallet::new_no_persist(descriptors, None, Network::Regtest).unwrap(); let tx = Transaction { - version: 0, + version: transaction::Version::non_standard(0), lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 50_000, + value: Amount::from_sat(50_000), script_pubkey: wallet.get_address(New).script_pubkey(), }], }; @@ -1145,7 +1169,6 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() { #[test] fn test_create_tx_global_xpubs_with_origin() { use bitcoin::bip32; - use bitcoin::hashes::hex::FromHex; let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.get_address(New); @@ -1155,7 +1178,7 @@ fn test_create_tx_global_xpubs_with_origin() { .add_global_xpubs(); let psbt = builder.finish().unwrap(); - let key = bip32::ExtendedPubKey::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap(); + let key = bip32::Xpub::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("73756c7f").unwrap(); let path = bip32::DerivationPath::from_str("m/48'/0'/0'/2'").unwrap(); @@ -1187,12 +1210,17 @@ fn test_add_foreign_utxo() { builder .add_recipient(addr.script_pubkey(), 60_000) .only_witness_utxo() - .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) + .add_foreign_utxo( + utxo.outpoint, + psbt_input, + foreign_utxo_satisfaction.to_wu() as usize, + ) .unwrap(); let mut psbt = builder.finish().unwrap(); wallet1.insert_txout(utxo.outpoint, utxo.txout); let fee = check_fee!(wallet1, psbt); - let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); assert_eq!( sent_received.0 - sent_received.1, @@ -1237,7 +1265,7 @@ fn test_add_foreign_utxo() { #[test] #[should_panic( - expected = "MissingTxOut([OutPoint { txid: 0x21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])" + expected = "MissingTxOut([OutPoint { txid: 21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])" )] fn test_calculate_fee_with_missing_foreign_utxo() { let (mut wallet1, _) = get_funded_wallet(get_test_wpkh()); @@ -1262,10 +1290,14 @@ fn test_calculate_fee_with_missing_foreign_utxo() { builder .add_recipient(addr.script_pubkey(), 60_000) .only_witness_utxo() - .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) + .add_foreign_utxo( + utxo.outpoint, + psbt_input, + foreign_utxo_satisfaction.to_wu() as usize, + ) .unwrap(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); wallet1.calculate_fee(&tx).unwrap(); } @@ -1279,8 +1311,11 @@ fn test_add_foreign_utxo_invalid_psbt_input() { .unwrap(); let mut builder = wallet.build_tx(); - let result = - builder.add_foreign_utxo(outpoint, psbt::Input::default(), foreign_utxo_satisfaction); + let result = builder.add_foreign_utxo( + outpoint, + psbt::Input::default(), + foreign_utxo_satisfaction.to_wu() as usize, + ); assert!(matches!(result, Err(AddForeignUtxoError::MissingUtxo))); } @@ -1308,7 +1343,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { non_witness_utxo: Some(tx1.as_ref().clone()), ..Default::default() }, - satisfaction_weight + satisfaction_weight.to_wu() as usize ) .is_err(), "should fail when outpoint doesn't match psbt_input" @@ -1321,7 +1356,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { non_witness_utxo: Some(tx2.as_ref().clone()), ..Default::default() }, - satisfaction_weight + satisfaction_weight.to_wu() as usize ) .is_ok(), "should be ok when outpoint does match psbt_input" @@ -1353,7 +1388,11 @@ fn test_add_foreign_utxo_only_witness_utxo() { ..Default::default() }; builder - .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight) + .add_foreign_utxo( + utxo2.outpoint, + psbt_input, + satisfaction_weight.to_wu() as usize, + ) .unwrap(); assert!( builder.finish().is_err(), @@ -1369,7 +1408,11 @@ fn test_add_foreign_utxo_only_witness_utxo() { }; builder .only_witness_utxo() - .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight) + .add_foreign_utxo( + utxo2.outpoint, + psbt_input, + satisfaction_weight.to_wu() as usize, + ) .unwrap(); assert!( builder.finish().is_ok(), @@ -1385,7 +1428,11 @@ fn test_add_foreign_utxo_only_witness_utxo() { ..Default::default() }; builder - .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight) + .add_foreign_utxo( + utxo2.outpoint, + psbt_input, + satisfaction_weight.to_wu() as usize, + ) .unwrap(); assert!( builder.finish().is_ok(), @@ -1421,7 +1468,6 @@ fn test_create_tx_global_xpubs_origin_missing() { #[test] fn test_create_tx_global_xpubs_master_without_origin() { use bitcoin::bip32; - use bitcoin::hashes::hex::FromHex; let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); let addr = wallet.get_address(New); @@ -1431,7 +1477,7 @@ fn test_create_tx_global_xpubs_master_without_origin() { .add_global_xpubs(); let psbt = builder.finish().unwrap(); - let key = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); + let key = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("997a323b").unwrap(); assert_eq!(psbt.xpub.len(), 1); @@ -1450,8 +1496,8 @@ fn test_bump_fee_irreplaceable_tx() { builder.add_recipient(addr.script_pubkey(), 25_000); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1467,8 +1513,8 @@ fn test_bump_fee_confirmed_tx() { builder.add_recipient(addr.script_pubkey(), 25_000); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx( @@ -1494,8 +1540,8 @@ fn test_bump_fee_low_fee_rate() { let psbt = builder.finish().unwrap(); let feerate = psbt.fee_rate().unwrap(); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1527,8 +1573,8 @@ fn test_bump_fee_low_abs() { .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1550,8 +1596,8 @@ fn test_bump_fee_zero_abs() { .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1572,11 +1618,12 @@ fn test_bump_fee_reduce_change() { .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1585,7 +1632,8 @@ fn test_bump_fee_reduce_change() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(feerate).enable_rbf(); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0); @@ -1603,14 +1651,15 @@ fn test_bump_fee_reduce_change() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 25_000 + Amount::from_sat(25_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -1620,7 +1669,8 @@ fn test_bump_fee_reduce_change() { builder.fee_absolute(200); builder.enable_rbf(); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0); @@ -1643,14 +1693,15 @@ fn test_bump_fee_reduce_change() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 25_000 + Amount::from_sat(25_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -1669,10 +1720,10 @@ fn test_bump_fee_reduce_single_recipient() { .drain_wallet() .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.clone().extract_tx(); + let tx = psbt.clone().extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let original_fee = check_fee!(wallet, psbt); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1684,7 +1735,8 @@ fn test_bump_fee_reduce_single_recipient() { .allow_shrinking(addr.script_pubkey()) .unwrap(); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0); @@ -1692,7 +1744,10 @@ fn test_bump_fee_reduce_single_recipient() { let tx = &psbt.unsigned_tx; assert_eq!(tx.output.len(), 1); - assert_eq!(tx.output[0].value + fee.unwrap_or(0), sent_received.0); + assert_eq!( + tx.output[0].value.to_sat() + fee.unwrap_or(0), + sent_received.0 + ); assert_fee_rate!(psbt, fee.unwrap_or(0), feerate, @add_signature); } @@ -1710,9 +1765,9 @@ fn test_bump_fee_absolute_reduce_single_recipient() { .enable_rbf(); let psbt = builder.finish().unwrap(); let original_fee = check_fee!(wallet, psbt); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1731,7 +1786,10 @@ fn test_bump_fee_absolute_reduce_single_recipient() { assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0)); assert_eq!(tx.output.len(), 1); - assert_eq!(tx.output[0].value + fee.unwrap_or(0), sent_received.0); + assert_eq!( + tx.output[0].value.to_sat() + fee.unwrap_or(0), + sent_received.0 + ); assert_eq!(fee.unwrap_or(0), 300); } @@ -1741,11 +1799,11 @@ fn test_bump_fee_drain_wallet() { let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); // receive an extra tx so that our wallet has two utxos. let tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 25_000, + value: Amount::from_sat(25_000), script_pubkey: wallet.get_address(New).script_pubkey(), }], }; @@ -1766,17 +1824,17 @@ fn test_bump_fee_drain_wallet() { builder .drain_to(addr.script_pubkey()) .add_utxo(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }) .unwrap() .manually_selected_only() .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1791,7 +1849,7 @@ fn test_bump_fee_drain_wallet() { .unwrap() .fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.extract_tx()); + let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx")); assert_eq!(sent_received.0, 75_000); } @@ -1806,12 +1864,12 @@ fn test_bump_fee_remove_output_manually_selected_only() { // existing output. In other words, bump_fee + manually_selected_only is always an error // unless you've also set "allow_shrinking" OR there is a change output. let init_tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { script_pubkey: wallet.get_address(New).script_pubkey(), - value: 25_000, + value: Amount::from_sat(25_000), }], }; wallet @@ -1827,7 +1885,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { ) .unwrap(); let outpoint = OutPoint { - txid: init_tx.txid(), + txid: init_tx.compute_txid(), vout: 0, }; let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") @@ -1841,9 +1899,9 @@ fn test_bump_fee_remove_output_manually_selected_only() { .manually_selected_only() .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1860,12 +1918,12 @@ fn test_bump_fee_remove_output_manually_selected_only() { fn test_bump_fee_add_input() { let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let init_tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { script_pubkey: wallet.get_address(New).script_pubkey(), - value: 25_000, + value: Amount::from_sat(25_000), }], }; let pos = wallet @@ -1885,9 +1943,9 @@ fn test_bump_fee_add_input() { .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); let original_details = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1895,7 +1953,8 @@ fn test_bump_fee_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50)); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_details.0 + 25_000); assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000); @@ -1909,14 +1968,15 @@ fn test_bump_fee_add_input() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 45_000 + Amount::from_sat(45_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -1935,9 +1995,9 @@ fn test_bump_fee_absolute_add_input() { .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1945,7 +2005,8 @@ fn test_bump_fee_absolute_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(6_000); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0 + 25_000); @@ -1960,14 +2021,15 @@ fn test_bump_fee_absolute_add_input() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 45_000 + Amount::from_sat(45_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -1991,11 +2053,12 @@ fn test_bump_fee_no_change_add_input_and_change() { .manually_selected_only() .enable_rbf(); let psbt = builder.finish().unwrap(); - let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); - let tx = psbt.extract_tx(); - let txid = tx.txid(); + let tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -2005,7 +2068,8 @@ fn test_bump_fee_no_change_add_input_and_change() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50)); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); let original_send_all_amount = original_sent_received.0 - original_fee.unwrap_or(0); @@ -2024,14 +2088,15 @@ fn test_bump_fee_no_change_add_input_and_change() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - original_send_all_amount + Amount::from_sat(original_send_all_amount) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), 75_000 - original_send_all_amount - fee.unwrap_or(0) ); @@ -2050,17 +2115,18 @@ fn test_bump_fee_add_input_change_dust() { .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let original_fee = check_fee!(wallet, psbt); - let mut tx = psbt.extract_tx(); + let mut tx = psbt.extract_tx().expect("failed to extract tx"); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // to get realistic weight } let original_tx_weight = tx.weight(); assert_eq!(tx.input.len(), 1); assert_eq!(tx.output.len(), 2); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -2082,7 +2148,8 @@ fn test_bump_fee_add_input_change_dust() { let fee_abs = 50_000 + 25_000 - 45_000 - 10; builder.fee_rate(Amount::from_sat(fee_abs) / new_tx_weight); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(original_sent_received.1, 5_000 - original_fee.unwrap_or(0)); @@ -2100,7 +2167,7 @@ fn test_bump_fee_add_input_change_dust() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 45_000 + Amount::from_sat(45_000) ); assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(140), @dust_change, @add_signature); @@ -2119,9 +2186,9 @@ fn test_bump_fee_force_add_input() { .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let mut tx = psbt.extract_tx(); + let mut tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } @@ -2136,7 +2203,8 @@ fn test_bump_fee_force_add_input() { .unwrap() .fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0 + 25_000); @@ -2151,14 +2219,15 @@ fn test_bump_fee_force_add_input() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 45_000 + Amount::from_sat(45_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -2178,9 +2247,9 @@ fn test_bump_fee_absolute_force_add_input() { .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); let psbt = builder.finish().unwrap(); - let mut tx = psbt.extract_tx(); + let mut tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); // skip saving the new utxos, we know they can't be used anyways for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature @@ -2194,7 +2263,8 @@ fn test_bump_fee_absolute_force_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.add_utxo(incoming_op).unwrap().fee_absolute(250); let psbt = builder.finish().unwrap(); - let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); let fee = check_fee!(wallet, psbt); assert_eq!(sent_received.0, original_sent_received.0 + 25_000); @@ -2209,14 +2279,15 @@ fn test_bump_fee_absolute_force_add_input() { .find(|txout| txout.script_pubkey == addr.script_pubkey()) .unwrap() .value, - 45_000 + Amount::from_sat(45_000) ); assert_eq!( tx.output .iter() .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() - .value, + .value + .to_sat(), sent_received.1 ); @@ -2249,8 +2320,8 @@ fn test_bump_fee_unconfirmed_inputs_only() { 25_000, ConfirmationTime::Unconfirmed { last_seen: 0 }, ); - let mut tx = psbt.extract_tx(); - let txid = tx.txid(); + let mut tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } @@ -2282,8 +2353,8 @@ fn test_bump_fee_unconfirmed_input() { .drain_to(addr.script_pubkey()) .enable_rbf(); let psbt = builder.finish().unwrap(); - let mut tx = psbt.extract_tx(); - let txid = tx.txid(); + let mut tx = psbt.extract_tx().expect("failed to extract tx"); + let txid = tx.compute_txid(); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } @@ -2341,7 +2412,7 @@ fn test_sign_single_xprv() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2356,7 +2427,7 @@ fn test_sign_single_xprv_with_master_fingerprint_and_path() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2371,7 +2442,7 @@ fn test_sign_single_xprv_bip44_path() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2386,7 +2457,7 @@ fn test_sign_single_xprv_sh_wpkh() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2402,7 +2473,7 @@ fn test_sign_single_wif() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2420,7 +2491,7 @@ fn test_sign_single_xprv_no_hd_keypaths() { let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!(extracted.input[0].witness.len(), 2); } @@ -2458,7 +2529,7 @@ fn test_signing_only_one_of_multiple_inputs() { // add another input to the psbt that is at least passable. let dud_input = bitcoin::psbt::Input { witness_utxo: Some(TxOut { - value: 100_000, + value: Amount::from_sat(100_000), script_pubkey: miniscript::Descriptor::::from_str( "wpkh(025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357)", ) @@ -2591,7 +2662,7 @@ fn test_sign_nonstandard_sighash() { "Should finalize the input since we can produce signatures" ); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!( *extracted.input[0].witness.to_vec()[0].last().unwrap(), sighash.to_u32() as u8, @@ -2762,7 +2833,7 @@ fn test_sending_to_bip350_bech32m_address() { #[test] fn test_get_address() { use bdk::descriptor::template::Bip84; - let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let mut wallet = Wallet::new_no_persist( Bip84(key, KeychainKind::External), Some(Bip84(key, KeychainKind::Internal)), @@ -2813,7 +2884,7 @@ fn test_get_address_no_reuse_single_descriptor() { use bdk::descriptor::template::Bip84; use std::collections::HashSet; - let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); + let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); let mut wallet = Wallet::new_no_persist(Bip84(key, KeychainKind::External), None, Network::Regtest).unwrap(); @@ -2954,7 +3025,7 @@ fn test_taproot_psbt_populate_tap_key_origins_repeated_key() { #[test] fn test_taproot_psbt_input_tap_tree() { - use bitcoin::hashes::hex::FromHex; + use bitcoin::hex::FromHex; use bitcoin::taproot; let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree()); @@ -3085,10 +3156,15 @@ fn test_taproot_foreign_utxo() { let mut builder = wallet1.build_tx(); builder .add_recipient(addr.script_pubkey(), 60_000) - .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) + .add_foreign_utxo( + utxo.outpoint, + psbt_input, + foreign_utxo_satisfaction.to_wu() as usize, + ) .unwrap(); let psbt = builder.finish().unwrap(); - let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx()); + let sent_received = + wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet1.insert_txout(utxo.outpoint, utxo.txout); let fee = check_fee!(wallet1, psbt); @@ -3396,7 +3472,7 @@ fn test_taproot_sign_non_default_sighash() { "Should finalize the input since we can produce signatures" ); - let extracted = psbt.extract_tx(); + let extracted = psbt.extract_tx().expect("failed to extract tx"); assert_eq!( *extracted.input[0].witness.to_vec()[0].last().unwrap(), sighash as u8, @@ -3417,14 +3493,14 @@ fn test_spend_coinbase() { }) .unwrap(); let coinbase_tx = Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() }], output: vec![TxOut { - value: 25_000, + value: Amount::from_sat(25_000), script_pubkey: wallet.get_address(New).address.script_pubkey(), }], }; @@ -3581,7 +3657,10 @@ fn test_fee_rate_sign_no_grinding_high_r() { .unwrap(); // We only have one key in the partial_sigs map, this is a trick to retrieve it let key = psbt.inputs[0].partial_sigs.keys().next().unwrap(); - sig_len = psbt.inputs[0].partial_sigs[key].sig.serialize_der().len(); + sig_len = psbt.inputs[0].partial_sigs[key] + .signature + .serialize_der() + .len(); } // Actually finalizing the transaction... wallet @@ -3627,7 +3706,10 @@ fn test_fee_rate_sign_grinding_low_r() { .unwrap(); let key = psbt.inputs[0].partial_sigs.keys().next().unwrap(); - let sig_len = psbt.inputs[0].partial_sigs[key].sig.serialize_der().len(); + let sig_len = psbt.inputs[0].partial_sigs[key] + .signature + .serialize_der() + .len(); assert_eq!(sig_len, 70); assert_fee_rate!(psbt, fee.unwrap_or(0), fee_rate); } @@ -3686,7 +3768,7 @@ fn test_tx_cancellation() { .unwrap(); assert_eq!(change_derivation_2, (KeychainKind::Internal, 1)); - wallet.cancel_tx(&psbt1.extract_tx()); + wallet.cancel_tx(&psbt1.extract_tx().expect("failed to extract tx")); let psbt3 = new_tx!(wallet); let change_derivation_3 = psbt3 @@ -3706,7 +3788,7 @@ fn test_tx_cancellation() { .unwrap(); assert_eq!(change_derivation_3, (KeychainKind::Internal, 2)); - wallet.cancel_tx(&psbt3.extract_tx()); + wallet.cancel_tx(&psbt3.extract_tx().expect("failed to extract tx")); let psbt3 = new_tx!(wallet); let change_derivation_4 = psbt3 diff --git a/crates/bitcoind_rpc/Cargo.toml b/crates/bitcoind_rpc/Cargo.toml index cc1acadc6..41cde4d6b 100644 --- a/crates/bitcoind_rpc/Cargo.toml +++ b/crates/bitcoind_rpc/Cargo.toml @@ -14,9 +14,9 @@ readme = "README.md" [dependencies] # For no-std, remember to enable the bitcoin/no-std feature -bitcoin = { version = "0.30", default-features = false } -bitcoincore-rpc = { version = "0.17" } -bdk_chain = { path = "../chain", version = "0.11", default-features = false } +bitcoin = { version = "0.32.0-rc1", default-features = false } +bitcoincore-rpc = { version = "0.19" } +bdk_chain = { path = "../chain", default-features = false } [dev-dependencies] bdk_testenv = { path = "../testenv", version = "0.1.0", default_features = false } diff --git a/crates/bitcoind_rpc/tests/test_emitter.rs b/crates/bitcoind_rpc/tests/test_emitter.rs index 97946da99..9ac8b72c8 100644 --- a/crates/bitcoind_rpc/tests/test_emitter.rs +++ b/crates/bitcoind_rpc/tests/test_emitter.rs @@ -206,7 +206,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> { .graph .txs .iter() - .map(|tx| tx.txid()) + .map(|tx| tx.compute_txid()) .collect::>(), exp_txids, "changeset should have the 3 mempool transactions", @@ -350,7 +350,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> { .rpc_client() .get_new_address(None, None)? .assume_checked(); - let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros()); + let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros()); let addr_to_track = Address::from_script(&spk_to_track, bitcoin::Network::Regtest)?; // setup receiver @@ -453,7 +453,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> { let emitted_txids = emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(); assert_eq!( emitted_txids, exp_txids, @@ -522,7 +522,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<() emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(), tx_introductions.iter().map(|&(_, txid)| txid).collect(), "first mempool emission should include all txs", @@ -531,7 +531,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<() emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(), tx_introductions.iter().map(|&(_, txid)| txid).collect(), "second mempool emission should still include all txs", @@ -551,7 +551,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<() let emitted_txids = emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(); assert_eq!( emitted_txids, exp_txids, @@ -609,7 +609,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> { emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(), env.rpc_client() .get_raw_mempool()? @@ -646,7 +646,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> { let mempool = emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(); let exp_mempool = tx_introductions .iter() @@ -661,7 +661,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> { let mempool = emitter .mempool()? .into_iter() - .map(|(tx, _)| tx.txid()) + .map(|(tx, _)| tx.compute_txid()) .collect::>(); let exp_mempool = tx_introductions .iter() diff --git a/crates/chain/Cargo.toml b/crates/chain/Cargo.toml index 6c5a59915..241d84a73 100644 --- a/crates/chain/Cargo.toml +++ b/crates/chain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bdk_chain" -version = "0.11.0" +version = "0.12.0" edition = "2021" rust-version = "1.63" homepage = "https://bitcoindevkit.org" @@ -14,12 +14,12 @@ readme = "README.md" [dependencies] # For no-std, remember to enable the bitcoin/no-std feature -bitcoin = { version = "0.30.0", default-features = false } +bitcoin = { version = "0.32.0-rc1", default-features = false } serde_crate = { package = "serde", version = "1", optional = true, features = ["derive", "rc"] } # Use hashbrown as a feature flag to have HashSet and HashMap from it. hashbrown = { version = "0.9.1", optional = true, features = ["serde"] } -miniscript = { version = "10.0.0", optional = true, default-features = false } +miniscript = { version = "12.0.0", optional = true, default-features = false } [dev-dependencies] rand = "0.8" diff --git a/crates/chain/src/descriptor_ext.rs b/crates/chain/src/descriptor_ext.rs index 4c77c160b..2f3af95e6 100644 --- a/crates/chain/src/descriptor_ext.rs +++ b/crates/chain/src/descriptor_ext.rs @@ -12,7 +12,7 @@ impl DescriptorExt for Descriptor { self.at_derivation_index(0) .expect("descriptor can't have hardened derivation") .script_pubkey() - .dust_value() + .minimal_non_dust() .to_sat() } } diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index c2b83600b..f88e9650f 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -144,7 +144,7 @@ where let mut graph = tx_graph::ChangeSet::default(); for (tx, anchors) in txs { if self.index.is_tx_relevant(tx) { - let txid = tx.txid(); + let txid = tx.compute_txid(); graph.append(self.graph.insert_tx(tx.clone())); for anchor in anchors { graph.append(self.graph.insert_anchor(txid, anchor)); @@ -235,7 +235,7 @@ where for (tx_pos, tx) in block.txdata.iter().enumerate() { changeset.indexer.append(self.index.index_tx(tx)); if self.index.is_tx_relevant(tx) { - let txid = tx.txid(); + let txid = tx.compute_txid(); let anchor = A::from_block_position(block, block_id, tx_pos); changeset.graph.append(self.graph.insert_tx(tx.clone())); changeset @@ -262,7 +262,7 @@ where let mut graph = tx_graph::ChangeSet::default(); for (tx_pos, tx) in block.txdata.iter().enumerate() { let anchor = A::from_block_position(&block, block_id, tx_pos); - graph.append(self.graph.insert_anchor(tx.txid(), anchor)); + graph.append(self.graph.insert_anchor(tx.compute_txid(), anchor)); graph.append(self.graph.insert_tx(tx.clone())); } let indexer = self.index_tx_graph_changeset(&graph); diff --git a/crates/chain/src/keychain/txout_index.rs b/crates/chain/src/keychain/txout_index.rs index 79f98fad2..20029abc6 100644 --- a/crates/chain/src/keychain/txout_index.rs +++ b/crates/chain/src/keychain/txout_index.rs @@ -129,7 +129,7 @@ impl Indexer for KeychainTxOutIndex { fn index_tx(&mut self, tx: &bitcoin::Transaction) -> Self::ChangeSet { let mut changeset = super::ChangeSet::::default(); for (op, txout) in tx.output.iter().enumerate() { - changeset.append(self.index_txout(OutPoint::new(tx.txid(), op as u32), txout)); + changeset.append(self.index_txout(OutPoint::new(tx.compute_txid(), op as u32), txout)); } changeset } diff --git a/crates/chain/src/spk_txout_index.rs b/crates/chain/src/spk_txout_index.rs index 90ee7dcab..4513e7d06 100644 --- a/crates/chain/src/spk_txout_index.rs +++ b/crates/chain/src/spk_txout_index.rs @@ -4,7 +4,7 @@ use crate::{ collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}, indexed_tx_graph::Indexer, }; -use bitcoin::{self, OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid}; +use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid}; /// An index storing [`TxOut`]s that have a script pubkey that matches those in a list. /// @@ -86,7 +86,7 @@ impl SpkTxOutIndex { /// 2. When getting new data from the chain, you usually scan it before incorporating it into your chain state. pub fn scan(&mut self, tx: &Transaction) -> BTreeSet { let mut scanned_indices = BTreeSet::new(); - let txid = tx.txid(); + let txid = tx.compute_txid(); for (i, txout) in tx.output.iter().enumerate() { let op = OutPoint::new(txid, i as u32); if let Some(spk_i) = self.scan_txout(op, txout) { @@ -281,12 +281,12 @@ impl SpkTxOutIndex { for txin in &tx.input { if let Some((_, txout)) = self.txout(txin.previous_output) { - sent += txout.value; + sent += txout.value.to_sat(); } } for txout in &tx.output { if self.index_of_spk(&txout.script_pubkey).is_some() { - received += txout.value; + received += txout.value.to_sat(); } } diff --git a/crates/chain/src/tx_data_traits.rs b/crates/chain/src/tx_data_traits.rs index 8fa17ff90..b3ab3515e 100644 --- a/crates/chain/src/tx_data_traits.rs +++ b/crates/chain/src/tx_data_traits.rs @@ -43,7 +43,7 @@ use alloc::vec::Vec; /// let mut graph_a = TxGraph::::default(); /// let _ = graph_a.insert_tx(tx.clone()); /// graph_a.insert_anchor( -/// tx.txid(), +/// tx.compute_txid(), /// BlockId { /// height: 1, /// hash: Hash::hash("first".as_bytes()), @@ -58,7 +58,7 @@ use alloc::vec::Vec; /// let mut graph_b = TxGraph::::default(); /// let _ = graph_b.insert_tx(tx.clone()); /// graph_b.insert_anchor( -/// tx.txid(), +/// tx.compute_txid(), /// ConfirmationHeightAnchor { /// anchor_block: BlockId { /// height: 2, @@ -76,7 +76,7 @@ use alloc::vec::Vec; /// let mut graph_c = TxGraph::::default(); /// let _ = graph_c.insert_tx(tx.clone()); /// graph_c.insert_anchor( -/// tx.txid(), +/// tx.compute_txid(), /// ConfirmationTimeHeightAnchor { /// anchor_block: BlockId { /// height: 2, diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index d951d2d31..4822d6b68 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -319,7 +319,7 @@ impl TxGraph { /// /// [`insert_txout`]: Self::insert_txout pub fn calculate_fee(&self, tx: &Transaction) -> Result { - if tx.is_coin_base() { + if tx.is_coinbase() { return Ok(0); } @@ -331,7 +331,7 @@ impl TxGraph { (sum, missing_outpoints) } Some(txout) => { - sum += txout.value as i64; + sum += txout.value.to_sat() as i64; (sum, missing_outpoints) } }, @@ -343,7 +343,7 @@ impl TxGraph { let outputs_sum = tx .output .iter() - .map(|txout| txout.value as i64) + .map(|txout| txout.value.to_sat() as i64) .sum::(); let fee = inputs_sum - outputs_sum; @@ -448,7 +448,7 @@ impl TxGraph { &'g self, tx: &'g Transaction, ) -> impl Iterator + '_ { - let txid = tx.txid(); + let txid = tx.compute_txid(); tx.input .iter() .enumerate() @@ -519,7 +519,7 @@ impl TxGraph { pub fn insert_tx(&mut self, tx: Transaction) -> ChangeSet { let mut update = Self::default(); update.txs.insert( - tx.txid(), + tx.compute_txid(), (TxNodeInternal::Whole(tx.into()), BTreeSet::new(), 0), ); self.apply_update(update) @@ -536,7 +536,7 @@ impl TxGraph { ) -> ChangeSet { let mut changeset = ChangeSet::::default(); for (tx, seen_at) in txs { - changeset.append(self.insert_seen_at(tx.txid(), seen_at)); + changeset.append(self.insert_seen_at(tx.compute_txid(), seen_at)); changeset.append(self.insert_tx(tx)); } changeset @@ -582,7 +582,7 @@ impl TxGraph { pub fn apply_changeset(&mut self, changeset: ChangeSet) { for wrapped_tx in changeset.txs { let tx = wrapped_tx.as_ref(); - let txid = tx.txid(); + let txid = tx.compute_txid(); tx.input .iter() @@ -600,7 +600,7 @@ impl TxGraph { } Some((TxNodeInternal::Whole(tx), _, _)) => { debug_assert_eq!( - tx.as_ref().txid(), + tx.as_ref().compute_txid(), txid, "tx should produce txid that is same as key" ); @@ -807,7 +807,7 @@ impl TxGraph { TxNodeInternal::Whole(tx) => { // A coinbase tx that is not anchored in the best chain cannot be unconfirmed and // should always be filtered out. - if tx.as_ref().is_coin_base() { + if tx.is_coinbase() { return Ok(None); } tx.clone() @@ -828,7 +828,7 @@ impl TxGraph { // resulting array will also include `tx` let unconfirmed_ancestor_txs = TxAncestors::new_include_root(self, tx.clone(), |_, ancestor_tx: Arc| { - let tx_node = self.get_tx_node(ancestor_tx.as_ref().txid())?; + let tx_node = self.get_tx_node(ancestor_tx.as_ref().compute_txid())?; // We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in // the best chain) for block in tx_node.anchors { @@ -846,7 +846,7 @@ impl TxGraph { // and our unconf descendants' last seen. let unconfirmed_descendants_txs = TxDescendants::new_include_root( self, - tx.as_ref().txid(), + tx.as_ref().compute_txid(), |_, descendant_txid: Txid| { let tx_node = self.get_tx_node(descendant_txid)?; // We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in @@ -887,7 +887,7 @@ impl TxGraph { return Ok(None); } if conflicting_tx.last_seen_unconfirmed == *last_seen - && conflicting_tx.as_ref().txid() > tx.as_ref().txid() + && conflicting_tx.as_ref().compute_txid() > tx.as_ref().compute_txid() { // Conflicting tx has priority if txid of conflicting tx > txid of original tx return Ok(None); @@ -982,7 +982,7 @@ impl TxGraph { chain_tip: BlockId, ) -> impl Iterator, A>, C::Error>> { self.full_txs().filter_map(move |tx| { - self.try_get_chain_position(chain, chain_tip, tx.txid) + self.try_get_chain_position(chain, chain_tip, tx.compute_txid()) .map(|v| { v.map(|observed_in| CanonicalTx { chain_position: observed_in, @@ -1063,7 +1063,7 @@ impl TxGraph { txout, chain_position, spent_by, - is_on_coinbase: tx_node.tx.as_ref().is_coin_base(), + is_on_coinbase: tx_node.tx.is_coinbase(), }, ))) }, @@ -1166,16 +1166,16 @@ impl TxGraph { match &txout.chain_position { ChainPosition::Confirmed(_) => { if txout.is_confirmed_and_spendable(chain_tip.height) { - confirmed += txout.txout.value; + confirmed += txout.txout.value.to_sat(); } else if !txout.is_mature(chain_tip.height) { - immature += txout.txout.value; + immature += txout.txout.value.to_sat(); } } ChainPosition::Unconfirmed(_) => { if trust_predicate(&spk_i, &txout.txout.script_pubkey) { - trusted_pending += txout.txout.value; + trusted_pending += txout.txout.value.to_sat(); } else { - untrusted_pending += txout.txout.value; + untrusted_pending += txout.txout.value.to_sat(); } } } @@ -1258,7 +1258,7 @@ impl ChangeSet { tx.output .iter() .enumerate() - .map(move |(vout, txout)| (OutPoint::new(tx.txid(), vout as _), txout)) + .map(move |(vout, txout)| (OutPoint::new(tx.compute_txid(), vout as _), txout)) }) .chain(self.txouts.iter().map(|(op, txout)| (*op, txout))) } diff --git a/crates/chain/tests/common/mod.rs b/crates/chain/tests/common/mod.rs index 7cc3f57a9..6116484ce 100644 --- a/crates/chain/tests/common/mod.rs +++ b/crates/chain/tests/common/mod.rs @@ -70,7 +70,7 @@ macro_rules! changeset { #[allow(unused)] pub fn new_tx(lt: u32) -> bitcoin::Transaction { bitcoin::Transaction { - version: 0x00, + version: bitcoin::transaction::Version::non_standard(0x00), lock_time: bitcoin::absolute::LockTime::from_consensus(lt), input: vec![], output: vec![], diff --git a/crates/chain/tests/common/tx_template.rs b/crates/chain/tests/common/tx_template.rs index ec2eb1159..3f9872acb 100644 --- a/crates/chain/tests/common/tx_template.rs +++ b/crates/chain/tests/common/tx_template.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use bdk_chain::{tx_graph::TxGraph, Anchor, SpkTxOutIndex}; use bitcoin::{ - locktime::absolute::LockTime, secp256k1::Secp256k1, OutPoint, ScriptBuf, Sequence, Transaction, - TxIn, TxOut, Txid, Witness, + locktime::absolute::LockTime, secp256k1::Secp256k1, transaction, Amount, OutPoint, ScriptBuf, + Sequence, Transaction, TxIn, TxOut, Txid, Witness, }; use miniscript::Descriptor; @@ -68,7 +68,7 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>( for (bogus_txin_vout, tx_tmp) in tx_templates.into_iter().enumerate() { let tx = Transaction { - version: 0, + version: transaction::Version::non_standard(0), lock_time: LockTime::ZERO, input: tx_tmp .inputs @@ -111,25 +111,25 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>( .iter() .map(|output| match &output.spk_index { None => TxOut { - value: output.value, + value: Amount::from_sat(output.value), script_pubkey: ScriptBuf::new(), }, Some(index) => TxOut { - value: output.value, + value: Amount::from_sat(output.value), script_pubkey: spk_index.spk_at_index(index).unwrap().to_owned(), }, }) .collect(), }; - tx_ids.insert(tx_tmp.tx_name, tx.txid()); + tx_ids.insert(tx_tmp.tx_name, tx.compute_txid()); spk_index.scan(&tx); let _ = graph.insert_tx(tx.clone()); for anchor in tx_tmp.anchors.iter() { - let _ = graph.insert_anchor(tx.txid(), anchor.clone()); + let _ = graph.insert_anchor(tx.compute_txid(), anchor.clone()); } if let Some(seen_at) = tx_tmp.last_seen { - let _ = graph.insert_seen_at(tx.txid(), seen_at); + let _ = graph.insert_seen_at(tx.compute_txid(), seen_at); } } (graph, spk_index, tx_ids) diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index 8a56db175..624ad6669 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -9,7 +9,9 @@ use bdk_chain::{ local_chain::LocalChain, tx_graph, ChainPosition, ConfirmationHeightAnchor, }; -use bitcoin::{secp256k1::Secp256k1, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut}; +use bitcoin::{ + secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut, +}; use miniscript::Descriptor; /// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented @@ -35,11 +37,11 @@ fn insert_relevant_txs() { let tx_a = Transaction { output: vec![ TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: spk_0, }, TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: spk_1, }, ], @@ -48,7 +50,7 @@ fn insert_relevant_txs() { let tx_b = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a.txid(), 0), + previous_output: OutPoint::new(tx_a.compute_txid(), 0), ..Default::default() }], ..common::new_tx(1) @@ -56,7 +58,7 @@ fn insert_relevant_txs() { let tx_c = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a.txid(), 1), + previous_output: OutPoint::new(tx_a.compute_txid(), 1), ..Default::default() }], ..common::new_tx(2) @@ -154,7 +156,7 @@ fn test_list_owned_txouts() { ..Default::default() }], output: vec![TxOut { - value: 70000, + value: Amount::from_sat(70000), script_pubkey: trusted_spks[0].to_owned(), }], ..common::new_tx(0) @@ -163,7 +165,7 @@ fn test_list_owned_txouts() { // tx2 is an incoming transaction received at untrusted keychain at block 1. let tx2 = Transaction { output: vec![TxOut { - value: 30000, + value: Amount::from_sat(30000), script_pubkey: untrusted_spks[0].to_owned(), }], ..common::new_tx(0) @@ -172,11 +174,11 @@ fn test_list_owned_txouts() { // tx3 spends tx2 and gives a change back in trusted keychain. Confirmed at Block 2. let tx3 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx2.txid(), 0), + previous_output: OutPoint::new(tx2.compute_txid(), 0), ..Default::default() }], output: vec![TxOut { - value: 10000, + value: Amount::from_sat(10000), script_pubkey: trusted_spks[1].to_owned(), }], ..common::new_tx(0) @@ -185,7 +187,7 @@ fn test_list_owned_txouts() { // tx4 is an external transaction receiving at untrusted keychain, unconfirmed. let tx4 = Transaction { output: vec![TxOut { - value: 20000, + value: Amount::from_sat(20000), script_pubkey: untrusted_spks[1].to_owned(), }], ..common::new_tx(0) @@ -194,7 +196,7 @@ fn test_list_owned_txouts() { // tx5 is spending tx3 and receiving change at trusted keychain, unconfirmed. let tx5 = Transaction { output: vec![TxOut { - value: 15000, + value: Amount::from_sat(15000), script_pubkey: trusted_spks[2].to_owned(), }], ..common::new_tx(0) @@ -324,16 +326,22 @@ fn test_list_owned_txouts() { balance, ) = fetch(0, &graph); - assert_eq!(confirmed_txouts_txid, [tx1.txid()].into()); + assert_eq!(confirmed_txouts_txid, [tx1.compute_txid()].into()); assert_eq!( unconfirmed_txouts_txid, - [tx2.txid(), tx3.txid(), tx4.txid(), tx5.txid()].into() + [ + tx2.compute_txid(), + tx3.compute_txid(), + tx4.compute_txid(), + tx5.compute_txid() + ] + .into() ); - assert_eq!(confirmed_utxos_txid, [tx1.txid()].into()); + assert_eq!(confirmed_utxos_txid, [tx1.compute_txid()].into()); assert_eq!( unconfirmed_utxos_txid, - [tx3.txid(), tx4.txid(), tx5.txid()].into() + [tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into() ); assert_eq!( @@ -358,17 +366,20 @@ fn test_list_owned_txouts() { ) = fetch(1, &graph); // tx2 gets into confirmed txout set - assert_eq!(confirmed_txouts_txid, [tx1.txid(), tx2.txid()].into()); + assert_eq!( + confirmed_txouts_txid, + [tx1.compute_txid(), tx2.compute_txid()].into() + ); assert_eq!( unconfirmed_txouts_txid, - [tx3.txid(), tx4.txid(), tx5.txid()].into() + [tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into() ); // tx2 doesn't get into confirmed utxos set - assert_eq!(confirmed_utxos_txid, [tx1.txid()].into()); + assert_eq!(confirmed_utxos_txid, [tx1.compute_txid()].into()); assert_eq!( unconfirmed_utxos_txid, - [tx3.txid(), tx4.txid(), tx5.txid()].into() + [tx3.compute_txid(), tx4.compute_txid(), tx5.compute_txid()].into() ); assert_eq!( @@ -395,13 +406,22 @@ fn test_list_owned_txouts() { // tx3 now gets into the confirmed txout set assert_eq!( confirmed_txouts_txid, - [tx1.txid(), tx2.txid(), tx3.txid()].into() + [tx1.compute_txid(), tx2.compute_txid(), tx3.compute_txid()].into() + ); + assert_eq!( + unconfirmed_txouts_txid, + [tx4.compute_txid(), tx5.compute_txid()].into() ); - assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into()); // tx3 also gets into confirmed utxo set - assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into()); - assert_eq!(unconfirmed_utxos_txid, [tx4.txid(), tx5.txid()].into()); + assert_eq!( + confirmed_utxos_txid, + [tx1.compute_txid(), tx3.compute_txid()].into() + ); + assert_eq!( + unconfirmed_utxos_txid, + [tx4.compute_txid(), tx5.compute_txid()].into() + ); assert_eq!( balance, @@ -426,12 +446,21 @@ fn test_list_owned_txouts() { assert_eq!( confirmed_txouts_txid, - [tx1.txid(), tx2.txid(), tx3.txid()].into() + [tx1.compute_txid(), tx2.compute_txid(), tx3.compute_txid()].into() + ); + assert_eq!( + unconfirmed_txouts_txid, + [tx4.compute_txid(), tx5.compute_txid()].into() ); - assert_eq!(unconfirmed_txouts_txid, [tx4.txid(), tx5.txid()].into()); - assert_eq!(confirmed_utxos_txid, [tx1.txid(), tx3.txid()].into()); - assert_eq!(unconfirmed_utxos_txid, [tx4.txid(), tx5.txid()].into()); + assert_eq!( + confirmed_utxos_txid, + [tx1.compute_txid(), tx3.compute_txid()].into() + ); + assert_eq!( + unconfirmed_utxos_txid, + [tx4.compute_txid(), tx5.compute_txid()].into() + ); // Coinbase is still immature assert_eq!( diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index 0f71b08da..6e67a0f29 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -9,7 +9,7 @@ use bdk_chain::{ Append, }; -use bitcoin::{secp256k1::Secp256k1, OutPoint, ScriptBuf, Transaction, TxOut}; +use bitcoin::{secp256k1::Secp256k1, Amount, OutPoint, ScriptBuf, Transaction, TxOut}; use miniscript::{Descriptor, DescriptorPublicKey}; #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)] @@ -176,14 +176,14 @@ fn test_lookahead() { .at_derivation_index(external_index) .unwrap() .script_pubkey(), - value: 10_000, + value: Amount::from_sat(10_000), }, TxOut { script_pubkey: internal_desc .at_derivation_index(internal_index) .unwrap() .script_pubkey(), - value: 10_000, + value: Amount::from_sat(10_000), }, ], ..common::new_tx(external_index) @@ -238,7 +238,7 @@ fn test_scan_with_lookahead() { let op = OutPoint::new(h!("fake tx"), spk_i); let txout = TxOut { script_pubkey: spk.clone(), - value: 0, + value: Amount::ZERO, }; let changeset = txout_index.index_txout(op, &txout); @@ -264,7 +264,7 @@ fn test_scan_with_lookahead() { let op = OutPoint::new(h!("fake tx"), 41); let txout = TxOut { script_pubkey: spk_41, - value: 0, + value: Amount::ZERO, }; let changeset = txout_index.index_txout(op, &txout); assert!(changeset.is_empty()); diff --git a/crates/chain/tests/test_spk_txout_index.rs b/crates/chain/tests/test_spk_txout_index.rs index e8b752146..ce0f51327 100644 --- a/crates/chain/tests/test_spk_txout_index.rs +++ b/crates/chain/tests/test_spk_txout_index.rs @@ -1,5 +1,5 @@ use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex}; -use bitcoin::{absolute, OutPoint, ScriptBuf, Transaction, TxIn, TxOut}; +use bitcoin::{absolute, transaction, Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut}; #[test] fn spk_txout_sent_and_received() { @@ -11,11 +11,11 @@ fn spk_txout_sent_and_received() { index.insert_spk(1, spk2.clone()); let tx1 = Transaction { - version: 0x02, + version: transaction::Version::TWO, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 42_000, + value: Amount::from_sat(42_000), script_pubkey: spk1.clone(), }], }; @@ -30,23 +30,23 @@ fn spk_txout_sent_and_received() { ); let tx2 = Transaction { - version: 0x1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { - txid: tx1.txid(), + txid: tx1.compute_txid(), vout: 0, }, ..Default::default() }], output: vec![ TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: spk2, }, TxOut { script_pubkey: spk1, - value: 30_000, + value: Amount::from_sat(30_000), }, ], }; @@ -73,11 +73,11 @@ fn mark_used() { assert!(spk_index.is_used(&1)); let tx1 = Transaction { - version: 0x02, + version: transaction::Version::TWO, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 42_000, + value: Amount::from_sat(42_000), script_pubkey: spk1, }], }; diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 8b4674485..a1510af90 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -8,7 +8,8 @@ use bdk_chain::{ Anchor, Append, BlockId, ChainOracle, ChainPosition, ConfirmationHeightAnchor, }; use bitcoin::{ - absolute, hashes::Hash, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, + absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, + TxOut, Txid, }; use common::*; use core::iter; @@ -23,14 +24,14 @@ fn insert_txouts() { ( OutPoint::new(h!("tx1"), 1), TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new(), }, ), ( OutPoint::new(h!("tx1"), 2), TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: ScriptBuf::new(), }, ), @@ -40,21 +41,21 @@ fn insert_txouts() { let update_ops = [( OutPoint::new(h!("tx2"), 0), TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: ScriptBuf::new(), }, )]; // One full transaction to be included in the update let update_txs = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() }], output: vec![TxOut { - value: 30_000, + value: Amount::from_sat(30_000), script_pubkey: ScriptBuf::new(), }], }; @@ -127,11 +128,11 @@ fn insert_txouts() { // Mark it as confirmed. assert_eq!( - graph.insert_anchor(update_txs.txid(), conf_anchor), + graph.insert_anchor(update_txs.compute_txid(), conf_anchor), ChangeSet { txs: [].into(), txouts: [].into(), - anchors: [(conf_anchor, update_txs.txid())].into(), + anchors: [(conf_anchor, update_txs.compute_txid())].into(), last_seen: [].into() } ); @@ -146,7 +147,11 @@ fn insert_txouts() { ChangeSet { txs: [Arc::new(update_txs.clone())].into(), txouts: update_ops.clone().into(), - anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(), + anchors: [ + (conf_anchor, update_txs.compute_txid()), + (unconf_anchor, h!("tx2")) + ] + .into(), last_seen: [(h!("tx2"), 1000000)].into() } ); @@ -164,14 +169,14 @@ fn insert_txouts() { ( 1u32, &TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new(), } ), ( 2u32, &TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: ScriptBuf::new(), } ) @@ -180,11 +185,13 @@ fn insert_txouts() { ); assert_eq!( - graph.tx_outputs(update_txs.txid()).expect("should exists"), + graph + .tx_outputs(update_txs.compute_txid()) + .expect("should exists"), [( 0u32, &TxOut { - value: 30_000, + value: Amount::from_sat(30_000), script_pubkey: ScriptBuf::new() } )] @@ -197,7 +204,11 @@ fn insert_txouts() { ChangeSet { txs: [Arc::new(update_txs.clone())].into(), txouts: update_ops.into_iter().chain(original_ops).collect(), - anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(), + anchors: [ + (conf_anchor, update_txs.compute_txid()), + (unconf_anchor, h!("tx2")) + ] + .into(), last_seen: [(h!("tx2"), 1000000)].into() } ); @@ -206,7 +217,7 @@ fn insert_txouts() { #[test] fn insert_tx_graph_doesnt_count_coinbase_as_spent() { let tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), @@ -225,19 +236,19 @@ fn insert_tx_graph_doesnt_count_coinbase_as_spent() { #[test] fn insert_tx_graph_keeps_track_of_spend() { let tx1 = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], }; let op = OutPoint { - txid: tx1.txid(), + txid: tx1.compute_txid(), vout: 0, }; let tx2 = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: op, @@ -258,7 +269,7 @@ fn insert_tx_graph_keeps_track_of_spend() { assert_eq!( graph1.outspends(op), - &iter::once(tx2.txid()).collect::>() + &iter::once(tx2.compute_txid()).collect::>() ); assert_eq!(graph2.outspends(op), graph1.outspends(op)); } @@ -266,19 +277,21 @@ fn insert_tx_graph_keeps_track_of_spend() { #[test] fn insert_tx_can_retrieve_full_tx_from_graph() { let tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], }; let mut graph = TxGraph::<()>::default(); let _ = graph.insert_tx(tx.clone()); assert_eq!( - graph.get_tx(tx.txid()).map(|tx| tx.as_ref().clone()), + graph + .get_tx(tx.compute_txid()) + .map(|tx| tx.as_ref().clone()), Some(tx) ); } @@ -287,22 +300,22 @@ fn insert_tx_can_retrieve_full_tx_from_graph() { fn insert_tx_displaces_txouts() { let mut tx_graph = TxGraph::<()>::default(); let tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 42_000, - script_pubkey: ScriptBuf::default(), + value: Amount::from_sat(42_000), + script_pubkey: ScriptBuf::new(), }], }; let changeset = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { - value: 1_337_000, + value: Amount::from_sat(1_337_000), script_pubkey: ScriptBuf::default(), }, ); @@ -311,12 +324,12 @@ fn insert_tx_displaces_txouts() { let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { - value: 1_000_000_000, - script_pubkey: ScriptBuf::default(), + value: Amount::from_sat(1_000_000_000), + script_pubkey: ScriptBuf::new(), }, ); @@ -325,16 +338,16 @@ fn insert_tx_displaces_txouts() { assert_eq!( tx_graph .get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0 }) .unwrap() .value, - 42_000 + Amount::from_sat(42_000) ); assert_eq!( tx_graph.get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 1 }), None @@ -345,12 +358,12 @@ fn insert_tx_displaces_txouts() { fn insert_txout_does_not_displace_tx() { let mut tx_graph = TxGraph::<()>::default(); let tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 42_000, - script_pubkey: ScriptBuf::default(), + value: Amount::from_sat(42_000), + script_pubkey: ScriptBuf::new(), }], }; @@ -358,39 +371,39 @@ fn insert_txout_does_not_displace_tx() { let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { - value: 1_337_000, - script_pubkey: ScriptBuf::default(), + value: Amount::from_sat(1_337_000), + script_pubkey: ScriptBuf::new(), }, ); let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { - value: 1_000_000_000, - script_pubkey: ScriptBuf::default(), + value: Amount::from_sat(1_000_000_000), + script_pubkey: ScriptBuf::new(), }, ); assert_eq!( tx_graph .get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0 }) .unwrap() .value, - 42_000 + Amount::from_sat(42_000) ); assert_eq!( tx_graph.get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 1 }), None @@ -401,21 +414,21 @@ fn insert_txout_does_not_displace_tx() { fn test_calculate_fee() { let mut graph = TxGraph::<()>::default(); let intx1 = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 100, - ..Default::default() + value: Amount::from_sat(100), + script_pubkey: ScriptBuf::new(), }], }; let intx2 = Transaction { - version: 0x02, + version: transaction::Version::TWO, lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { - value: 200, - ..Default::default() + value: Amount::from_sat(200), + script_pubkey: ScriptBuf::new(), }], }; @@ -425,8 +438,8 @@ fn test_calculate_fee() { vout: 0, }, TxOut { - value: 300, - ..Default::default() + value: Amount::from_sat(300), + script_pubkey: ScriptBuf::new(), }, ); @@ -435,19 +448,19 @@ fn test_calculate_fee() { let _ = graph.insert_txout(intxout1.0, intxout1.1); let mut tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![ TxIn { previous_output: OutPoint { - txid: intx1.txid(), + txid: intx1.compute_txid(), vout: 0, }, ..Default::default() }, TxIn { previous_output: OutPoint { - txid: intx2.txid(), + txid: intx2.compute_txid(), vout: 0, }, ..Default::default() @@ -458,8 +471,8 @@ fn test_calculate_fee() { }, ], output: vec![TxOut { - value: 500, - ..Default::default() + value: Amount::from_sat(500), + script_pubkey: ScriptBuf::new(), }], }; @@ -491,13 +504,13 @@ fn test_calculate_fee() { #[test] fn test_calculate_fee_on_coinbase() { let tx = Transaction { - version: 0x01, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint::null(), ..Default::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], }; let graph = TxGraph::<()>::default(); @@ -533,27 +546,27 @@ fn test_walk_ancestors() { previous_output: OutPoint::new(h!("op0"), 0), ..TxIn::default() }], - output: vec![TxOut::default(), TxOut::default()], + output: vec![TxOut::NULL, TxOut::NULL], ..common::new_tx(0) }; // tx_b0 spends tx_a0 let tx_b0 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a0.txid(), 0), + previous_output: OutPoint::new(tx_a0.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default(), TxOut::default()], + output: vec![TxOut::NULL, TxOut::NULL], ..common::new_tx(0) }; // tx_b1 spends tx_a0 let tx_b1 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a0.txid(), 1), + previous_output: OutPoint::new(tx_a0.compute_txid(), 1), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -562,27 +575,27 @@ fn test_walk_ancestors() { previous_output: OutPoint::new(h!("op1"), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; // tx_c0 spends tx_b0 let tx_c0 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_b0.txid(), 0), + previous_output: OutPoint::new(tx_b0.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; // tx_c1 spends tx_b0 let tx_c1 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_b0.txid(), 1), + previous_output: OutPoint::new(tx_b0.compute_txid(), 1), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -590,15 +603,15 @@ fn test_walk_ancestors() { let tx_c2 = Transaction { input: vec![ TxIn { - previous_output: OutPoint::new(tx_b1.txid(), 0), + previous_output: OutPoint::new(tx_b1.compute_txid(), 0), ..TxIn::default() }, TxIn { - previous_output: OutPoint::new(tx_b2.txid(), 0), + previous_output: OutPoint::new(tx_b2.compute_txid(), 0), ..TxIn::default() }, ], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -607,17 +620,17 @@ fn test_walk_ancestors() { previous_output: OutPoint::new(h!("op2"), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; // tx_d0 spends tx_c1 let tx_d0 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_c1.txid(), 0), + previous_output: OutPoint::new(tx_c1.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -625,25 +638,25 @@ fn test_walk_ancestors() { let tx_d1 = Transaction { input: vec![ TxIn { - previous_output: OutPoint::new(tx_c2.txid(), 0), + previous_output: OutPoint::new(tx_c2.compute_txid(), 0), ..TxIn::default() }, TxIn { - previous_output: OutPoint::new(tx_c3.txid(), 0), + previous_output: OutPoint::new(tx_c3.compute_txid(), 0), ..TxIn::default() }, ], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; // tx_e0 spends tx_d1 let tx_e0 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_d1.txid(), 0), + previous_output: OutPoint::new(tx_d1.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -662,7 +675,7 @@ fn test_walk_ancestors() { ]); [&tx_a0, &tx_b1].iter().for_each(|&tx| { - let changeset = graph.insert_anchor(tx.txid(), tip.block_id()); + let changeset = graph.insert_anchor(tx.compute_txid(), tip.block_id()); assert!(!changeset.is_empty()); }); @@ -679,7 +692,7 @@ fn test_walk_ancestors() { // Only traverse unconfirmed ancestors of tx_e0 this time graph .walk_ancestors(tx_e0.clone(), |depth, tx| { - let tx_node = graph.get_tx_node(tx.txid())?; + let tx_node = graph.get_tx_node(tx.compute_txid())?; for block in tx_node.anchors { match local_chain.is_block_in_chain(block.anchor_block(), tip.block_id()) { Ok(Some(true)) => return None, @@ -726,7 +739,7 @@ fn test_conflicting_descendants() { previous_output, ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(0) }; @@ -736,22 +749,22 @@ fn test_conflicting_descendants() { previous_output, ..TxIn::default() }], - output: vec![TxOut::default(), TxOut::default()], + output: vec![TxOut::NULL, TxOut::NULL], ..common::new_tx(1) }; // tx_b spends tx_a let tx_b = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a.txid(), 0), + previous_output: OutPoint::new(tx_a.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(2) }; - let txid_a = tx_a.txid(); - let txid_b = tx_b.txid(); + let txid_a = tx_a.compute_txid(); + let txid_b = tx_b.compute_txid(); let mut graph = TxGraph::<()>::default(); let _ = graph.insert_tx(tx_a); @@ -768,17 +781,17 @@ fn test_conflicting_descendants() { #[test] fn test_descendants_no_repeat() { let tx_a = Transaction { - output: vec![TxOut::default(), TxOut::default(), TxOut::default()], + output: vec![TxOut::NULL, TxOut::NULL, TxOut::NULL], ..common::new_tx(0) }; let txs_b = (0..3) .map(|vout| Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_a.txid(), vout), + previous_output: OutPoint::new(tx_a.compute_txid(), vout), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(1) }) .collect::>(); @@ -786,10 +799,10 @@ fn test_descendants_no_repeat() { let txs_c = (0..2) .map(|vout| Transaction { input: vec![TxIn { - previous_output: OutPoint::new(txs_b[vout as usize].txid(), vout), + previous_output: OutPoint::new(txs_b[vout as usize].compute_txid(), vout), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(2) }) .collect::>(); @@ -797,24 +810,24 @@ fn test_descendants_no_repeat() { let tx_d = Transaction { input: vec![ TxIn { - previous_output: OutPoint::new(txs_c[0].txid(), 0), + previous_output: OutPoint::new(txs_c[0].compute_txid(), 0), ..TxIn::default() }, TxIn { - previous_output: OutPoint::new(txs_c[1].txid(), 0), + previous_output: OutPoint::new(txs_c[1].compute_txid(), 0), ..TxIn::default() }, ], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(3) }; let tx_e = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_d.txid(), 0), + previous_output: OutPoint::new(tx_d.compute_txid(), 0), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(4) }; @@ -824,7 +837,7 @@ fn test_descendants_no_repeat() { previous_output: OutPoint::new(h!("tx_does_not_exist"), v), ..TxIn::default() }], - output: vec![TxOut::default()], + output: vec![TxOut::NULL], ..common::new_tx(v) }) .collect::>(); @@ -845,11 +858,11 @@ fn test_descendants_no_repeat() { .chain(core::iter::once(&tx_e)) { let _ = graph.insert_tx(tx.clone()); - expected_txids.push(tx.txid()); + expected_txids.push(tx.compute_txid()); } let descendants = graph - .walk_descendants(tx_a.txid(), |_, txid| Some(txid)) + .walk_descendants(tx_a.compute_txid(), |_, txid| Some(txid)) .collect::>(); assert_eq!(descendants, expected_txids); @@ -871,11 +884,11 @@ fn test_chain_spends() { input: vec![], output: vec![ TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new(), }, TxOut { - value: 20_000, + value: Amount::from_sat(20_000), script_pubkey: ScriptBuf::new(), }, ], @@ -885,16 +898,16 @@ fn test_chain_spends() { // The first confirmed transaction spends vout: 0. And is confirmed at block 98. let tx_1 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_0.txid(), 0), + previous_output: OutPoint::new(tx_0.compute_txid(), 0), ..TxIn::default() }], output: vec![ TxOut { - value: 5_000, + value: Amount::from_sat(5_000), script_pubkey: ScriptBuf::new(), }, TxOut { - value: 5_000, + value: Amount::from_sat(5_000), script_pubkey: ScriptBuf::new(), }, ], @@ -904,16 +917,16 @@ fn test_chain_spends() { // The second transactions spends vout:1, and is unconfirmed. let tx_2 = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_0.txid(), 1), + previous_output: OutPoint::new(tx_0.compute_txid(), 1), ..TxIn::default() }], output: vec![ TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new(), }, TxOut { - value: 10_000, + value: Amount::from_sat(10_000), script_pubkey: ScriptBuf::new(), }, ], @@ -928,7 +941,7 @@ fn test_chain_spends() { for (ht, tx) in [(95, &tx_0), (98, &tx_1)] { let _ = graph.insert_anchor( - tx.txid(), + tx.compute_txid(), ConfirmationHeightAnchor { anchor_block: tip.block_id(), confirmation_height: ht, @@ -938,19 +951,23 @@ fn test_chain_spends() { // Assert that confirmed spends are returned correctly. assert_eq!( - graph.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 0)), + graph.get_chain_spend( + &local_chain, + tip.block_id(), + OutPoint::new(tx_0.compute_txid(), 0) + ), Some(( ChainPosition::Confirmed(&ConfirmationHeightAnchor { anchor_block: tip.block_id(), confirmation_height: 98 }), - tx_1.txid(), + tx_1.compute_txid(), )), ); // Check if chain position is returned correctly. assert_eq!( - graph.get_chain_position(&local_chain, tip.block_id(), tx_0.txid()), + graph.get_chain_position(&local_chain, tip.block_id(), tx_0.compute_txid()), // Some(ObservedAs::Confirmed(&local_chain.get_block(95).expect("block expected"))), Some(ChainPosition::Confirmed(&ConfirmationHeightAnchor { anchor_block: tip.block_id(), @@ -960,25 +977,33 @@ fn test_chain_spends() { // Even if unconfirmed tx has a last_seen of 0, it can still be part of a chain spend. assert_eq!( - graph.get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1)), - Some((ChainPosition::Unconfirmed(0), tx_2.txid())), + graph.get_chain_spend( + &local_chain, + tip.block_id(), + OutPoint::new(tx_0.compute_txid(), 1) + ), + Some((ChainPosition::Unconfirmed(0), tx_2.compute_txid())), ); // Mark the unconfirmed as seen and check correct ObservedAs status is returned. - let _ = graph.insert_seen_at(tx_2.txid(), 1234567); + let _ = graph.insert_seen_at(tx_2.compute_txid(), 1234567); // Check chain spend returned correctly. assert_eq!( graph - .get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1)) + .get_chain_spend( + &local_chain, + tip.block_id(), + OutPoint::new(tx_0.compute_txid(), 1) + ) .unwrap(), - (ChainPosition::Unconfirmed(1234567), tx_2.txid()) + (ChainPosition::Unconfirmed(1234567), tx_2.compute_txid()) ); // A conflicting transaction that conflicts with tx_1. let tx_1_conflict = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_0.txid(), 0), + previous_output: OutPoint::new(tx_0.compute_txid(), 0), ..Default::default() }], ..common::new_tx(0) @@ -987,13 +1012,13 @@ fn test_chain_spends() { // Because this tx conflicts with an already confirmed transaction, chain position should return none. assert!(graph - .get_chain_position(&local_chain, tip.block_id(), tx_1_conflict.txid()) + .get_chain_position(&local_chain, tip.block_id(), tx_1_conflict.compute_txid()) .is_none()); // Another conflicting tx that conflicts with tx_2. let tx_2_conflict = Transaction { input: vec![TxIn { - previous_output: OutPoint::new(tx_0.txid(), 1), + previous_output: OutPoint::new(tx_0.compute_txid(), 1), ..Default::default() }], ..common::new_tx(0) @@ -1001,12 +1026,12 @@ fn test_chain_spends() { // Insert in graph and mark it as seen. let _ = graph.insert_tx(tx_2_conflict.clone()); - let _ = graph.insert_seen_at(tx_2_conflict.txid(), 1234568); + let _ = graph.insert_seen_at(tx_2_conflict.compute_txid(), 1234568); // This should return a valid observation with correct last seen. assert_eq!( graph - .get_chain_position(&local_chain, tip.block_id(), tx_2_conflict.txid()) + .get_chain_position(&local_chain, tip.block_id(), tx_2_conflict.compute_txid()) .expect("position expected"), ChainPosition::Unconfirmed(1234568) ); @@ -1014,14 +1039,21 @@ fn test_chain_spends() { // Chain_spend now catches the new transaction as the spend. assert_eq!( graph - .get_chain_spend(&local_chain, tip.block_id(), OutPoint::new(tx_0.txid(), 1)) + .get_chain_spend( + &local_chain, + tip.block_id(), + OutPoint::new(tx_0.compute_txid(), 1) + ) .expect("expect observation"), - (ChainPosition::Unconfirmed(1234568), tx_2_conflict.txid()) + ( + ChainPosition::Unconfirmed(1234568), + tx_2_conflict.compute_txid() + ) ); // Chain position of the `tx_2` is now none, as it is older than `tx_2_conflict` assert!(graph - .get_chain_position(&local_chain, tip.block_id(), tx_2.txid()) + .get_chain_position(&local_chain, tip.block_id(), tx_2.compute_txid()) .is_none()); } @@ -1242,7 +1274,7 @@ fn call_map_anchors_with_non_deterministic_anchor() { for tx_node in full_txs_vec.iter() { let new_txnode = new_txs.next().unwrap(); - assert_eq!(new_txnode.txid, tx_node.txid); + assert_eq!(new_txnode.compute_txid(), tx_node.compute_txid()); assert_eq!(new_txnode.tx, tx_node.tx); assert_eq!( new_txnode.last_seen_unconfirmed, diff --git a/crates/chain/tests/test_tx_graph_conflicts.rs b/crates/chain/tests/test_tx_graph_conflicts.rs index 8ac440f3e..aae6458ff 100644 --- a/crates/chain/tests/test_tx_graph_conflicts.rs +++ b/crates/chain/tests/test_tx_graph_conflicts.rs @@ -596,7 +596,7 @@ fn test_tx_conflict_handling() { let txs = tx_graph .list_chain_txs(&local_chain, chain_tip) - .map(|tx| tx.tx_node.txid) + .map(|tx| tx.tx_node.compute_txid()) .collect::>(); let exp_txs = scenario .exp_chain_txs diff --git a/crates/electrum/Cargo.toml b/crates/electrum/Cargo.toml index 18064183d..cfffb3793 100644 --- a/crates/electrum/Cargo.toml +++ b/crates/electrum/Cargo.toml @@ -12,11 +12,11 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bdk_chain = { path = "../chain", version = "0.11.0", default-features = false } -electrum-client = { version = "0.18" } +bdk_chain = { path = "../chain", default-features = false } +electrum-client = { version = "0.20" } #rustls = { version = "=0.21.1", optional = true, features = ["dangerous_configuration"] } [dev-dependencies] -bdk_testenv = { path = "../testenv", version = "0.1.0", default-features = false } -electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +bdk_testenv = { path = "../testenv", default-features = false } +electrsd = { version= "0.28.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } anyhow = "1" \ No newline at end of file diff --git a/crates/electrum/src/electrum_ext.rs b/crates/electrum/src/electrum_ext.rs index 5501b1495..b1d236441 100644 --- a/crates/electrum/src/electrum_ext.rs +++ b/crates/electrum/src/electrum_ext.rs @@ -426,7 +426,7 @@ fn populate_with_outpoints( for outpoint in outpoints { let txid = outpoint.txid; let tx = client.transaction_get(&txid)?; - debug_assert_eq!(tx.txid(), txid); + debug_assert_eq!(tx.compute_txid(), txid); let txout = match tx.output.get(outpoint.vout as usize) { Some(txout) => txout, None => continue, diff --git a/crates/electrum/tests/test_electrum.rs b/crates/electrum/tests/test_electrum.rs index 0dc80ac61..68afb3bea 100644 --- a/crates/electrum/tests/test_electrum.rs +++ b/crates/electrum/tests/test_electrum.rs @@ -40,7 +40,7 @@ fn scan_detects_confirmed_tx() -> Result<()> { .client .get_new_address(None, None)? .assume_checked(); - let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros()); + let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros()); let addr_to_track = Address::from_script(&spk_to_track, bdk_chain::bitcoin::Network::Regtest)?; // Setup receiver. @@ -106,7 +106,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> { .client .get_new_address(None, None)? .assume_checked(); - let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros()); + let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros()); let addr_to_track = Address::from_script(&spk_to_track, bdk_chain::bitcoin::Network::Regtest)?; // Setup receiver. diff --git a/crates/esplora/Cargo.toml b/crates/esplora/Cargo.toml index c1cecac4f..ee7afdd5e 100644 --- a/crates/esplora/Cargo.toml +++ b/crates/esplora/Cargo.toml @@ -12,18 +12,18 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bdk_chain = { path = "../chain", version = "0.11.0", default-features = false } -esplora-client = { version = "0.6.0", default-features = false } +bdk_chain = { path = "../chain", default-features = false } +esplora-client = { version = "0.8.0", default-features = false } async-trait = { version = "0.1.66", optional = true } futures = { version = "0.3.26", optional = true } # use these dependencies if you need to enable their /no-std features -bitcoin = { version = "0.30.0", optional = true, default-features = false } -miniscript = { version = "10.0.0", optional = true, default-features = false } +bitcoin = { version = "0.32.0-rc1", optional = true, default-features = false } +miniscript = { version = "12.0.0", optional = true, default-features = false } [dev-dependencies] -bdk_testenv = { path = "../testenv", version = "0.1.0", default_features = false } -electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +bdk_testenv = { path = "../testenv", default_features = false } +electrsd = { version= "0.28.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } [features] diff --git a/crates/esplora/src/async_ext.rs b/crates/esplora/src/async_ext.rs index 9e25eedfb..bd7a2c850 100644 --- a/crates/esplora/src/async_ext.rs +++ b/crates/esplora/src/async_ext.rs @@ -1,7 +1,7 @@ use async_trait::async_trait; use bdk_chain::collections::btree_map; use bdk_chain::{ - bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, + bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, collections::BTreeMap, local_chain::{self, CheckPoint}, BlockId, ConfirmationTimeHeightAnchor, TxGraph, @@ -228,7 +228,7 @@ impl EsploraAsyncExt for esplora_client::AsyncClient { }, TxOut { script_pubkey: prevout.scriptpubkey.clone(), - value: prevout.value, + value: Amount::from_sat(prevout.value), }, )) }); diff --git a/crates/esplora/src/blocking_ext.rs b/crates/esplora/src/blocking_ext.rs index 9cd11e819..52aefedcb 100644 --- a/crates/esplora/src/blocking_ext.rs +++ b/crates/esplora/src/blocking_ext.rs @@ -3,7 +3,7 @@ use std::thread::JoinHandle; use bdk_chain::collections::btree_map; use bdk_chain::collections::BTreeMap; use bdk_chain::{ - bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, + bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid}, local_chain::{self, CheckPoint}, BlockId, ConfirmationTimeHeightAnchor, TxGraph, }; @@ -218,7 +218,7 @@ impl EsploraExt for esplora_client::BlockingClient { }, TxOut { script_pubkey: prevout.scriptpubkey.clone(), - value: prevout.value, + value: Amount::from_sat(prevout.value), }, )) }); diff --git a/crates/esplora/tests/blocking_ext.rs b/crates/esplora/tests/blocking_ext.rs index de0594eec..35e38a778 100644 --- a/crates/esplora/tests/blocking_ext.rs +++ b/crates/esplora/tests/blocking_ext.rs @@ -30,7 +30,7 @@ macro_rules! local_chain { pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> { let env = TestEnv::new()?; let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap()); - let client = Builder::new(base_url.as_str()).build_blocking()?; + let client = Builder::new(base_url.as_str()).build_blocking(); let receive_address0 = Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm")?.assume_checked(); @@ -111,7 +111,7 @@ pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> { pub fn test_update_tx_graph_stop_gap() -> anyhow::Result<()> { let env = TestEnv::new()?; let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap()); - let client = Builder::new(base_url.as_str()).build_blocking()?; + let client = Builder::new(base_url.as_str()).build_blocking(); let _block_hashes = env.mine_blocks(101, None)?; // Now let's test the gap limit. First of all get a chain of 10 addresses. @@ -215,7 +215,7 @@ fn update_local_chain() -> anyhow::Result<()> { // so new blocks can be seen by Electrs let env = env.reset_electrsd()?; let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap()); - let client = Builder::new(base_url.as_str()).build_blocking()?; + let client = Builder::new(base_url.as_str()).build_blocking(); struct TestCase { name: &'static str, diff --git a/crates/file_store/Cargo.toml b/crates/file_store/Cargo.toml index 6c92e3d65..c18fc4ff2 100644 --- a/crates/file_store/Cargo.toml +++ b/crates/file_store/Cargo.toml @@ -11,7 +11,7 @@ authors = ["Bitcoin Dev Kit Developers"] readme = "README.md" [dependencies] -bdk_chain = { path = "../chain", version = "0.11.0", features = [ "serde", "miniscript" ] } +bdk_chain = { path = "../chain", features = [ "serde", "miniscript" ] } bincode = { version = "1" } serde = { version = "1", features = ["derive"] } diff --git a/crates/hwi/Cargo.toml b/crates/hwi/Cargo.toml index de7272432..711a2f948 100644 --- a/crates/hwi/Cargo.toml +++ b/crates/hwi/Cargo.toml @@ -10,4 +10,4 @@ readme = "README.md" [dependencies] bdk = { path = "../bdk" } -hwi = { version = "0.7.0", features = [ "miniscript"] } +hwi = { version = "0.8.0", features = [ "miniscript"] } diff --git a/crates/hwi/src/signer.rs b/crates/hwi/src/signer.rs index b16b60c54..a297291ce 100644 --- a/crates/hwi/src/signer.rs +++ b/crates/hwi/src/signer.rs @@ -1,6 +1,6 @@ use bdk::bitcoin::bip32::Fingerprint; -use bdk::bitcoin::psbt::PartiallySignedTransaction; use bdk::bitcoin::secp256k1::{All, Secp256k1}; +use bdk::bitcoin::Psbt; use hwi::error::Error; use hwi::types::{HWIChain, HWIDevice}; @@ -37,7 +37,7 @@ impl SignerCommon for HWISigner { impl TransactionSigner for HWISigner { fn sign_transaction( &self, - psbt: &mut PartiallySignedTransaction, + psbt: &mut Psbt, _sign_options: &bdk::SignOptions, _secp: &Secp256k1, ) -> Result<(), SignerError> { diff --git a/crates/testenv/Cargo.toml b/crates/testenv/Cargo.toml index 46d4e177b..04a310694 100644 --- a/crates/testenv/Cargo.toml +++ b/crates/testenv/Cargo.toml @@ -13,9 +13,9 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bitcoincore-rpc = { version = "0.17" } -bdk_chain = { path = "../chain", version = "0.11", default-features = false } -electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +bitcoincore-rpc = { version = "0.19" } +bdk_chain = { path = "../chain", default-features = false } +electrsd = { version= "0.28.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } anyhow = { version = "1" } [features] diff --git a/crates/testenv/src/lib.rs b/crates/testenv/src/lib.rs index b836387c1..8cba86261 100644 --- a/crates/testenv/src/lib.rs +++ b/crates/testenv/src/lib.rs @@ -1,7 +1,7 @@ use bdk_chain::bitcoin::{ address::NetworkChecked, block::Header, hash_types::TxMerkleNode, hashes::Hash, - secp256k1::rand::random, Address, Amount, Block, BlockHash, CompactTarget, ScriptBuf, - ScriptHash, Transaction, TxIn, TxOut, Txid, + secp256k1::rand::random, transaction, Address, Amount, Block, BlockHash, CompactTarget, + ScriptBuf, ScriptHash, Transaction, TxIn, TxOut, Txid, }; use bitcoincore_rpc::{ bitcoincore_rpc_json::{GetBlockTemplateModes, GetBlockTemplateRules}, @@ -109,7 +109,7 @@ impl TestEnv { )?; let txdata = vec![Transaction { - version: 1, + version: transaction::Version::ONE, lock_time: bdk_chain::bitcoin::absolute::LockTime::from_height(0)?, input: vec![TxIn { previous_output: bdk_chain::bitcoin::OutPoint::default(), @@ -122,7 +122,7 @@ impl TestEnv { witness: bdk_chain::bitcoin::Witness::new(), }], output: vec![TxOut { - value: 0, + value: Amount::ZERO, script_pubkey: ScriptBuf::new_p2sh(&ScriptHash::all_zeros()), }], }]; diff --git a/example-crates/example_cli/src/lib.rs b/example-crates/example_cli/src/lib.rs index 4989c08c6..8c8607ba1 100644 --- a/example-crates/example_cli/src/lib.rs +++ b/example-crates/example_cli/src/lib.rs @@ -3,12 +3,14 @@ use anyhow::Context; use bdk_coin_select::{coin_select_bnb, CoinSelector, CoinSelectorOpt, WeightedValue}; use bdk_file_store::Store; use serde::{de::DeserializeOwned, Serialize}; -use std::{cmp::Reverse, collections::HashMap, path::PathBuf, sync::Mutex, time::Duration}; +use std::{cmp::Reverse, collections::BTreeMap, path::PathBuf, sync::Mutex, time::Duration}; use bdk_chain::{ bitcoin::{ - absolute, address, psbt::Prevouts, secp256k1::Secp256k1, sighash::SighashCache, Address, - Network, Sequence, Transaction, TxIn, TxOut, + absolute, address, + secp256k1::Secp256k1, + sighash::{Prevouts, SighashCache}, + transaction, Address, Amount, Network, Sequence, Transaction, TxIn, TxOut, }, indexed_tx_graph::{self, IndexedTxGraph}, keychain::{self, KeychainTxOutIndex}, @@ -197,7 +199,7 @@ pub struct CreateTxChange { pub fn create_tx( graph: &mut KeychainTxGraph, chain: &O, - keymap: &HashMap, + keymap: &BTreeMap, cs_algorithm: CoinSelectionAlgo, address: Address, value: u64, @@ -235,7 +237,7 @@ where .iter() .map(|(plan, utxo)| { WeightedValue::new( - utxo.txout.value, + utxo.txout.value.to_sat(), plan.expected_weight() as _, plan.witness_version().is_some(), ) @@ -243,7 +245,7 @@ where .collect(); let mut outputs = vec![TxOut { - value, + value: Amount::from_sat(value), script_pubkey: address.script_pubkey(), }]; @@ -273,7 +275,7 @@ where .expect("failed to obtain change plan"); let mut change_output = TxOut { - value: 0, + value: Amount::ZERO, script_pubkey: change_script, }; @@ -311,13 +313,13 @@ where let selected_txos = selection.apply_selection(&candidates).collect::>(); if let Some(drain_value) = selection_meta.drain_value { - change_output.value = drain_value; + change_output.value = Amount::from_sat(drain_value); // if the selection tells us to use change and the change value is sufficient, we add it as an output outputs.push(change_output) } let mut transaction = Transaction { - version: 0x02, + version: transaction::Version::TWO, // because the temporary planning module does not support timelocks, we can use the chain // tip as the `lock_time` for anti-fee-sniping purposes lock_time: absolute::LockTime::from_height(chain.get_chain_tip()?.height) @@ -440,7 +442,7 @@ pub fn handle_commands>, db: &Mutex>, chain: &Mutex, - keymap: &HashMap, + keymap: &BTreeMap, network: Network, broadcast: impl FnOnce(S, &Transaction) -> anyhow::Result<()>, cmd: Commands, @@ -631,7 +633,7 @@ where match (broadcast)(chain_specific, &transaction) { Ok(_) => { - println!("Broadcasted Tx : {}", transaction.txid()); + println!("Broadcasted Tx : {}", transaction.compute_txid()); let keychain_changeset = graph.lock().unwrap().insert_tx(transaction); diff --git a/example-crates/example_esplora/src/main.rs b/example-crates/example_esplora/src/main.rs index e92205706..0772539f0 100644 --- a/example-crates/example_esplora/src/main.rs +++ b/example-crates/example_esplora/src/main.rs @@ -86,7 +86,7 @@ impl EsploraArgs { _ => panic!("unsupported network"), }); - let client = esplora_client::Builder::new(esplora_url).build_blocking()?; + let client = esplora_client::Builder::new(esplora_url).build_blocking(); Ok(client) } } diff --git a/example-crates/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs index 4f8aba9fd..63c7436d5 100644 --- a/example-crates/wallet_electrum/src/main.rs +++ b/example-crates/wallet_electrum/src/main.rs @@ -99,9 +99,9 @@ fn main() -> Result<(), anyhow::Error> { let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx()?; client.transaction_broadcast(&tx)?; - println!("Tx broadcasted! Txid: {}", tx.txid()); + println!("Tx broadcasted! Txid: {}", tx.compute_txid()); Ok(()) } diff --git a/example-crates/wallet_esplora_async/src/main.rs b/example-crates/wallet_esplora_async/src/main.rs index 690cd87e2..9e70c675c 100644 --- a/example-crates/wallet_esplora_async/src/main.rs +++ b/example-crates/wallet_esplora_async/src/main.rs @@ -90,9 +90,9 @@ async fn main() -> Result<(), anyhow::Error> { let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx()?; client.broadcast(&tx).await?; - println!("Tx broadcasted! Txid: {}", tx.txid()); + println!("Tx broadcasted! Txid: {}", tx.compute_txid()); Ok(()) } diff --git a/example-crates/wallet_esplora_blocking/src/main.rs b/example-crates/wallet_esplora_blocking/src/main.rs index 73bfdd559..de03d3f14 100644 --- a/example-crates/wallet_esplora_blocking/src/main.rs +++ b/example-crates/wallet_esplora_blocking/src/main.rs @@ -34,7 +34,7 @@ fn main() -> Result<(), anyhow::Error> { print!("Syncing..."); let client = - esplora_client::Builder::new("https://blockstream.info/testnet/api").build_blocking()?; + esplora_client::Builder::new("https://blockstream.info/testnet/api").build_blocking(); let prev_tip = wallet.latest_checkpoint(); let keychain_spks = wallet @@ -90,9 +90,9 @@ fn main() -> Result<(), anyhow::Error> { let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); - let tx = psbt.extract_tx(); + let tx = psbt.extract_tx()?; client.broadcast(&tx)?; - println!("Tx broadcasted! Txid: {}", tx.txid()); + println!("Tx broadcasted! Txid: {}", tx.compute_txid()); Ok(()) } diff --git a/nursery/coin_select/src/coin_selector.rs b/nursery/coin_select/src/coin_selector.rs index 281992a96..729f9b23b 100644 --- a/nursery/coin_select/src/coin_selector.rs +++ b/nursery/coin_select/src/coin_selector.rs @@ -96,7 +96,7 @@ impl CoinSelectorOpt { ) -> Self { let mut tx = Transaction { input: vec![], - version: 1, + version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, output: txouts.to_vec(), }; @@ -112,7 +112,7 @@ impl CoinSelectorOpt { target_value: if txouts.is_empty() { None } else { - Some(txouts.iter().map(|txout| txout.value).sum()) + Some(txouts.iter().map(|txout| txout.value.to_sat()).sum()) }, ..Self::from_weights( base_weight.to_wu() as u32, diff --git a/nursery/coin_select/src/lib.rs b/nursery/coin_select/src/lib.rs index dc38c676d..3b8ae12f9 100644 --- a/nursery/coin_select/src/lib.rs +++ b/nursery/coin_select/src/lib.rs @@ -12,7 +12,7 @@ use bdk_chain::{ bitcoin, collections::{BTreeSet, HashMap}, }; -use bitcoin::{absolute, Transaction, TxOut}; +use bitcoin::{absolute, transaction, Transaction, TxOut}; use core::fmt::{Debug, Display}; mod coin_selector; @@ -29,5 +29,5 @@ pub const TXIN_BASE_WEIGHT: u32 = (32 + 4 + 4) * 4; // Shamelessly copied from // https://github.com/rust-bitcoin/rust-miniscript/blob/d5615acda1a7fdc4041a11c1736af139b8c7ebe8/src/util.rs#L8 pub(crate) fn varint_size(v: usize) -> u32 { - bitcoin::VarInt(v as u64).len() as u32 + bitcoin::VarInt(v as u64).size() as u32 } diff --git a/nursery/tmp_plan/src/lib.rs b/nursery/tmp_plan/src/lib.rs index 226ce8b59..d39a7fe6c 100644 --- a/nursery/tmp_plan/src/lib.rs +++ b/nursery/tmp_plan/src/lib.rs @@ -17,14 +17,13 @@ use bdk_chain::{bitcoin, collections::*, miniscript}; use bitcoin::{ absolute, - address::WitnessVersion, bip32::{DerivationPath, Fingerprint, KeySource}, blockdata::transaction::Sequence, ecdsa, hashes::{hash160, ripemd160, sha256}, secp256k1::Secp256k1, taproot::{self, LeafVersion, TapLeafHash}, - ScriptBuf, TxIn, Witness, + ScriptBuf, TxIn, Witness, WitnessVersion, }; use miniscript::{ descriptor::{InnerXKey, Tr}, @@ -32,7 +31,7 @@ use miniscript::{ }; pub(crate) fn varint_len(v: usize) -> usize { - bitcoin::VarInt(v as u64).len() as usize + bitcoin::VarInt(v as u64).size() as usize } mod plan_impls; diff --git a/nursery/tmp_plan/src/plan_impls.rs b/nursery/tmp_plan/src/plan_impls.rs index 6b4da3c90..e594dfb73 100644 --- a/nursery/tmp_plan/src/plan_impls.rs +++ b/nursery/tmp_plan/src/plan_impls.rs @@ -240,7 +240,7 @@ fn plan_steps( if max_sequence.is_height_locked() == older.is_height_locked() { if max_sequence.to_consensus_u32() >= older.to_consensus_u32() { Some(TermPlan { - min_sequence: Some(*older), + min_sequence: Some((*older).into()), ..Default::default() }) } else { @@ -319,7 +319,7 @@ fn plan_steps( } } Terminal::Thresh(_, _) => todo!(), - Terminal::Multi(_, _) => todo!(), - Terminal::MultiA(_, _) => todo!(), + Terminal::Multi(_) => todo!(), + Terminal::MultiA(_) => todo!(), } } diff --git a/nursery/tmp_plan/src/requirements.rs b/nursery/tmp_plan/src/requirements.rs index 08e1ef822..f602353a4 100644 --- a/nursery/tmp_plan/src/requirements.rs +++ b/nursery/tmp_plan/src/requirements.rs @@ -3,12 +3,11 @@ use core::ops::Deref; use bitcoin::{ bip32, - hashes::{hash160, ripemd160, sha256}, + hashes::{hash160, ripemd160, sha256, Hash}, key::XOnlyPublicKey, - psbt::Prevouts, - secp256k1::{KeyPair, Message, PublicKey, Signing, Verification}, + secp256k1::{Keypair, Message, PublicKey, Signing, Verification}, sighash, - sighash::{EcdsaSighashType, SighashCache, TapSighashType}, + sighash::{EcdsaSighashType, Prevouts, SighashCache, TapSighashType}, taproot, Transaction, TxOut, }; @@ -88,20 +87,16 @@ pub enum RequiredSignatures { #[derive(Clone, Debug)] pub enum SigningError { - SigHashError(sighash::Error), + SighashTaproot(sighash::TaprootError), + SighashP2wpkh(sighash::P2wpkhError), DerivationError(bip32::Error), } -impl From for SigningError { - fn from(e: sighash::Error) -> Self { - Self::SigHashError(e) - } -} - impl core::fmt::Display for SigningError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - SigningError::SigHashError(e) => e.fmt(f), + SigningError::SighashTaproot(ref e) => write!(f, "sighash taproot: {}", e), + SigningError::SighashP2wpkh(ref e) => write!(f, "sighash p2wpkh: {}", e), SigningError::DerivationError(e) => e.fmt(f), } } @@ -113,8 +108,30 @@ impl From for SigningError { } } +impl From for SigningError { + fn from(e: sighash::TaprootError) -> Self { + Self::SighashTaproot(e) + } +} + +impl From for SigningError { + fn from(e: sighash::P2wpkhError) -> Self { + Self::SighashP2wpkh(e) + } +} + #[cfg(feature = "std")] -impl std::error::Error for SigningError {} +impl std::error::Error for SigningError { + fn cause(&self) -> Option<&dyn std::error::Error> { + use SigningError::*; + + match *self { + SighashTaproot(ref e) => Some(e), + SighashP2wpkh(ref e) => Some(e), + DerivationError(ref e) => Some(e), + } + } +} impl RequiredSignatures { pub fn sign_with_keymap>( @@ -163,16 +180,16 @@ impl RequiredSignatures { let tweak = taproot::TapTweakHash::from_key_and_tweak(x_only_pubkey, merkle_root.clone()); - let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone()) + let keypair = Keypair::from_secret_key(&secp, &secret_key.clone()) .add_xonly_tweak(&secp, &tweak.to_scalar()) .unwrap(); - let msg = Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes"); - let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair); + let msg = Message::from_digest(sighash.to_byte_array()); + let signature = secp.sign_schnorr_no_aux_rand(&msg, &keypair); let bitcoin_sig = taproot::Signature { - sig, - hash_ty: schnorr_sighashty, + signature, + sighash_type: schnorr_sighashty, }; auth_data @@ -209,13 +226,12 @@ impl RequiredSignatures { todo!(); } }; - let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone()); - let msg = - Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes"); - let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair); + let keypair = Keypair::from_secret_key(&secp, &secret_key.clone()); + let msg = Message::from_digest(sighash.to_byte_array()); + let signature = secp.sign_schnorr_no_aux_rand(&msg, &keypair); let bitcoin_sig = taproot::Signature { - sig, - hash_ty: sighash_type, + signature, + sighash_type: sighash_type, }; auth_data