diff --git a/Cargo.toml b/Cargo.toml index 53ceb7cd47..5d2be3559e 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 2cfa8c9518..fa078aa3be 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 = "11.0.0", features = ["serde"], default-features = false } -bitcoin = { version = "0.31.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 aa52ff279d..bac73e8af9 100644 --- a/crates/bdk/src/descriptor/dsl.rs +++ b/crates/bdk/src/descriptor/dsl.rs @@ -702,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) @@ -768,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 ),* ) @@ -777,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 ),* ) diff --git a/crates/bdk/src/descriptor/error.rs b/crates/bdk/src/descriptor/error.rs index b2809f2107..54db9889dd 100644 --- a/crates/bdk/src/descriptor/error.rs +++ b/crates/bdk/src/descriptor/error.rs @@ -37,7 +37,7 @@ 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 @@ -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) } } diff --git a/crates/bdk/src/descriptor/mod.rs b/crates/bdk/src/descriptor/mod.rs index 4b1135feb7..0d39481042 100644 --- a/crates/bdk/src/descriptor/mod.rs +++ b/crates/bdk/src/descriptor/mod.rs @@ -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(); } _ => {} } @@ -606,8 +606,8 @@ mod test { use assert_matches::assert_matches; use bitcoin::hex::FromHex; use bitcoin::secp256k1::Secp256k1; - use bitcoin::ScriptBuf; use bitcoin::{bip32, Psbt}; + use bitcoin::{NetworkKind, ScriptBuf}; use super::*; use crate::psbt::PsbtUtils; @@ -743,7 +743,7 @@ mod test { .unwrap(); let mut xprv_testnet = xprv; - xprv_testnet.network = Network::Testnet; + xprv_testnet.network = NetworkKind::Test; let xpub_testnet = bip32::Xpub::from_priv(&secp, &xprv_testnet); let desc_pubkey = DescriptorPublicKey::XPub(DescriptorXKey { diff --git a/crates/bdk/src/descriptor/policy.rs b/crates/bdk/src/descriptor/policy.rs index 820bf2d2d3..52c1df4c70 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,86 @@ 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 { + if threshold.k() == 0 { return Ok(None); } - let parsed_keys = keys.iter().map(|k| PkOrF::from_key(k, secp)).collect(); + 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 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)) + } + + fn make_multi_a( + threshold: &Threshold, + signers: &SignersContainer, + build_sat: BuildSatisfaction, + sorted: bool, + secp: &SecpCtx, + ) -> Result, PolicyError> { + if threshold.k() == 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 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 +692,7 @@ impl Policy { let mut policy: Policy = SatisfiableItem::Multisig { keys: parsed_keys, - threshold, + threshold: threshold.k(), } .into(); policy.contribution = contribution; @@ -952,11 +1009,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 +1026,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 +1048,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 +1152,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, )?) } diff --git a/crates/bdk/src/descriptor/template.rs b/crates/bdk/src/descriptor/template.rs index 6f51139acf..84227a70df 100644 --- a/crates/bdk/src/descriptor/template.rs +++ b/crates/bdk/src/descriptor/template.rs @@ -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; @@ -568,7 +569,7 @@ mod test { use bitcoin::bip32::ChildNumber::{self, Hardened}; let xprvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap(); - assert_eq!(Network::Bitcoin, xprvkey.network); + assert_eq!(NetworkKind::Main, xprvkey.network); let xdesc = Bip44(xprvkey, KeychainKind::Internal) .build(Network::Bitcoin) .unwrap(); @@ -582,7 +583,7 @@ mod test { } let tprvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap(); - assert_eq!(Network::Testnet, tprvkey.network); + assert_eq!(NetworkKind::Test, tprvkey.network); let tdesc = Bip44(tprvkey, KeychainKind::Internal) .build(Network::Testnet) .unwrap(); diff --git a/crates/bdk/src/keys/mod.rs b/crates/bdk/src/keys/mod.rs index 75abb3aa67..53dbf5f584 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; @@ -334,7 +334,7 @@ impl ExtendedKey { 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, @@ -353,7 +353,7 @@ impl ExtendedKey { ExtendedKey::Public((xpub, _)) => xpub, }; - xpub.network = network; + xpub.network = network.into(); xpub } } @@ -400,7 +400,7 @@ impl From for ExtendedKey { /// impl DerivableKey for MyCustomKeyType { /// fn into_extended_key(self) -> Result, KeyError> { /// let xprv = bip32::Xpriv { -/// network: self.network, +/// network: self.network.into(), /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, @@ -432,7 +432,7 @@ impl From for ExtendedKey { /// impl DerivableKey for MyCustomKeyType { /// fn into_extended_key(self) -> Result, KeyError> { /// let xprv = bip32::Xpriv { -/// network: bitcoin::Network::Bitcoin, // pick an arbitrary network here +/// network: bitcoin::NetworkKind::Main, // pick an arbitrary network here /// depth: 0, /// parent_fingerprint: bip32::Fingerprint::default(), /// private_key: self.key_data.inner, @@ -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() } @@ -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/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs index 49cb56c0cb..5511c10238 100644 --- a/crates/bdk/src/wallet/coin_selection.rs +++ b/crates/bdk/src/wallet/coin_selection.rs @@ -316,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, diff --git a/crates/bdk/src/wallet/export.rs b/crates/bdk/src/wallet/export.rs index 50c91eb66f..08aa78dbfe 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") diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index 846878823c..ae4831eee6 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -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()); @@ -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) @@ -1632,7 +1633,7 @@ impl Wallet { /// 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()? @@ -1670,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 @@ -1711,7 +1714,7 @@ impl Wallet { derivation_index, confirmation_time, }), - satisfaction_weight, + satisfaction_weight: satisfaction_weight.to_wu() as usize, } } None => { @@ -2042,6 +2045,7 @@ impl Wallet { self.get_descriptor_for_keychain(keychain) .max_weight_to_satisfy() .unwrap() + .to_wu() as usize }) }) .collect() diff --git a/crates/bdk/src/wallet/signer.rs b/crates/bdk/src/wallet/signer.rs index 4610657e2f..492d16b218 100644 --- a/crates/bdk/src/wallet/signer.rs +++ b/crates/bdk/src/wallet/signer.rs @@ -92,7 +92,7 @@ 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, Psbt, PublicKey}; +use bitcoin::{transaction, PrivateKey, Psbt, PublicKey}; use miniscript::descriptor::{ Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, @@ -158,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 @@ -168,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) } } @@ -188,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), } @@ -548,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); } @@ -573,7 +594,7 @@ 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(); @@ -585,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 @@ -932,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); } diff --git a/crates/bdk/src/wallet/tx_builder.rs b/crates/bdk/src/wallet/tx_builder.rs index 4009dab1aa..1f9b3fe2e0 100644 --- a/crates/bdk/src/wallet/tx_builder.rs +++ b/crates/bdk/src/wallet/tx_builder.rs @@ -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, }); } diff --git a/crates/bdk/src/wallet/utils.rs b/crates/bdk/src/wallet/utils.rs index 208a88dfe1..402361134b 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 diff --git a/crates/bdk/tests/common.rs b/crates/bdk/tests/common.rs index 0598e9f1ad..562e7b17e3 100644 --- a/crates/bdk/tests/common.rs +++ b/crates/bdk/tests/common.rs @@ -49,7 +49,7 @@ pub fn get_funded_wallet_with_change( 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(), @@ -99,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/wallet.rs b/crates/bdk/tests/wallet.rs index 68ef541b9b..8a656883d7 100644 --- a/crates/bdk/tests/wallet.rs +++ b/crates/bdk/tests/wallet.rs @@ -39,7 +39,7 @@ fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) -> 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)); @@ -1016,7 +1021,7 @@ 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(); @@ -1063,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() @@ -1164,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::hex::FromHex; let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.get_address(New); @@ -1206,7 +1210,11 @@ 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); @@ -1257,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()); @@ -1282,7 +1290,11 @@ 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().expect("failed to extract tx"); @@ -1299,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))); } @@ -1328,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" @@ -1341,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" @@ -1373,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(), @@ -1389,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(), @@ -1405,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(), @@ -1441,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::hex::FromHex; let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); let addr = wallet.get_address(New); @@ -1471,7 +1497,7 @@ fn test_bump_fee_irreplaceable_tx() { let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1488,7 +1514,7 @@ fn test_bump_fee_confirmed_tx() { let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx( @@ -1515,7 +1541,7 @@ fn test_bump_fee_low_fee_rate() { let feerate = psbt.fee_rate().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1548,7 +1574,7 @@ fn test_bump_fee_low_abs() { let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1571,7 +1597,7 @@ fn test_bump_fee_zero_abs() { let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1597,7 +1623,7 @@ fn test_bump_fee_reduce_change() { let original_fee = check_fee!(wallet, psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1697,7 +1723,7 @@ fn test_bump_fee_reduce_single_recipient() { 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(); @@ -1741,7 +1767,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() { let original_fee = check_fee!(wallet, psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -1798,7 +1824,7 @@ 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() @@ -1808,7 +1834,7 @@ fn test_bump_fee_drain_wallet() { 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(); @@ -1859,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") @@ -1875,7 +1901,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { let psbt = builder.finish().unwrap(); 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(); @@ -1919,7 +1945,7 @@ fn test_bump_fee_add_input() { let psbt = builder.finish().unwrap(); 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(); @@ -1971,7 +1997,7 @@ fn test_bump_fee_absolute_add_input() { let psbt = builder.finish().unwrap(); 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(); @@ -2032,7 +2058,7 @@ fn test_bump_fee_no_change_add_input_and_change() { let original_fee = check_fee!(wallet, psbt); let tx = psbt.extract_tx().expect("failed to extract tx"); - let txid = tx.txid(); + let txid = tx.compute_txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .unwrap(); @@ -2100,7 +2126,7 @@ fn test_bump_fee_add_input_change_dust() { 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(); @@ -2162,7 +2188,7 @@ fn test_bump_fee_force_add_input() { let psbt = builder.finish().unwrap(); 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 } @@ -2223,7 +2249,7 @@ fn test_bump_fee_absolute_force_add_input() { let psbt = builder.finish().unwrap(); 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 @@ -2295,7 +2321,7 @@ fn test_bump_fee_unconfirmed_inputs_only() { ConfirmationTime::Unconfirmed { last_seen: 0 }, ); let mut tx = psbt.extract_tx().expect("failed to extract 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 } @@ -2328,7 +2354,7 @@ fn test_bump_fee_unconfirmed_input() { .enable_rbf(); let psbt = builder.finish().unwrap(); let mut tx = psbt.extract_tx().expect("failed to extract 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 } @@ -3130,7 +3156,11 @@ 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 = @@ -3627,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 @@ -3673,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); } diff --git a/crates/bitcoind_rpc/Cargo.toml b/crates/bitcoind_rpc/Cargo.toml index 387c01af7b..41cde4d6bf 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.31", default-features = false } -bitcoincore-rpc = { version = "0.18" } -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 f2e2a5d59c..9ac8b72c85 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", @@ -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 8328d61746..241d84a732 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.31.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 = "11.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 4c77c160ba..2f3af95e6d 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 c2b83600b1..f88e9650f0 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 79f98fad23..20029abc6a 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 24d06d123c..4513e7d06e 100644 --- a/crates/chain/src/spk_txout_index.rs +++ b/crates/chain/src/spk_txout_index.rs @@ -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) { diff --git a/crates/chain/src/tx_data_traits.rs b/crates/chain/src/tx_data_traits.rs index 8fa17ff904..b3ab3515ef 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 b0759adbf7..4822d6b689 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -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" ); @@ -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, @@ -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/tx_template.rs b/crates/chain/tests/common/tx_template.rs index fab12c1c27..3f9872acbe 100644 --- a/crates/chain/tests/common/tx_template.rs +++ b/crates/chain/tests/common/tx_template.rs @@ -122,14 +122,14 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>( .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 1c8bf398b4..624ad66693 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -50,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) @@ -58,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) @@ -174,7 +174,7 @@ 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 { @@ -326,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!( @@ -360,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!( @@ -397,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, @@ -428,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_spk_txout_index.rs b/crates/chain/tests/test_spk_txout_index.rs index c84bd71949..ce0f51327d 100644 --- a/crates/chain/tests/test_spk_txout_index.rs +++ b/crates/chain/tests/test_spk_txout_index.rs @@ -34,7 +34,7 @@ fn spk_txout_sent_and_received() { lock_time: absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { - txid: tx1.txid(), + txid: tx1.compute_txid(), vout: 0, }, ..Default::default() diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index 74dd271dc5..a1510af901 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -128,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() } ); @@ -147,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() } ); @@ -181,7 +185,9 @@ 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 { @@ -198,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() } ); @@ -233,7 +243,7 @@ fn insert_tx_graph_keeps_track_of_spend() { }; let op = OutPoint { - txid: tx1.txid(), + txid: tx1.compute_txid(), vout: 0, }; @@ -259,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)); } @@ -279,7 +289,9 @@ fn insert_tx_can_retrieve_full_tx_from_graph() { 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) ); } @@ -299,7 +311,7 @@ fn insert_tx_displaces_txouts() { let changeset = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { @@ -312,7 +324,7 @@ fn insert_tx_displaces_txouts() { let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { @@ -326,7 +338,7 @@ fn insert_tx_displaces_txouts() { assert_eq!( tx_graph .get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0 }) .unwrap() @@ -335,7 +347,7 @@ fn insert_tx_displaces_txouts() { ); assert_eq!( tx_graph.get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 1 }), None @@ -359,7 +371,7 @@ fn insert_txout_does_not_displace_tx() { let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { @@ -370,7 +382,7 @@ fn insert_txout_does_not_displace_tx() { let _ = tx_graph.insert_txout( OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0, }, TxOut { @@ -382,7 +394,7 @@ fn insert_txout_does_not_displace_tx() { assert_eq!( tx_graph .get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 0 }) .unwrap() @@ -391,7 +403,7 @@ fn insert_txout_does_not_displace_tx() { ); assert_eq!( tx_graph.get_txout(OutPoint { - txid: tx.txid(), + txid: tx.compute_txid(), vout: 1 }), None @@ -441,14 +453,14 @@ fn test_calculate_fee() { 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() @@ -541,7 +553,7 @@ fn test_walk_ancestors() { // 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::NULL, TxOut::NULL], @@ -551,7 +563,7 @@ fn test_walk_ancestors() { // 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::NULL], @@ -570,7 +582,7 @@ fn test_walk_ancestors() { // 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::NULL], @@ -580,7 +592,7 @@ fn test_walk_ancestors() { // 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::NULL], @@ -591,11 +603,11 @@ 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() }, ], @@ -615,7 +627,7 @@ fn test_walk_ancestors() { // 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::NULL], @@ -626,11 +638,11 @@ 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() }, ], @@ -641,7 +653,7 @@ fn test_walk_ancestors() { // 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::NULL], @@ -663,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()); }); @@ -680,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, @@ -744,15 +756,15 @@ fn test_conflicting_descendants() { // 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::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); @@ -776,7 +788,7 @@ fn test_descendants_no_repeat() { 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::NULL], @@ -787,7 +799,7 @@ 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::NULL], @@ -798,11 +810,11 @@ 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() }, ], @@ -812,7 +824,7 @@ fn test_descendants_no_repeat() { 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::NULL], @@ -846,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); @@ -886,7 +898,7 @@ 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![ @@ -905,7 +917,7 @@ 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![ @@ -929,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, @@ -939,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(), @@ -961,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) @@ -988,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) @@ -1002,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) ); @@ -1015,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()); } @@ -1243,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 8ac440f3e4..aae6458ff8 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 c424a0d7fd..cfffb3793d 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.19" } +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", default-features = false } -electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +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 5501b14956..b1d236441c 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/esplora/Cargo.toml b/crates/esplora/Cargo.toml index d2d890746d..ee7afdd5e8 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.7.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.31.0", optional = true, default-features = false } -miniscript = { version = "11.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", default_features = false } -electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] } +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/file_store/Cargo.toml b/crates/file_store/Cargo.toml index 6c92e3d654..c18fc4ff2e 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/testenv/Cargo.toml b/crates/testenv/Cargo.toml index e52d2a3bcd..04a310694d 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.18" } -bdk_chain = { path = "../chain", version = "0.11", default-features = false } -electrsd = { version= "0.27.1", 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/example-crates/example_cli/src/lib.rs b/example-crates/example_cli/src/lib.rs index cac9f8667b..8c8607ba11 100644 --- a/example-crates/example_cli/src/lib.rs +++ b/example-crates/example_cli/src/lib.rs @@ -633,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/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs index 5a76e60f36..63c7436d59 100644 --- a/example-crates/wallet_electrum/src/main.rs +++ b/example-crates/wallet_electrum/src/main.rs @@ -101,7 +101,7 @@ fn main() -> Result<(), anyhow::Error> { 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 657479b670..9e70c675c4 100644 --- a/example-crates/wallet_esplora_async/src/main.rs +++ b/example-crates/wallet_esplora_async/src/main.rs @@ -92,7 +92,7 @@ async fn main() -> Result<(), anyhow::Error> { 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 307792856d..de03d3f14d 100644 --- a/example-crates/wallet_esplora_blocking/src/main.rs +++ b/example-crates/wallet_esplora_blocking/src/main.rs @@ -92,7 +92,7 @@ fn main() -> Result<(), anyhow::Error> { 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/tmp_plan/src/plan_impls.rs b/nursery/tmp_plan/src/plan_impls.rs index 6b4da3c904..e594dfb73c 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 520290c0ea..f602353a4c 100644 --- a/nursery/tmp_plan/src/requirements.rs +++ b/nursery/tmp_plan/src/requirements.rs @@ -87,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), } } @@ -112,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>( @@ -167,11 +185,11 @@ impl RequiredSignatures { .unwrap(); let msg = Message::from_digest(sighash.to_byte_array()); - let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair); + 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 @@ -210,10 +228,10 @@ impl RequiredSignatures { }; let keypair = Keypair::from_secret_key(&secp, &secret_key.clone()); let msg = Message::from_digest(sighash.to_byte_array()); - let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair); + 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