[dependencies]
log = "0.4"
rand = "^0.8"
-miniscript = { version = "9", features = ["serde"], default-features = false }
-bitcoin = { version = "0.29", features = ["serde", "base64", "rand"], default-features = false }
+miniscript = { version = "10.0.0", features = ["serde"], default-features = false }
+bitcoin = { version = "0.30.0", features = ["serde", "base64", "rand-std"], default-features = false }
serde = { version = "^1.0", features = ["derive"] }
serde_json = { version = "^1.0" }
bdk_chain = { path = "../chain", version = "0.5.0", features = ["miniscript", "serde"], default-features = false }
# Optional dependencies
-hwi = { version = "0.5", optional = true, features = [ "use-miniscript"] }
+hwi = { version = "0.7.0", optional = true, features = [ "miniscript"] }
bip39 = { version = "1.0.1", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
[dev-dependencies]
lazy_static = "1.4"
env_logger = "0.7"
-# Move back to importing from rust-bitcoin once https://github.com/rust-bitcoin/rust-bitcoin/pull/1342 is released
-base64 = "^0.13"
assert_matches = "1.5.0"
[package.metadata.docs.rs]
<!-- use bdk::electrum_client::Client; -->
<!-- use bdk::wallet::AddressIndex::New; -->
-<!-- use base64; -->
+<!-- use bitcoin::base64; -->
<!-- use bdk::bitcoin::consensus::serialize; -->
<!-- use bdk::bitcoin::Network; -->
<!-- ```rust,no_run -->
<!-- use bdk::{Wallet, SignOptions}; -->
-<!-- use base64; -->
+<!-- use bitcoin::base64; -->
<!-- use bdk::bitcoin::consensus::deserialize; -->
<!-- use bdk::bitcoin::Network; -->
// You may not use this file except in accordance with one or both of these
// licenses.
+use bdk::bitcoin::bip32::DerivationPath;
use bdk::bitcoin::secp256k1::Secp256k1;
-use bdk::bitcoin::util::bip32::DerivationPath;
use bdk::bitcoin::Network;
use bdk::descriptor;
use bdk::descriptor::IntoWalletDescriptor;
use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
$crate::impl_top_level_pk!(Pkh, $crate::miniscript::Legacy, $key)
+ .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
.map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Pkh(a), b, c))
});
( wpkh ( $key:expr ) ) => ({
use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
$crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
- .and_then(|(a, b, c)| Ok((a?, b, c)))
+ .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
.map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Wpkh(a), b, c))
});
( sh ( wpkh ( $key:expr ) ) ) => ({
use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, Sh};
$crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
- .and_then(|(a, b, c)| Ok((a?, b, c)))
+ .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
.and_then(|(a, b, c)| Ok((Descriptor::<DescriptorPublicKey>::Sh(Sh::new_wpkh(a.into_inner())?), b, c)))
});
( sh ( $( $minisc:tt )* ) ) => ({
$crate::keys::make_pkh($key, &secp)
});
( after ( $value:expr ) ) => ({
- $crate::impl_leaf_opcode_value!(After, $crate::bitcoin::PackedLockTime($value)) // TODO!! https://github.com/rust-bitcoin/rust-bitcoin/issues/1302
+ $crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value))
});
( older ( $value:expr ) ) => ({
$crate::impl_leaf_opcode_value!(Older, $crate::bitcoin::Sequence($value)) // TODO!!
#[cfg(test)]
mod test {
use alloc::string::ToString;
- use bitcoin::hashes::hex::ToHex;
use bitcoin::secp256k1::Secp256k1;
use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
use miniscript::{Descriptor, Legacy, Segwitv0};
use crate::descriptor::{DescriptorError, DescriptorMeta};
use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
+ use bitcoin::bip32;
use bitcoin::network::constants::Network::{Bitcoin, Regtest, Signet, Testnet};
- use bitcoin::util::bip32;
use bitcoin::PrivateKey;
// test the descriptor!() macro
assert_eq!(desc.is_witness(), is_witness);
assert_eq!(!desc.has_wildcard(), is_fixed);
for i in 0..expected.len() {
- let index = i as u32;
- let child_desc = if !desc.has_wildcard() {
- desc.at_derivation_index(0)
- } else {
- desc.at_derivation_index(index)
- };
+ let child_desc = desc
+ .at_derivation_index(i as u32)
+ .expect("i is not hardened");
let address = child_desc.address(Regtest);
if let Ok(address) = address {
assert_eq!(address.to_string(), *expected.get(i).unwrap());
} else {
let script = child_desc.script_pubkey();
- assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap());
+ assert_eq!(script.to_hex_string(), *expected.get(i).unwrap());
}
}
}
}
#[test]
- #[should_panic(
- expected = "Miniscript(ContextError(CompressedOnly(\"04b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a87378ec38ff91d43e8c2092ebda601780485263da089465619e0358a5c1be7ac91f4\")))"
- )]
+ #[should_panic(expected = "Miniscript(ContextError(UncompressedKeysNotAllowed))")]
fn test_dsl_miniscript_checks() {
let mut uncompressed_pk =
PrivateKey::from_wif("L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6").unwrap();
InvalidDescriptorCharacter(u8),
/// BIP32 error
- Bip32(bitcoin::util::bip32::Error),
+ Bip32(bitcoin::bip32::Error),
/// Error during base58 decoding
- Base58(bitcoin::util::base58::Error),
+ Base58(bitcoin::base58::Error),
/// Key-related error
- Pk(bitcoin::util::key::Error),
+ Pk(bitcoin::key::Error),
/// Miniscript error
Miniscript(miniscript::Error),
/// Hex decoding error
#[cfg(feature = "std")]
impl std::error::Error for Error {}
-impl_error!(bitcoin::util::bip32::Error, Bip32);
-impl_error!(bitcoin::util::base58::Error, Base58);
-impl_error!(bitcoin::util::key::Error, Pk);
+impl_error!(bitcoin::bip32::Error, Bip32);
+impl_error!(bitcoin::base58::Error, Base58);
+impl_error!(bitcoin::key::Error, Pk);
impl_error!(miniscript::Error, Miniscript);
impl_error!(bitcoin::hashes::hex::Error, Hex);
impl_error!(crate::descriptor::policy::PolicyError, Policy);
use alloc::string::String;
use alloc::vec::Vec;
-use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
-use bitcoin::util::{psbt, taproot};
-use bitcoin::{secp256k1, PublicKey, XOnlyPublicKey};
+use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
+use bitcoin::{key::XOnlyPublicKey, secp256k1, PublicKey};
+use bitcoin::{psbt, taproot};
use bitcoin::{Network, TxOut};
use miniscript::descriptor::{
- DefiniteDescriptorKey, DescriptorSecretKey, DescriptorType, InnerXKey, SinglePubKey,
+ DefiniteDescriptorKey, DescriptorMultiXKey, DescriptorSecretKey, DescriptorType,
+ DescriptorXKey, InnerXKey, KeyMap, SinglePubKey, Wildcard,
};
pub use miniscript::{
- descriptor::DescriptorXKey, descriptor::KeyMap, descriptor::Wildcard, Descriptor,
- DescriptorPublicKey, Legacy, Miniscript, ScriptContext, Segwitv0,
+ Descriptor, DescriptorPublicKey, Legacy, Miniscript, ScriptContext, Segwitv0,
};
use miniscript::{ForEachKey, MiniscriptKey, TranslatePk};
/// Alias for the type of maps that represent derivation paths in a [`psbt::Input`] or
/// [`psbt::Output`]
///
-/// [`psbt::Input`]: bitcoin::util::psbt::Input
-/// [`psbt::Output`]: bitcoin::util::psbt::Output
+/// [`psbt::Input`]: bitcoin::psbt::Input
+/// [`psbt::Output`]: bitcoin::psbt::Output
pub type HdKeyPaths = BTreeMap<secp256k1::PublicKey, KeySource>;
/// Alias for the type of maps that represent taproot key origins in a [`psbt::Input`] or
/// [`psbt::Output`]
///
-/// [`psbt::Input`]: bitcoin::util::psbt::Input
-/// [`psbt::Output`]: bitcoin::util::psbt::Output
-pub type TapKeyOrigins = BTreeMap<bitcoin::XOnlyPublicKey, (Vec<taproot::TapLeafHash>, KeySource)>;
+/// [`psbt::Input`]: bitcoin::psbt::Input
+/// [`psbt::Output`]: bitcoin::psbt::Output
+pub type TapKeyOrigins = BTreeMap<XOnlyPublicKey, (Vec<taproot::TapLeafHash>, KeySource)>;
/// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`]
pub trait IntoWalletDescriptor {
network: Network,
}
- impl<'s, 'd>
- miniscript::Translator<DescriptorPublicKey, miniscript::DummyKey, DescriptorError>
+ impl<'s, 'd> miniscript::Translator<DescriptorPublicKey, String, DescriptorError>
for Translator<'s, 'd>
{
- fn pk(
- &mut self,
- pk: &DescriptorPublicKey,
- ) -> Result<miniscript::DummyKey, DescriptorError> {
+ fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<String, DescriptorError> {
let secp = &self.secp;
let (_, _, networks) = if self.descriptor.is_taproot() {
};
if networks.contains(&self.network) {
- Ok(miniscript::DummyKey)
+ Ok(Default::default())
} else {
Err(DescriptorError::Key(KeyError::InvalidNetwork))
}
fn sha256(
&mut self,
_sha256: &<DescriptorPublicKey as MiniscriptKey>::Sha256,
- ) -> Result<miniscript::DummySha256Hash, DescriptorError> {
+ ) -> Result<String, DescriptorError> {
Ok(Default::default())
}
fn hash256(
&mut self,
_hash256: &<DescriptorPublicKey as MiniscriptKey>::Hash256,
- ) -> Result<miniscript::DummyHash256Hash, DescriptorError> {
+ ) -> Result<String, DescriptorError> {
Ok(Default::default())
}
fn ripemd160(
&mut self,
_ripemd160: &<DescriptorPublicKey as MiniscriptKey>::Ripemd160,
- ) -> Result<miniscript::DummyRipemd160Hash, DescriptorError> {
+ ) -> Result<String, DescriptorError> {
Ok(Default::default())
}
fn hash160(
&mut self,
_hash160: &<DescriptorPublicKey as MiniscriptKey>::Hash160,
- ) -> Result<miniscript::DummyHash160Hash, DescriptorError> {
+ ) -> Result<String, DescriptorError> {
Ok(Default::default())
}
}
// check the network for the keys
- self.0.translate_pk(&mut Translator {
+ use miniscript::TranslateErr;
+ match self.0.translate_pk(&mut Translator {
secp,
network,
descriptor: &self.0,
- })?;
+ }) {
+ Ok(_) => {}
+ Err(TranslateErr::TranslatorErr(e)) => return Err(e),
+ Err(TranslateErr::OuterError(e)) => return Err(e.into()),
+ }
Ok(self)
}
}
// fixup the network for keys that need it in the descriptor
- let translated = desc.translate_pk(&mut Translator { network })?;
+ use miniscript::TranslateErr;
+ let translated = match desc.translate_pk(&mut Translator { network }) {
+ Ok(descriptor) => descriptor,
+ Err(TranslateErr::TranslatorErr(e)) => return Err(e),
+ Err(TranslateErr::OuterError(e)) => return Err(e.into()),
+ };
// ...and in the key map
let fixed_keymap = keymap
.into_iter()
fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
}
+impl<T> XKeyUtils for DescriptorMultiXKey<T>
+where
+ T: InnerXKey,
+{
+ fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
+ match self.origin {
+ Some((fingerprint, _)) => fingerprint,
+ None => self.xkey.xkey_fingerprint(secp),
+ }
+ }
+}
+
impl<T> XKeyUtils for DescriptorXKey<T>
where
T: InnerXKey,
false
});
- path_found.map(|path| self.at_derivation_index(path))
+ path_found.map(|path| {
+ self.at_derivation_index(path)
+ .expect("We ignore hardened wildcards")
+ })
}
fn derive_from_hd_keypaths(
return None;
}
- let descriptor = self.at_derivation_index(0);
+ let descriptor = self.at_derivation_index(0).expect("0 is not hardened");
match descriptor.desc_type() {
// TODO: add pk() here
DescriptorType::Pkh
use core::str::FromStr;
use assert_matches::assert_matches;
- use bitcoin::consensus::encode::deserialize;
use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::Secp256k1;
- use bitcoin::util::{bip32, psbt};
- use bitcoin::Script;
+ use bitcoin::ScriptBuf;
+ use bitcoin::{bip32, psbt::Psbt};
use super::*;
use crate::psbt::PsbtUtils;
"wpkh(02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737)",
)
.unwrap();
- let psbt: psbt::PartiallySignedTransaction = deserialize(
+ let psbt = Psbt::deserialize(
&Vec::<u8>::from_hex(
"70736274ff010052010000000162307be8e431fbaff807cdf9cdc3fde44d7402\
11bc8342c31ffd6ec11fe35bcc0100000000ffffffff01328601000000000016\
"pkh([0f056943/44h/0h/0h]tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/10/*)",
)
.unwrap();
- let psbt: psbt::PartiallySignedTransaction = deserialize(
+ let psbt = Psbt::deserialize(
&Vec::<u8>::from_hex(
"70736274ff010053010000000145843b86be54a3cd8c9e38444e1162676c00df\
e7964122a70df491ea12fd67090100000000ffffffff01c19598000000000017\
"wsh(and_v(v:pk(03b6633fef2397a0a9de9d7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14),older(6)))",
)
.unwrap();
- let psbt: psbt::PartiallySignedTransaction = deserialize(
+ let psbt = Psbt::deserialize(
&Vec::<u8>::from_hex(
"70736274ff01005302000000011c8116eea34408ab6529223c9a176606742207\
67a1ff1d46a6e3c4a88243ea6e01000000000600000001109698000000000017\
"sh(and_v(v:pk(021403881a5587297818fcaf17d239cefca22fce84a45b3b1d23e836c4af671dbb),after(630000)))",
)
.unwrap();
- let psbt: psbt::PartiallySignedTransaction = deserialize(
+ let psbt = Psbt::deserialize(
&Vec::<u8>::from_hex(
"70736274ff0100530100000001bc8c13df445dfadcc42afa6dc841f85d22b01d\
a6270ebf981740f4b7b1d800390000000000feffffff01ba9598000000000017\
let (descriptor, _) =
into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet).unwrap();
- let descriptor = descriptor.at_derivation_index(0);
+ let descriptor = descriptor.at_derivation_index(0).unwrap();
- let script = Script::from_str("5321022f533b667e2ea3b36e21961c9fe9dca340fbe0af5210173a83ae0337ab20a57621026bb53a98e810bd0ee61a0ed1164ba6c024786d76554e793e202dc6ce9c78c4ea2102d5b8a7d66a41ffdb6f4c53d61994022e886b4f45001fb158b95c9164d45f8ca3210324b75eead2c1f9c60e8adeb5e7009fec7a29afcdb30d829d82d09562fe8bae8521032d34f8932200833487bd294aa219dcbe000b9f9b3d824799541430009f0fa55121037468f8ea99b6c64788398b5ad25480cad08f4b0d65be54ce3a55fd206b5ae4722103f72d3d96663b0ea99b0aeb0d7f273cab11a8de37885f1dddc8d9112adb87169357ae").unwrap();
+ let script = ScriptBuf::from_hex("5321022f533b667e2ea3b36e21961c9fe9dca340fbe0af5210173a83ae0337ab20a57621026bb53a98e810bd0ee61a0ed1164ba6c024786d76554e793e202dc6ce9c78c4ea2102d5b8a7d66a41ffdb6f4c53d61994022e886b4f45001fb158b95c9164d45f8ca3210324b75eead2c1f9c60e8adeb5e7009fec7a29afcdb30d829d82d09562fe8bae8521032d34f8932200833487bd294aa219dcbe000b9f9b3d824799541430009f0fa55121037468f8ea99b6c64788398b5ad25480cad08f4b0d65be54ce3a55fd206b5ae4722103f72d3d96663b0ea99b0aeb0d7f273cab11a8de37885f1dddc8d9112adb87169357ae").unwrap();
let mut psbt_input = psbt::Input::default();
psbt_input
use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
+use bitcoin::bip32::Fingerprint;
use bitcoin::hashes::{hash160, ripemd160, sha256};
-use bitcoin::util::bip32::Fingerprint;
-use bitcoin::{LockTime, PublicKey, Sequence, XOnlyPublicKey};
+use bitcoin::{absolute, key::XOnlyPublicKey, PublicKey, Sequence};
use miniscript::descriptor::{
DescriptorPublicKey, ShInner, SinglePub, SinglePubKey, SortedMultiVec, WshInner,
use super::checksum::calc_checksum;
use super::error::Error;
use super::XKeyUtils;
-use bitcoin::util::psbt::{Input as PsbtInput, PartiallySignedTransaction as Psbt};
+use bitcoin::psbt::{self, Psbt};
use miniscript::psbt::PsbtInputSatisfier;
/// A unique identifier for a key
..
}) => PkOrF::XOnlyPubkey(*pk),
DescriptorPublicKey::XPub(xpub) => PkOrF::Fingerprint(xpub.root_fingerprint(secp)),
+ DescriptorPublicKey::MultiXPub(multi) => {
+ PkOrF::Fingerprint(multi.root_fingerprint(secp))
+ }
}
}
}
/// Absolute timeclock timestamp
AbsoluteTimelock {
/// The timelock value
- value: LockTime,
+ value: absolute::LockTime,
},
/// Relative timelock locktime
RelativeTimelock {
pub csv: Option<Sequence>,
/// Optional timelock condition
#[serde(skip_serializing_if = "Option::is_none")]
- pub timelock: Option<LockTime>,
+ pub timelock: Option<absolute::LockTime>,
}
impl Condition {
- fn merge_nlocktime(a: LockTime, b: LockTime) -> Result<LockTime, PolicyError> {
+ fn merge_nlocktime(
+ a: absolute::LockTime,
+ b: absolute::LockTime,
+ ) -> Result<absolute::LockTime, PolicyError> {
if !a.is_same_unit(b) {
Err(PolicyError::MixedTimelockUnits)
} else if a > b {
..
}) => pk.to_pubkeyhash(SigType::Ecdsa).into(),
DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint(secp).into(),
+ DescriptorPublicKey::MultiXPub(xpub) => xpub.root_fingerprint(secp).into(),
}
}
fn generic_sig_in_psbt<
// C is for "check", it's a closure we use to *check* if a psbt input contains the signature
// for a specific key
- C: Fn(&PsbtInput, &SinglePubKey) -> bool,
+ C: Fn(&psbt::Input, &SinglePubKey) -> bool,
// E is for "extract", it extracts a key from the bip32 derivations found in the psbt input
- E: Fn(&PsbtInput, Fingerprint) -> Option<SinglePubKey>,
+ E: Fn(&psbt::Input, Fingerprint) -> Option<SinglePubKey>,
>(
psbt: &Psbt,
key: &DescriptorPublicKey,
None => false,
}
}
+ DescriptorPublicKey::MultiXPub(xpub) => {
+ //TODO check actual derivation matches
+ match extract(input, xpub.root_fingerprint(secp)) {
+ Some(pubkey) => check(input, &pubkey),
+ None => false,
+ }
+ }
})
}
}
Terminal::After(value) => {
let mut policy: Policy = SatisfiableItem::AbsoluteTimelock {
- value: value.into(),
+ value: (*value).into(),
}
.into();
policy.contribution = Satisfaction::Complete {
condition: Condition {
- timelock: Some(value.into()),
+ timelock: Some((*value).into()),
csv: None,
},
};
{
let after = After::new(Some(current_height), false);
let after_sat =
- Satisfier::<bitcoin::PublicKey>::check_after(&after, value.into());
+ Satisfier::<bitcoin::PublicKey>::check_after(&after, (*value).into());
let inputs_sat = psbt_inputs_sat(psbt).all(|sat| {
- Satisfier::<bitcoin::PublicKey>::check_after(&sat, value.into())
+ Satisfier::<bitcoin::PublicKey>::check_after(&sat, (*value).into())
});
if after_sat && inputs_sat {
policy.satisfaction = policy.contribution.clone();
use crate::wallet::signer::SignersContainer;
use alloc::{string::ToString, sync::Arc};
use assert_matches::assert_matches;
+ use bitcoin::bip32;
use bitcoin::secp256k1::Secp256k1;
- use bitcoin::util::bip32;
use bitcoin::Network;
use core::str::FromStr;
let addr = wallet_desc
.at_derivation_index(0)
+ .unwrap()
.address(Network::Testnet)
.unwrap();
assert_eq!(
let addr = wallet_desc
.at_derivation_index(0)
+ .unwrap()
.address(Network::Testnet)
.unwrap();
assert_eq!(
//! This module contains the definition of various common script templates that are ready to be
//! used. See the documentation of each template for an example.
-use bitcoin::util::bip32;
+use bitcoin::bip32;
use bitcoin::Network;
use miniscript::{Legacy, Segwitv0, Tap};
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip44;
///
-/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44(key.clone(), KeychainKind::External),
/// Some(Bip44(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip44Public;
///
-/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
-/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
+/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip44Public(key, fingerprint, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip49;
///
-/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49(key.clone(), KeychainKind::External),
/// Some(Bip49(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip49Public;
///
-/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
-/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
+/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip49Public(key, fingerprint, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip84;
///
-/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84(key.clone(), KeychainKind::External),
/// Some(Bip84(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip84Public;
///
-/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
-/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip84Public(key, fingerprint, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip86;
///
-/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86(key.clone(), KeychainKind::External),
/// Some(Bip86(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip86Public;
///
-/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
-/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip86Public(key, fingerprint, KeychainKind::Internal)),
// BIP44 `pkh(key/44'/{0,1}'/0'/{0,1}/*)`
#[test]
fn test_bip44_template_cointype() {
- use bitcoin::util::bip32::ChildNumber::{self, Hardened};
+ use bitcoin::bip32::ChildNumber::{self, Hardened};
- let xprvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
+ let xprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
assert_eq!(Network::Bitcoin, xprvkey.network);
let xdesc = Bip44(xprvkey, KeychainKind::Internal)
.build(Network::Bitcoin)
.unwrap();
if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 {
- let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().into();
+ let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
let purpose = path.get(0).unwrap();
assert_matches!(purpose, Hardened { index: 44 });
let coin_type = path.get(1).unwrap();
assert_matches!(coin_type, Hardened { index: 0 });
}
- let tprvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let tprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
assert_eq!(Network::Testnet, tprvkey.network);
let tdesc = Bip44(tprvkey, KeychainKind::Internal)
.build(Network::Testnet)
.unwrap();
if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 {
- let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().into();
+ let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
let purpose = path.get(0).unwrap();
assert_matches!(purpose, Hardened { index: 44 });
let coin_type = path.get(1).unwrap();
for i in 0..expected.len() {
let index = i as u32;
let child_desc = if !desc.has_wildcard() {
- desc.at_derivation_index(0)
+ desc.at_derivation_index(0).unwrap()
} else {
- desc.at_derivation_index(index)
+ desc.at_derivation_index(index).unwrap()
};
let address = child_desc.address(network).unwrap();
assert_eq!(address.to_string(), *expected.get(i).unwrap());
// BIP44 `pkh(key/44'/0'/0'/{0,1}/*)`
#[test]
fn test_bip44_template() {
- let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip44(prvkey, KeychainKind::External).build(Network::Bitcoin),
false,
// BIP44 public `pkh(key/{0,1}/*)`
#[test]
fn test_bip44_public_template() {
- let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
- let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+ let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
+ let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip44Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
false,
// BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))`
#[test]
fn test_bip49_template() {
- let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip49(prvkey, KeychainKind::External).build(Network::Bitcoin),
true,
// BIP49 public `sh(wpkh(key/{0,1}/*))`
#[test]
fn test_bip49_public_template() {
- let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
- let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+ let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
+ let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip49Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
true,
// BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)`
#[test]
fn test_bip84_template() {
- let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip84(prvkey, KeychainKind::External).build(Network::Bitcoin),
true,
// BIP84 public `wpkh(key/{0,1}/*)`
#[test]
fn test_bip84_public_template() {
- let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
- let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+ let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
+ let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip84Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
true,
// Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
#[test]
fn test_bip86_template() {
- let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap();
+ let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap();
check(
Bip86(prvkey, KeychainKind::External).build(Network::Bitcoin),
false,
// Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
#[test]
fn test_bip86_public_template() {
- let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap();
- let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("73c5da0a").unwrap();
+ let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap();
+ let fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap();
check(
Bip86Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
false,
/// Miniscript PSBT error
MiniscriptPsbt(MiniscriptPsbtError),
/// BIP32 error
- Bip32(bitcoin::util::bip32::Error),
+ Bip32(bitcoin::bip32::Error),
/// Partially signed bitcoin transaction error
- Psbt(bitcoin::util::psbt::Error),
+ Psbt(bitcoin::psbt::Error),
}
/// Errors returned by miniscript when updating inconsistent PSBTs
impl_error!(miniscript::Error, Miniscript);
impl_error!(MiniscriptPsbtError, MiniscriptPsbt);
-impl_error!(bitcoin::util::bip32::Error, Bip32);
-impl_error!(bitcoin::util::psbt::Error, Psbt);
+impl_error!(bitcoin::bip32::Error, Bip32);
+impl_error!(bitcoin::psbt::Error, Psbt);
// something that should be fairly simple to re-implement.
use alloc::string::String;
-use bitcoin::util::bip32;
+use bitcoin::bip32;
use bitcoin::Network;
use miniscript::ScriptContext;
(word_count, language): Self::Options,
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
- let entropy = &entropy.as_ref()[..(word_count as usize / 8)];
+ let entropy = &entropy[..(word_count as usize / 8)];
let mnemonic = Mnemonic::from_entropy_in(language, entropy)?;
Ok(GeneratedKey::new(mnemonic, any_network()))
use alloc::string::ToString;
use core::str::FromStr;
- use bitcoin::util::bip32;
+ use bitcoin::bip32;
use bip39::{Language, Mnemonic};
use bitcoin::secp256k1::{self, Secp256k1, Signing};
-use bitcoin::util::bip32;
-use bitcoin::{Network, PrivateKey, PublicKey, XOnlyPublicKey};
+use bitcoin::bip32;
+use bitcoin::{key::XOnlyPublicKey, Network, PrivateKey, PublicKey};
use miniscript::descriptor::{Descriptor, DescriptorXKey, Wildcard};
pub use miniscript::descriptor::{
///
/// ```
/// use bdk::bitcoin;
-/// use bdk::bitcoin::util::bip32;
+/// use bdk::bitcoin::bip32;
/// use bdk::keys::{DerivableKey, ExtendedKey, KeyError, ScriptContext};
///
/// struct MyCustomKeyType {
/// key_data: bitcoin::PrivateKey,
-/// chain_code: Vec<u8>,
+/// chain_code: [u8; 32],
/// network: bitcoin::Network,
/// }
///
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
/// private_key: self.key_data.inner,
-/// chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+/// chain_code: bip32::ChainCode::from(&self.chain_code),
/// child_number: bip32::ChildNumber::Normal { index: 0 },
/// };
///
///
/// ```
/// use bdk::bitcoin;
-/// use bdk::bitcoin::util::bip32;
+/// use bdk::bitcoin::bip32;
/// use bdk::keys::{
/// any_network, DerivableKey, DescriptorKey, ExtendedKey, KeyError, ScriptContext,
/// };
///
/// struct MyCustomKeyType {
/// key_data: bitcoin::PrivateKey,
-/// chain_code: Vec<u8>,
+/// chain_code: [u8; 32],
/// }
///
/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
/// private_key: self.key_data.inner,
-/// chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+/// chain_code: bip32::ChainCode::from(&self.chain_code),
/// child_number: bip32::ChildNumber::Normal { index: 0 },
/// };
///
Message(String),
/// BIP32 error
- Bip32(bitcoin::util::bip32::Error),
+ Bip32(bitcoin::bip32::Error),
/// Miniscript error
Miniscript(miniscript::Error),
}
impl_error!(miniscript::Error, Miniscript, KeyError);
-impl_error!(bitcoin::util::bip32::Error, Bip32, KeyError);
+impl_error!(bitcoin::bip32::Error, Bip32, KeyError);
impl fmt::Display for KeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(test)]
pub mod test {
- use bitcoin::util::bip32;
+ use bitcoin::bip32;
use super::*;
use crate::FeeRate;
use alloc::vec::Vec;
-use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+use bitcoin::psbt::PartiallySignedTransaction as Psbt;
use bitcoin::TxOut;
// TODO upstream the functions here to `rust-bitcoin`?
use bdk_chain::ConfirmationTime;
use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
-use bitcoin::{hash_types::Txid, util::psbt};
+use bitcoin::{hash_types::Txid, psbt, Weight};
use serde::{Deserialize, Serialize};
}
/// Calculate fee rate from `fee` and weight units (`wu`).
- pub fn from_wu(fee: u64, wu: usize) -> FeeRate {
- Self::from_vb(fee, wu.vbytes())
+ pub fn from_wu(fee: u64, wu: Weight) -> FeeRate {
+ Self::from_vb(fee, wu.to_vbytes_ceil() as usize)
}
/// Calculate fee rate from `fee` and `vbytes`.
}
/// Calculate absolute fee in Satoshis using size in weight units.
- pub fn fee_wu(&self, wu: usize) -> u64 {
- self.fee_vb(wu.vbytes())
+ pub fn fee_wu(&self, wu: Weight) -> u64 {
+ self.fee_vb(wu.to_vbytes_ceil() as usize)
}
/// Calculate absolute fee in Satoshis using size in virtual bytes.
//! &self,
//! required_utxos: Vec<WeightedUtxo>,
//! optional_utxos: Vec<WeightedUtxo>,
-//! fee_rate: FeeRate,
+//! fee_rate: bdk::FeeRate,
//! target_amount: u64,
//! drain_script: &Script,
//! ) -> Result<CoinSelectionResult, bdk::Error> {
//! let mut selected_amount = 0;
-//! let mut additional_weight = 0;
+//! let mut additional_weight = Weight::ZERO;
//! let all_utxos_selected = required_utxos
//! .into_iter()
//! .chain(optional_utxos)
//! (&mut selected_amount, &mut additional_weight),
//! |(selected_amount, additional_weight), weighted_utxo| {
//! **selected_amount += weighted_utxo.utxo.txout().value;
-//! **additional_weight += TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight;
+//! **additional_weight += Weight::from_wu(
+//! (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64,
+//! );
//! Some(weighted_utxo.utxo)
//! },
//! )
//! # let mut wallet = doctest_wallet!();
//! // create wallet, sync, ...
//!
-//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
+//! .unwrap()
+//! .require_network(Network::Testnet)
+//! .unwrap();
//! let (psbt, details) = {
//! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
//! builder.add_recipient(to_address.script_pubkey(), 50_000);
use alloc::vec::Vec;
use bitcoin::consensus::encode::serialize;
-use bitcoin::Script;
+use bitcoin::{Script, Weight};
use core::convert::TryInto;
use rand::seq::SliceRandom;
(&mut selected_amount, &mut fee_amount),
|(selected_amount, fee_amount), (must_use, weighted_utxo)| {
if must_use || **selected_amount < target_amount + **fee_amount {
- **fee_amount +=
- fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight);
+ **fee_amount += fee_rate.fee_wu(Weight::from_wu(
+ (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64,
+ ));
**selected_amount += weighted_utxo.utxo.txout().value;
log::debug!(
impl OutputGroup {
fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self {
- let fee = fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight);
+ let fee = fee_rate.fee_wu(Weight::from_wu(
+ (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as u64,
+ ));
let effective_value = weighted_utxo.utxo.txout().value as i64 - fee as i64;
OutputGroup {
weighted_utxo,
use core::str::FromStr;
use bdk_chain::ConfirmationTime;
- use bitcoin::{OutPoint, Script, TxOut};
+ use bitcoin::{OutPoint, ScriptBuf, TxOut};
use super::*;
use crate::types::*;
outpoint,
txout: TxOut {
value,
- script_pubkey: Script::new(),
+ script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
is_spent: false,
.unwrap(),
txout: TxOut {
value: rng.gen_range(0..200000000),
- script_pubkey: Script::new(),
+ script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
is_spent: false,
.unwrap(),
txout: TxOut {
value: utxos_value,
- script_pubkey: Script::new(),
+ script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
is_spent: false,
#[test]
fn test_largest_first_coin_selection_success() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 250_000 + FEE_AMOUNT;
let result = LargestFirstCoinSelection::default()
#[test]
fn test_largest_first_coin_selection_use_all() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
let result = LargestFirstCoinSelection::default()
#[test]
fn test_largest_first_coin_selection_use_only_necessary() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
let result = LargestFirstCoinSelection::default()
#[should_panic(expected = "InsufficientFunds")]
fn test_largest_first_coin_selection_insufficient_funds() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 500_000 + FEE_AMOUNT;
LargestFirstCoinSelection::default()
#[should_panic(expected = "InsufficientFunds")]
fn test_largest_first_coin_selection_insufficient_funds_high_fees() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 250_000 + FEE_AMOUNT;
LargestFirstCoinSelection::default()
#[test]
fn test_oldest_first_coin_selection_success() {
let utxos = get_oldest_first_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 180_000 + FEE_AMOUNT;
let result = OldestFirstCoinSelection::default()
#[test]
fn test_oldest_first_coin_selection_use_all() {
let utxos = get_oldest_first_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
let result = OldestFirstCoinSelection::default()
#[test]
fn test_oldest_first_coin_selection_use_only_necessary() {
let utxos = get_oldest_first_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
let result = OldestFirstCoinSelection::default()
#[should_panic(expected = "InsufficientFunds")]
fn test_oldest_first_coin_selection_insufficient_funds() {
let utxos = get_oldest_first_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 600_000 + FEE_AMOUNT;
OldestFirstCoinSelection::default()
let utxos = get_oldest_first_test_utxos();
let target_amount: u64 = utxos.iter().map(|wu| wu.utxo.txout().value).sum::<u64>() - 50;
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
OldestFirstCoinSelection::default()
.coin_select(
// select three outputs
let utxos = generate_same_value_utxos(100_000, 20);
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 250_000 + FEE_AMOUNT;
#[test]
fn test_bnb_coin_selection_required_are_enough() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
let result = BranchAndBoundCoinSelection::default()
#[test]
fn test_bnb_coin_selection_optional_are_enough() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 299756 + FEE_AMOUNT;
let result = BranchAndBoundCoinSelection::default()
assert_eq!(amount, 100_000);
let amount: u64 = optional.iter().map(|u| u.utxo.txout().value).sum();
assert!(amount > 150_000);
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 150_000 + FEE_AMOUNT;
#[should_panic(expected = "InsufficientFunds")]
fn test_bnb_coin_selection_insufficient_funds() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 500_000 + FEE_AMOUNT;
BranchAndBoundCoinSelection::default()
#[should_panic(expected = "InsufficientFunds")]
fn test_bnb_coin_selection_insufficient_funds_high_fees() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 250_000 + FEE_AMOUNT;
BranchAndBoundCoinSelection::default()
#[test]
fn test_bnb_coin_selection_check_fee_rate() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 99932; // first utxo's effective value
let result = BranchAndBoundCoinSelection::new(0)
for _i in 0..200 {
let mut optional_utxos = generate_random_utxos(&mut rng, 16);
let target_amount = sum_random_utxos(&mut rng, &mut optional_utxos);
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let result = BranchAndBoundCoinSelection::new(0)
.coin_select(
vec![],
let size_of_change = 31;
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let target_amount = 20_000 + FEE_AMOUNT;
BranchAndBoundCoinSelection::new(size_of_change)
.bnb(
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
let target_amount = 20_000 + FEE_AMOUNT;
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
BranchAndBoundCoinSelection::new(size_of_change)
.bnb(
// cost_of_change + 5.
let target_amount = 2 * 50_000 - 2 * 67 - cost_of_change.ceil() as i64 + 5;
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let result = BranchAndBoundCoinSelection::new(size_of_change)
.bnb(
let target_amount =
optional_utxos[3].effective_value + optional_utxos[23].effective_value;
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let result = BranchAndBoundCoinSelection::new(0)
.bnb(
.map(|u| OutputGroup::new(u, fee_rate))
.collect();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let result = BranchAndBoundCoinSelection::default().single_random_draw(
vec![],
#[test]
fn test_bnb_exclude_negative_effective_value() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let selection = BranchAndBoundCoinSelection::default().coin_select(
vec![],
#[test]
fn test_bnb_include_negative_effective_value_when_required() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let (required, optional) = utxos
.into_iter()
#[test]
fn test_bnb_sum_of_effective_value_negative() {
let utxos = get_test_utxos();
- let drain_script = Script::default();
+ let drain_script = ScriptBuf::default();
let selection = BranchAndBoundCoinSelection::default().coin_select(
utxos,
input: vec![],
output: vec![],
version: 0,
- lock_time: bitcoin::PackedLockTime::ZERO,
+ lock_time: bitcoin::absolute::LockTime::ZERO,
};
wallet
.insert_checkpoint(BlockId {
//! # use bdk::wallet::hardwaresigner::HWISigner;
//! # use bdk::wallet::AddressIndex::New;
//! # use bdk::{FeeRate, KeychainKind, SignOptions, Wallet};
-//! # use hwi::{types::HWIChain, HWIClient};
+//! # use hwi::HWIClient;
//! # use std::sync::Arc;
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! panic!("No devices found!");
//! }
//! let first_device = devices.remove(0)?;
-//! let custom_signer = HWISigner::from_device(&first_device, HWIChain::Test)?;
+//! let custom_signer = HWISigner::from_device(&first_device, Network::Testnet.into())?;
//!
//! # let mut wallet = Wallet::new_no_persist(
//! # "",
//! # }
//! ```
+use bitcoin::bip32::Fingerprint;
use bitcoin::psbt::PartiallySignedTransaction;
use bitcoin::secp256k1::{All, Secp256k1};
-use bitcoin::util::bip32::Fingerprint;
use hwi::error::Error;
use hwi::types::{HWIChain, HWIDevice};
IndexedTxGraph, Persist, PersistBackend,
};
use bitcoin::consensus::encode::serialize;
+use bitcoin::psbt;
use bitcoin::secp256k1::Secp256k1;
-use bitcoin::util::psbt;
+use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::{
- Address, EcdsaSighashType, LockTime, Network, OutPoint, SchnorrSighashType, Script, Sequence,
- Transaction, TxOut, Txid, Witness,
+ absolute, Address, Network, OutPoint, Script, ScriptBuf, Sequence, Transaction, TxOut, Txid,
+ Weight, Witness,
};
use core::fmt;
use core::ops::Deref;
let (index, spk, additions) = match address_index {
AddressIndex::New => {
let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain);
- (index, spk.clone(), Some(index_additions))
+ (index, spk.into(), Some(index_additions))
}
AddressIndex::LastUnused => {
let ((index, spk), index_additions) = txout_index.next_unused_spk(&keychain);
- (index, spk.clone(), Some(index_additions))
+ (index, spk.into(), Some(index_additions))
}
AddressIndex::Peek(index) => {
let (index, spk) = txout_index
/// script pubkeys the wallet is storing internally).
pub fn spks_of_all_keychains(
&self,
- ) -> BTreeMap<KeychainKind, impl Iterator<Item = (u32, Script)> + Clone> {
+ ) -> BTreeMap<KeychainKind, impl Iterator<Item = (u32, ScriptBuf)> + Clone> {
self.indexed_graph.index.spks_of_all_keychains()
}
pub fn spks_of_keychain(
&self,
keychain: KeychainKind,
- ) -> impl Iterator<Item = (u32, Script)> + Clone {
+ ) -> impl Iterator<Item = (u32, ScriptBuf)> + Clone {
self.indexed_graph.index.spks_of_keychain(&keychain)
}
/// # use bdk::*;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
- /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let (psbt, details) = {
/// let mut builder = wallet.build_tx();
/// builder
None => self
.chain
.tip()
- .map(|cp| LockTime::from_height(cp.height()).expect("Invalid height")),
+ .map(|cp| absolute::LockTime::from_height(cp.height()).expect("Invalid height")),
h => h,
};
// Fee sniping can be partially prevented by setting the timelock
// to current_height. If we don't know the current_height,
// we default to 0.
- let fee_sniping_height = current_height.unwrap_or(LockTime::ZERO);
+ let fee_sniping_height = current_height.unwrap_or(absolute::LockTime::ZERO);
// We choose the biggest between the required nlocktime and the fee sniping
// height
// No requirement, just use the fee_sniping_height
None => fee_sniping_height,
// There's a block-based requirement, but the value is lower than the fee_sniping_height
- Some(value @ LockTime::Blocks(_)) if value < fee_sniping_height => fee_sniping_height,
+ Some(value @ absolute::LockTime::Blocks(_)) if value < fee_sniping_height => fee_sniping_height,
// There's a time-based requirement or a block-based requirement greater
// than the fee_sniping_height use that value
Some(value) => value,
let n_sequence = match (params.rbf, requirements.csv) {
// No RBF or CSV but there's an nLockTime, so the nSequence cannot be final
- (None, None) if lock_time != LockTime::ZERO => Sequence::ENABLE_LOCKTIME_NO_RBF,
+ (None, None) if lock_time != absolute::LockTime::ZERO => {
+ Sequence::ENABLE_LOCKTIME_NO_RBF
+ }
// No RBF, CSV or nLockTime, make the transaction final
(None, None) => Sequence::MAX,
let mut tx = Transaction {
version,
- lock_time: lock_time.into(),
+ lock_time,
input: vec![],
output: vec![],
};
// end up with a transaction with a slightly higher fee rate than the requested one.
// If, instead, we undershoot, we may end up with a feerate lower than the requested one
// - we might come up with non broadcastable txs!
- fee_amount += fee_rate.fee_wu(2);
+ fee_amount += fee_rate.fee_wu(Weight::from_wu(2));
if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeAllowed
&& internal_descriptor.is_none()
params.drain_wallet,
params.manually_selected_only,
params.bumping_fee.is_some(), // we mandate confirmed transactions if we're bumping the fee
- current_height.map(LockTime::to_consensus_u32),
+ current_height.map(absolute::LockTime::to_consensus_u32),
);
// get drain script
let change_keychain = self.map_keychain(KeychainKind::Internal);
let ((index, spk), index_additions) =
self.indexed_graph.index.next_unused_spk(&change_keychain);
- let spk = spk.clone();
+ let spk = spk.into();
self.indexed_graph.index.mark_used(&change_keychain, index);
self.persist
.stage(ChangeSet::from(IndexedAdditions::from(index_additions)));
.iter()
.map(|u| bitcoin::TxIn {
previous_output: u.outpoint(),
- script_sig: Script::default(),
+ script_sig: ScriptBuf::default(),
sequence: n_sequence,
witness: Witness::new(),
})
/// # use bdk::*;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
- /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let (mut psbt, _) = {
/// let mut builder = wallet.build_tx();
/// builder
/// let (mut psbt, _) = {
/// let mut builder = wallet.build_fee_bump(tx.txid())?;
/// builder
- /// .fee_rate(FeeRate::from_sat_per_vb(5.0));
+ /// .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0));
/// builder.finish()?
/// };
///
let weighted_utxo = match txout_index.index_of_spk(&txout.script_pubkey) {
Some(&(keychain, derivation_index)) => {
+ #[allow(deprecated)]
let satisfaction_weight = self
.get_descriptor_for_keychain(keychain)
.max_satisfaction_weight()
/// # use bdk::*;
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
/// # let mut wallet = doctest_wallet!();
- /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let (mut psbt, _) = {
/// let mut builder = wallet.build_tx();
/// builder.add_recipient(to_address.script_pubkey(), 50_000);
&& !psbt.inputs.iter().all(|i| {
i.sighash_type.is_none()
|| i.sighash_type == Some(EcdsaSighashType::All.into())
- || i.sighash_type == Some(SchnorrSighashType::All.into())
- || i.sighash_type == Some(SchnorrSighashType::Default.into())
+ || i.sighash_type == Some(TapSighashType::All.into())
+ || i.sighash_type == Some(TapSighashType::Default.into())
})
{
return Err(Error::Signer(signer::SignerError::NonStandardSighash));
.index
.index_of_spk(&txout.script_pubkey)?;
let descriptor = self.get_descriptor_for_keychain(keychain);
- Some(descriptor.at_derivation_index(child))
+ descriptor.at_derivation_index(child).ok()
}
fn get_available_utxos(&self) -> Vec<(LocalUtxo, usize)> {
self.list_unspent()
.map(|utxo| {
let keychain = utxo.keychain;
+ #[allow(deprecated)]
(
utxo,
self.get_descriptor_for_keychain(keychain)
};
let desc = self.get_descriptor_for_keychain(keychain);
- let derived_descriptor = desc.at_derivation_index(child);
+ let derived_descriptor = desc
+ .at_derivation_index(child)
+ .expect("child can't be hardened");
psbt_input
.update_with_descriptor_unchecked(&derived_descriptor)
);
let desc = self.get_descriptor_for_keychain(keychain);
- let desc = desc.at_derivation_index(child);
+ let desc = desc
+ .at_derivation_index(child)
+ .expect("child can't be hardened");
if is_input {
psbt.update_input_with_descriptor(index, &desc)
/// Macro for getting a wallet for use in a doctest
macro_rules! doctest_wallet {
() => {{
- use $crate::bitcoin::{BlockHash, Transaction, PackedLockTime, TxOut, Network, hashes::Hash};
+ use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
use $crate::chain::{ConfirmationTime, BlockId};
use $crate::wallet::{AddressIndex, Wallet};
let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
let address = wallet.get_address(AddressIndex::New).address;
let tx = Transaction {
version: 1,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
value: 500_000,
//! # use core::str::FromStr;
//! # use bitcoin::secp256k1::{Secp256k1, All};
//! # use bitcoin::*;
-//! # use bitcoin::util::psbt;
+//! # use bitcoin::psbt;
//! # use bdk::signer::*;
//! # use bdk::*;
//! # #[derive(Debug)]
use core::fmt;
use core::ops::{Bound::Included, Deref};
-use bitcoin::blockdata::opcodes;
-use bitcoin::blockdata::script::Builder as ScriptBuilder;
-use bitcoin::hashes::{hash160, Hash};
+use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
+use bitcoin::hashes::hash160;
use bitcoin::secp256k1::Message;
-use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
-use bitcoin::util::{ecdsa, psbt, schnorr, sighash, taproot};
-use bitcoin::{secp256k1, XOnlyPublicKey};
-use bitcoin::{EcdsaSighashType, PrivateKey, PublicKey, SchnorrSighashType, Script};
+use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType};
+use bitcoin::{ecdsa, psbt, sighash, taproot};
+use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1};
+use bitcoin::{PrivateKey, PublicKey};
use miniscript::descriptor::{
- Descriptor, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey, KeyMap, SinglePriv,
- SinglePubKey,
+ Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
+ InnerXKey, KeyMap, SinglePriv, SinglePubKey,
};
use miniscript::{Legacy, Segwitv0, SigType, Tap, ToPublicKey};
}
/// Signing error
-#[derive(Debug, PartialEq, Eq, Clone)]
+#[derive(Debug)]
pub enum SignerError {
/// The private key is missing for the required public key
MissingKey,
}
}
+fn multikey_to_xkeys<K: InnerXKey + Clone>(
+ multikey: DescriptorMultiXKey<K>,
+) -> Vec<DescriptorXKey<K>> {
+ multikey
+ .derivation_paths
+ .into_paths()
+ .into_iter()
+ .map(|derivation_path| DescriptorXKey {
+ origin: multikey.origin.clone(),
+ xkey: multikey.xkey.clone(),
+ derivation_path,
+ wildcard: multikey.wildcard,
+ })
+ .collect()
+}
+
+impl SignerCommon for SignerWrapper<DescriptorMultiXKey<ExtendedPrivKey>> {
+ fn id(&self, secp: &SecpCtx) -> SignerId {
+ SignerId::from(self.root_fingerprint(secp))
+ }
+
+ fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
+ Some(DescriptorSecretKey::MultiXPrv(self.signer.clone()))
+ }
+}
+
+impl InputSigner for SignerWrapper<DescriptorMultiXKey<ExtendedPrivKey>> {
+ fn sign_input(
+ &self,
+ psbt: &mut psbt::PartiallySignedTransaction,
+ input_index: usize,
+ sign_options: &SignOptions,
+ secp: &SecpCtx,
+ ) -> Result<(), SignerError> {
+ let xkeys = multikey_to_xkeys(self.signer.clone());
+ for xkey in xkeys {
+ SignerWrapper::new(xkey, self.ctx).sign_input(psbt, input_index, sign_options, secp)?
+ }
+ Ok(())
+ }
+}
+
impl SignerCommon for SignerWrapper<PrivateKey> {
fn id(&self, secp: &SecpCtx) -> SignerId {
SignerId::from(self.public_key(secp).to_pubkeyhash(SigType::Ecdsa))
}
let (hash, hash_ty) = match self.ctx {
- SignerContext::Segwitv0 => Segwitv0::sighash(psbt, input_index, ())?,
- SignerContext::Legacy => Legacy::sighash(psbt, input_index, ())?,
+ SignerContext::Segwitv0 => {
+ let (h, t) = Segwitv0::sighash(psbt, input_index, ())?;
+ let h = h.to_raw_hash();
+ (h, t)
+ }
+ SignerContext::Legacy => {
+ let (h, t) = Legacy::sighash(psbt, input_index, ())?;
+ let h = h.to_raw_hash();
+ (h, t)
+ }
_ => return Ok(()), // handled above
};
sign_psbt_ecdsa(
secret_key: &secp256k1::SecretKey,
pubkey: PublicKey,
psbt_input: &mut psbt::Input,
- hash: bitcoin::Sighash,
+ hash: impl bitcoin::hashes::Hash + bitcoin::secp256k1::ThirtyTwoByteHash,
hash_ty: EcdsaSighashType,
secp: &SecpCtx,
allow_grinding: bool,
) {
- let msg = &Message::from_slice(&hash.into_inner()[..]).unwrap();
+ let msg = &Message::from(hash);
let sig = if allow_grinding {
secp.sign_ecdsa_low_r(msg, secret_key)
} else {
secp.verify_ecdsa(msg, &sig, &pubkey.inner)
.expect("invalid or corrupted ecdsa signature");
- let final_signature = ecdsa::EcdsaSig { sig, hash_ty };
+ let final_signature = ecdsa::Signature { sig, hash_ty };
psbt_input.partial_sigs.insert(pubkey, final_signature);
}
pubkey: XOnlyPublicKey,
leaf_hash: Option<taproot::TapLeafHash>,
psbt_input: &mut psbt::Input,
- hash: taproot::TapSighashHash,
- hash_ty: SchnorrSighashType,
+ hash: TapSighash,
+ hash_ty: TapSighashType,
secp: &SecpCtx,
) {
- use schnorr::TapTweak;
-
let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
let keypair = match leaf_hash {
None => keypair
Some(_) => keypair, // no tweak for script spend
};
- let msg = &Message::from_slice(&hash.into_inner()[..]).unwrap();
+ let msg = &Message::from(hash);
let sig = secp.sign_schnorr(msg, &keypair);
secp.verify_schnorr(&sig, msg, &XOnlyPublicKey::from_keypair(&keypair).0)
.expect("invalid or corrupted schnorr signature");
- let final_signature = schnorr::SchnorrSig { sig, hash_ty };
+ let final_signature = taproot::Signature { sig, hash_ty };
if let Some(lh) = leaf_hash {
psbt_input
SignerOrdering::default(),
Arc::new(SignerWrapper::new(xprv, ctx)),
),
+ DescriptorSecretKey::MultiXPrv(xprv) => container.add_external(
+ SignerId::from(xprv.root_fingerprint(secp)),
+ SignerOrdering::default(),
+ Arc::new(SignerWrapper::new(xprv, ctx)),
+ ),
};
}
impl ComputeSighash for Legacy {
type Extra = ();
- type Sighash = bitcoin::Sighash;
+ type Sighash = sighash::LegacySighash;
type SighashType = EcdsaSighashType;
fn sighash(
}
}
-fn p2wpkh_script_code(script: &Script) -> Script {
- ScriptBuilder::new()
- .push_opcode(opcodes::all::OP_DUP)
- .push_opcode(opcodes::all::OP_HASH160)
- .push_slice(&script[2..])
- .push_opcode(opcodes::all::OP_EQUALVERIFY)
- .push_opcode(opcodes::all::OP_CHECKSIG)
- .into_script()
-}
-
impl ComputeSighash for Segwitv0 {
type Extra = ();
- type Sighash = bitcoin::Sighash;
+ type Sighash = sighash::SegwitV0Sighash;
type SighashType = EcdsaSighashType;
fn sighash(
Some(ref witness_script) => witness_script.clone(),
None => {
if utxo.script_pubkey.is_v0_p2wpkh() {
- p2wpkh_script_code(&utxo.script_pubkey)
+ utxo.script_pubkey
+ .p2wpkh_script_code()
+ .expect("We check above that the spk is a p2wpkh")
} else if psbt_input
.redeem_script
.as_ref()
- .map(Script::is_v0_p2wpkh)
+ .map(|s| s.is_v0_p2wpkh())
.unwrap_or(false)
{
- p2wpkh_script_code(psbt_input.redeem_script.as_ref().unwrap())
+ psbt_input
+ .redeem_script
+ .as_ref()
+ .unwrap()
+ .p2wpkh_script_code()
+ .expect("We check above that the spk is a p2wpkh")
} else {
return Err(SignerError::MissingWitnessScript);
}
impl ComputeSighash for Tap {
type Extra = Option<taproot::TapLeafHash>;
- type Sighash = taproot::TapSighashHash;
- type SighashType = SchnorrSighashType;
+ type Sighash = TapSighash;
+ type SighashType = TapSighashType;
fn sighash(
psbt: &psbt::PartiallySignedTransaction,
input_index: usize,
extra: Self::Extra,
- ) -> Result<(Self::Sighash, SchnorrSighashType), SignerError> {
+ ) -> Result<(Self::Sighash, TapSighashType), SignerError> {
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
return Err(SignerError::InputIndexOutOfRange);
}
let sighash_type = psbt_input
.sighash_type
- .unwrap_or_else(|| SchnorrSighashType::Default.into())
- .schnorr_hash_ty()
+ .unwrap_or_else(|| TapSighashType::Default.into())
+ .taproot_hash_ty()
.map_err(|_| SignerError::InvalidSighash)?;
let witness_utxos = (0..psbt.inputs.len())
.map(|i| psbt.get_utxo_for(i))
use crate::descriptor::IntoWalletDescriptor;
use crate::keys::{DescriptorKey, IntoDescriptorKey};
use assert_matches::assert_matches;
+ use bitcoin::bip32;
use bitcoin::secp256k1::{All, Secp256k1};
- use bitcoin::util::bip32;
use bitcoin::Network;
use core::str::FromStr;
use miniscript::ScriptContext;
//! # use bitcoin::*;
//! # use bdk::*;
//! # use bdk::wallet::tx_builder::CreateTx;
-//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
//! # let mut wallet = doctest_wallet!();
//! // create a TxBuilder from a wallet
//! let mut tx_builder = wallet.build_tx();
//! // Create a transaction with one output to `to_address` of 50_000 satoshi
//! .add_recipient(to_address.script_pubkey(), 50_000)
//! // With a custom fee rate of 5.0 satoshi/vbyte
-//! .fee_rate(FeeRate::from_sat_per_vb(5.0))
+//! .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0))
//! // Only spend non-change outputs
//! .do_not_spend_change()
//! // Turn on RBF signaling
use core::cell::RefCell;
use core::marker::PhantomData;
-use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt};
-use bitcoin::{LockTime, OutPoint, Script, Sequence, Transaction};
+use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt};
+use bitcoin::{absolute, script::PushBytes, OutPoint, ScriptBuf, Sequence, Transaction};
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
use super::ChangeSet;
/// # use bitcoin::*;
/// # use core::str::FromStr;
/// # let mut wallet = doctest_wallet!();
-/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// # let addr2 = addr1.clone();
/// // chaining
/// let (psbt1, details) = {
//TODO: TxParams should eventually be exposed publicly.
#[derive(Default, Debug, Clone)]
pub(crate) struct TxParams {
- pub(crate) recipients: Vec<(Script, u64)>,
+ pub(crate) recipients: Vec<(ScriptBuf, u64)>,
pub(crate) drain_wallet: bool,
- pub(crate) drain_to: Option<Script>,
+ pub(crate) drain_to: Option<ScriptBuf>,
pub(crate) fee_policy: Option<FeePolicy>,
pub(crate) internal_policy_path: Option<BTreeMap<String, Vec<usize>>>,
pub(crate) external_policy_path: Option<BTreeMap<String, Vec<usize>>>,
pub(crate) manually_selected_only: bool,
pub(crate) sighash: Option<psbt::PsbtSighashType>,
pub(crate) ordering: TxOrdering,
- pub(crate) locktime: Option<LockTime>,
+ pub(crate) locktime: Option<absolute::LockTime>,
pub(crate) rbf: Option<RbfValue>,
pub(crate) version: Option<Version>,
pub(crate) change_policy: ChangeSpendPolicy,
pub(crate) add_global_xpubs: bool,
pub(crate) include_output_redeem_witness_script: bool,
pub(crate) bumping_fee: Option<PreviousFee>,
- pub(crate) current_height: Option<LockTime>,
+ pub(crate) current_height: Option<absolute::LockTime>,
pub(crate) allow_dust: bool,
}
/// # use std::collections::BTreeMap;
/// # use bitcoin::*;
/// # use bdk::*;
- /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ /// # let to_address =
+ /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
+ /// .unwrap()
+ /// .assume_checked();
/// # let mut wallet = doctest_wallet!();
/// let mut path = BTreeMap::new();
/// path.insert("aabbccdd".to_string(), vec![0, 1]);
for utxo in utxos {
let descriptor = wallet.get_descriptor_for_keychain(utxo.keychain);
+ #[allow(deprecated)]
let satisfaction_weight = descriptor.max_satisfaction_weight().unwrap();
self.params.utxos.push(WeightedUtxo {
satisfaction_weight,
/// Use a specific nLockTime while creating the transaction
///
/// This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator.
- pub fn nlocktime(&mut self, locktime: LockTime) -> &mut Self {
+ pub fn nlocktime(&mut self, locktime: absolute::LockTime) -> &mut Self {
self.params.locktime = Some(locktime);
self
}
self
}
- /// Only Fill-in the [`psbt::Input::witness_utxo`](bitcoin::util::psbt::Input::witness_utxo) field when spending from
+ /// Only Fill-in the [`psbt::Input::witness_utxo`](bitcoin::psbt::Input::witness_utxo) field when spending from
/// SegWit descriptors.
///
/// This reduces the size of the PSBT, but some signers might reject them due to the lack of
self
}
- /// Fill-in the [`psbt::Output::redeem_script`](bitcoin::util::psbt::Output::redeem_script) and
- /// [`psbt::Output::witness_script`](bitcoin::util::psbt::Output::witness_script) fields.
+ /// Fill-in the [`psbt::Output::redeem_script`](bitcoin::psbt::Output::redeem_script) and
+ /// [`psbt::Output::witness_script`](bitcoin::psbt::Output::witness_script) fields.
///
/// This is useful for signers which always require it, like ColdCard hardware wallets.
pub fn include_output_redeem_witness_script(&mut self) -> &mut Self {
///
/// In both cases, if you don't provide a current height, we use the last sync height.
pub fn current_height(&mut self, height: u32) -> &mut Self {
- self.params.current_height = Some(LockTime::from_height(height).expect("Invalid height"));
+ self.params.current_height =
+ Some(absolute::LockTime::from_height(height).expect("Invalid height"));
self
}
impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs, CreateTx> {
/// Replace the recipients already added with a new list
- pub fn set_recipients(&mut self, recipients: Vec<(Script, u64)>) -> &mut Self {
+ pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, u64)>) -> &mut Self {
self.params.recipients = recipients;
self
}
/// Add a recipient to the internal list
- pub fn add_recipient(&mut self, script_pubkey: Script, amount: u64) -> &mut Self {
+ pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: u64) -> &mut Self {
self.params.recipients.push((script_pubkey, amount));
self
}
/// Add data as an output, using OP_RETURN
- pub fn add_data(&mut self, data: &[u8]) -> &mut Self {
- let script = Script::new_op_return(data);
+ pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
+ let script = ScriptBuf::new_op_return(data);
self.add_recipient(script, 0u64);
self
}
/// # use bitcoin::*;
/// # use bdk::*;
/// # use bdk::wallet::tx_builder::CreateTx;
- /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ /// # let to_address =
+ /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
+ /// .unwrap()
+ /// .assume_checked();
/// # let mut wallet = doctest_wallet!();
/// let mut tx_builder = wallet.build_tx();
///
/// .drain_wallet()
/// // Send the excess (which is all the coins minus the fee) to this address.
/// .drain_to(to_address.script_pubkey())
- /// .fee_rate(FeeRate::from_sat_per_vb(5.0))
+ /// .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0))
/// .enable_rbf();
/// let (psbt, tx_details) = tx_builder.finish()?;
/// # Ok::<(), bdk::Error>(())
/// [`add_recipient`]: Self::add_recipient
/// [`add_utxos`]: Self::add_utxos
/// [`drain_wallet`]: Self::drain_wallet
- pub fn drain_to(&mut self, script_pubkey: Script) -> &mut Self {
+ pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self {
self.params.drain_to = Some(script_pubkey);
self
}
///
/// Returns an `Err` if `script_pubkey` can't be found among the recipients of the
/// transaction we are bumping.
- pub fn allow_shrinking(&mut self, script_pubkey: Script) -> Result<&mut Self, Error> {
+ pub fn allow_shrinking(&mut self, script_pubkey: ScriptBuf) -> Result<&mut Self, Error> {
match self
.params
.recipients
);
assert_eq!(tx.output[0].value, 800);
- assert_eq!(tx.output[1].script_pubkey, From::from(vec![0xAA]));
- assert_eq!(tx.output[2].script_pubkey, From::from(vec![0xAA, 0xEE]));
+ assert_eq!(tx.output[1].script_pubkey, ScriptBuf::from(vec![0xAA]));
+ assert_eq!(
+ tx.output[2].script_pubkey,
+ ScriptBuf::from(vec![0xAA, 0xEE])
+ );
}
fn get_test_utxos() -> Vec<LocalUtxo> {
vec![
LocalUtxo {
outpoint: OutPoint {
- txid: bitcoin::Txid::from_inner([0; 32]),
+ txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
vout: 0,
},
txout: Default::default(),
},
LocalUtxo {
outpoint: OutPoint {
- txid: bitcoin::Txid::from_inner([0; 32]),
+ txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
vout: 1,
},
txout: Default::default(),
// licenses.
use bitcoin::secp256k1::{All, Secp256k1};
-use bitcoin::{LockTime, Script, Sequence};
+use bitcoin::{absolute, Script, Sequence};
use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
}
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for After {
- fn check_after(&self, n: LockTime) -> bool {
+ fn check_after(&self, n: absolute::LockTime) -> bool {
if let Some(current_height) = self.current_height {
current_height >= n.to_consensus_u32()
} else {
pub(crate) const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 1 << 22;
use super::{check_nsequence_rbf, IsDust};
- use crate::bitcoin::{Address, Sequence};
+ use crate::bitcoin::{Address, Network, Sequence};
use core::str::FromStr;
#[test]
fn test_is_dust() {
let script_p2pkh = Address::from_str("1GNgwA8JfG7Kc8akJ8opdNWJUihqUztfPe")
+ .unwrap()
+ .require_network(Network::Bitcoin)
.unwrap()
.script_pubkey();
assert!(script_p2pkh.is_p2pkh());
assert!(!546.is_dust(&script_p2pkh));
let script_p2wpkh = Address::from_str("bc1qxlh2mnc0yqwas76gqq665qkggee5m98t8yskd8")
+ .unwrap()
+ .require_network(Network::Bitcoin)
.unwrap()
.script_pubkey();
assert!(script_p2wpkh.is_v0_p2wpkh());
let tx = Transaction {
version: 1,
- lock_time: bitcoin::PackedLockTime(0),
+ lock_time: bitcoin::absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
value: 50_000,
use bdk::wallet::AddressIndex;
use bdk::wallet::AddressIndex::New;
use bdk::{psbt, FeeRate, SignOptions};
-use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+use bitcoin::psbt::PartiallySignedTransaction as Psbt;
use core::str::FromStr;
mod common;
use common::*;
use bdk_chain::ConfirmationTime;
use bdk_chain::COINBASE_MATURITY;
use bitcoin::hashes::Hash;
+use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::BlockHash;
-use bitcoin::Script;
-use bitcoin::{util::psbt, Network};
+use bitcoin::ScriptBuf;
use bitcoin::{
- Address, EcdsaSighashType, LockTime, OutPoint, PackedLockTime, SchnorrSighashType, Sequence,
- Transaction, TxIn, TxOut,
+ absolute, script::PushBytesBuf, taproot::TapNodeHash, Address, OutPoint, Sequence, Transaction,
+ TxIn, TxOut, Weight,
};
+use bitcoin::{psbt, Network};
use core::str::FromStr;
mod common;
fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) -> OutPoint {
let tx = Transaction {
version: 1,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(LastUnused).script_pubkey(),
// Since we never synced the wallet we don't have a last_sync_height
// we could use to try to prevent fee sniping. We default to 0.
- assert_eq!(psbt.unsigned_tx.lock_time.0, 1_000);
+ assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 1_000);
}
#[test]
// If there's no current_height we're left with using the last sync height
assert_eq!(
- psbt.unsigned_tx.lock_time.0,
+ psbt.unsigned_tx.lock_time.to_consensus_u32(),
wallet.latest_checkpoint().unwrap().height()
);
}
builder.add_recipient(addr.script_pubkey(), 25_000);
let (psbt, _) = builder.finish().unwrap();
- assert_eq!(psbt.unsigned_tx.lock_time.0, 100_000);
+ assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 100_000);
}
#[test]
builder
.add_recipient(addr.script_pubkey(), 25_000)
.current_height(630_001)
- .nlocktime(LockTime::from_height(630_000).unwrap());
+ .nlocktime(absolute::LockTime::from_height(630_000).unwrap());
let (psbt, _) = builder.finish().unwrap();
// When we explicitly specify a nlocktime
// we don't try any fee sniping prevention trick
// (we ignore the current_height)
- assert_eq!(psbt.unsigned_tx.lock_time.0, 630_000);
+ assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 630_000);
}
#[test]
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 25_000)
- .nlocktime(LockTime::from_height(630_000).unwrap());
+ .nlocktime(absolute::LockTime::from_height(630_000).unwrap());
let (psbt, _) = builder.finish().unwrap();
- assert_eq!(psbt.unsigned_tx.lock_time.0, 630_000);
+ assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 630_000);
}
#[test]
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 25_000)
- .nlocktime(LockTime::from_height(50000).unwrap());
+ .nlocktime(absolute::LockTime::from_height(50000).unwrap());
builder.finish().unwrap();
}
#[test]
fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ let addr = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
+ .unwrap()
+ .assume_checked();
let drain_addr = wallet.get_address(New);
let mut builder = wallet.build_tx();
builder
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
- .sighash(bitcoin::EcdsaSighashType::Single.into());
+ .sighash(EcdsaSighashType::Single.into());
let (psbt, _) = builder.finish().unwrap();
assert_eq!(
psbt.inputs[0].sighash_type,
- Some(bitcoin::EcdsaSighashType::Single.into())
+ Some(EcdsaSighashType::Single.into())
);
}
#[test]
fn test_create_tx_input_hd_keypaths() {
- use bitcoin::util::bip32::{DerivationPath, Fingerprint};
+ use bitcoin::bip32::{DerivationPath, Fingerprint};
use core::str::FromStr;
let (mut wallet, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)");
#[test]
fn test_create_tx_output_hd_keypaths() {
- use bitcoin::util::bip32::{DerivationPath, Fingerprint};
+ use bitcoin::bip32::{DerivationPath, Fingerprint};
use core::str::FromStr;
let (mut wallet, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)");
assert_eq!(
psbt.inputs[0].redeem_script,
- Some(Script::from(
+ Some(ScriptBuf::from(
Vec::<u8>::from_hex(
"21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac"
)
assert_eq!(psbt.inputs[0].redeem_script, None);
assert_eq!(
psbt.inputs[0].witness_script,
- Some(Script::from(
+ Some(ScriptBuf::from(
Vec::<u8>::from_hex(
"21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac"
)
#[test]
fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() {
- use bitcoin::hashes::hex::FromHex;
-
let (mut wallet, _) =
get_funded_wallet("sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))");
let addr = wallet.get_address(New);
builder.drain_to(addr.script_pubkey()).drain_wallet();
let (psbt, _) = builder.finish().unwrap();
- let script = Script::from(
- Vec::<u8>::from_hex(
- "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac",
- )
- .unwrap(),
- );
+ let script = ScriptBuf::from_hex(
+ "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac",
+ )
+ .unwrap();
assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_v0_p2wsh()));
assert_eq!(psbt.inputs[0].witness_script, Some(script));
script_pubkey: wallet.get_address(New).address.script_pubkey(),
}],
version: 0,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
};
wallet
.insert_tx(
)
.unwrap();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
script_pubkey: wallet.get_address(New).address.script_pubkey(),
}],
version: 0,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
};
wallet
)
.unwrap();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
fn test_create_tx_policy_path_required() {
let (mut wallet, _) = get_funded_wallet(get_test_a_or_b_plus_csv());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 30_000);
builder.finish().unwrap();
let tx = Transaction {
version: 0,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
value: 50_000,
// child #0 is just the key "A"
let path = vec![(root_id, vec![0])].into_iter().collect();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
// child #1 is or(pk(B),older(144))
let path = vec![(root_id, vec![1])].into_iter().collect();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
// child #0 is pk(cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu)
let path = vec![(root_id, vec![0])].into_iter().collect();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 30_000)
#[test]
fn test_create_tx_global_xpubs_with_origin() {
+ use bitcoin::bip32;
use bitcoin::hashes::hex::FromHex;
- use bitcoin::util::bip32;
let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)");
let addr = wallet.get_address(New);
let (wallet2, _) =
get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let utxo = wallet2.list_unspent().next().expect("must take!");
+ #[allow(deprecated)]
let foreign_utxo_satisfaction = wallet2
.get_descriptor_for_keychain(KeychainKind::External)
.max_satisfaction_weight()
fn test_add_foreign_utxo_invalid_psbt_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let outpoint = wallet.list_unspent().next().expect("must exist").outpoint;
+ #[allow(deprecated)]
let foreign_utxo_satisfaction = wallet
.get_descriptor_for_keychain(KeychainKind::External)
.max_satisfaction_weight()
let tx1 = wallet1.get_tx(txid1, true).unwrap().transaction.unwrap();
let tx2 = wallet2.get_tx(txid2, true).unwrap().transaction.unwrap();
+ #[allow(deprecated)]
let satisfaction_weight = wallet2
.get_descriptor_for_keychain(KeychainKind::External)
.max_satisfaction_weight()
let (mut wallet1, _) = get_funded_wallet(get_test_wpkh());
let (wallet2, txid2) =
get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let utxo2 = wallet2.list_unspent().next().unwrap();
+ #[allow(deprecated)]
let satisfaction_weight = wallet2
.get_descriptor_for_keychain(KeychainKind::External)
.max_satisfaction_weight()
#[test]
fn test_create_tx_global_xpubs_master_without_origin() {
+ use bitcoin::bip32;
use bitcoin::hashes::hex::FromHex;
- use bitcoin::util::bip32;
let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)");
let addr = wallet.get_address(New);
#[test]
fn test_bump_fee_reduce_change() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 25_000)
#[test]
fn test_bump_fee_reduce_single_recipient() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.drain_to(addr.script_pubkey())
#[test]
fn test_bump_fee_absolute_reduce_single_recipient() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.drain_to(addr.script_pubkey())
// receive an extra tx so that our wallet has two utxos.
let tx = Transaction {
version: 1,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
value: 25_000,
},
)
.unwrap();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
// unless you've also set "allow_shrinking" OR there is a change output.
let init_tx = Transaction {
version: 1,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(New).script_pubkey(),
txid: init_tx.txid(),
vout: 0,
};
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.drain_to(addr.script_pubkey())
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let init_tx = Transaction {
version: 1,
- lock_time: PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(New).script_pubkey(),
.into();
wallet.insert_tx(init_tx, pos).unwrap();
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
fn test_bump_fee_absolute_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
receive_output_in_latest_block(&mut wallet, 25_000);
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
let op = receive_output_in_latest_block(&mut wallet, 25_000);
// initially make a tx without change by using `drain_to`
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.drain_to(addr.script_pubkey())
fn test_bump_fee_add_input_change_dust() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
receive_output_in_latest_block(&mut wallet, 25_000);
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
// + extra input weight: 160 WU = (32 (prevout) + 4 (vout) + 4 (nsequence)) * 4
// + input satisfaction weight: 112 WU = 106 (witness) + 2 (witness len) + (1 (script len)) * 4
// - change output weight: 124 WU = (8 (value) + 1 (script len) + 22 (script)) * 4
- let new_tx_weight = original_tx_weight + 160 + 112 - 124;
+ let new_tx_weight =
+ original_tx_weight + Weight::from_wu(160) + Weight::from_wu(112) - Weight::from_wu(124);
// two inputs (50k, 25k) and one output (45k) - epsilon
// We use epsilon here to avoid asking for a slightly too high feerate
let fee_abs = 50_000 + 25_000 - 45_000 - 10;
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let incoming_op = receive_output_in_latest_block(&mut wallet, 25_000);
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let incoming_op = receive_output_in_latest_block(&mut wallet, 25_000);
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder
.add_recipient(addr.script_pubkey(), 45_000)
// The replacement transaction may only include an unconfirmed input
// if that input was included in one of the original transactions.
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.drain_wallet()
// always fee bump with an unconfirmed input if it was included in the
// original transaction)
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
// We receive a tx with 0 confirmations, which will be used as an input
// in the drain tx.
receive_output(&mut wallet, 25_000, ConfirmationTime::unconfirmed(0));
// for a transaction.
// See https://github.com/bitcoindevkit/bdk/issues/660
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let send_to = Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt").unwrap();
+ let send_to = Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt")
+ .unwrap()
+ .assume_checked();
let fee_rate = FeeRate::from_sat_per_vb(2.01);
let incoming_op = receive_output_in_latest_block(&mut wallet, 8859);
#[test]
fn test_include_output_redeem_witness_script() {
let (mut wallet, _) = get_funded_wallet("sh(wsh(multi(1,cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW,cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu)))");
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 45_000)
#[test]
fn test_signing_only_one_of_multiple_inputs() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), 45_000)
let (mut psbt, _) = builder.finish().unwrap();
// add another input to the psbt that is at least passable.
- let dud_input = bitcoin::util::psbt::Input {
+ let dud_input = bitcoin::psbt::Input {
witness_utxo: Some(TxOut {
value: 100_000,
script_pubkey: miniscript::Descriptor::<bitcoin::PublicKey>::from_str(
wallet.get_address(New),
AddressInfo {
index: 0,
- address: Address::from_str("tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a").unwrap(),
+ address: Address::from_str("tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
}
);
wallet.get_address(New),
AddressInfo {
index: 1,
- address: Address::from_str("tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7").unwrap(),
+ address: Address::from_str("tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
}
);
wallet.get_address(Peek(25)),
AddressInfo {
index: 25,
- address: Address::from_str("tb1qsp7qu0knx3sl6536dzs0703u2w2ag6ppl9d0c2").unwrap(),
+ address: Address::from_str("tb1qsp7qu0knx3sl6536dzs0703u2w2ag6ppl9d0c2")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
}
);
wallet.get_address(New),
AddressInfo {
index: 2,
- address: Address::from_str("tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2").unwrap(),
+ address: Address::from_str("tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
}
);
fn test_sending_to_bip350_bech32m_address() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = Address::from_str("tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c")
- .unwrap();
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 45_000);
builder.finish().unwrap();
#[test]
fn test_get_address() {
use bdk::descriptor::template::Bip84;
- let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let mut wallet = Wallet::new_no_persist(
Bip84(key, KeychainKind::External),
Some(Bip84(key, KeychainKind::Internal)),
wallet.get_address(AddressIndex::New),
AddressInfo {
index: 0,
- address: Address::from_str("bcrt1qrhgaqu0zvf5q2d0gwwz04w0dh0cuehhqvzpp4w").unwrap(),
+ address: Address::from_str("bcrt1qrhgaqu0zvf5q2d0gwwz04w0dh0cuehhqvzpp4w")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
}
);
wallet.get_internal_address(AddressIndex::New),
AddressInfo {
index: 0,
- address: Address::from_str("bcrt1q0ue3s5y935tw7v3gmnh36c5zzsaw4n9c9smq79").unwrap(),
+ address: Address::from_str("bcrt1q0ue3s5y935tw7v3gmnh36c5zzsaw4n9c9smq79")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::Internal,
}
);
wallet.get_internal_address(AddressIndex::New),
AddressInfo {
index: 0,
- address: Address::from_str("bcrt1qrhgaqu0zvf5q2d0gwwz04w0dh0cuehhqvzpp4w").unwrap(),
+ address: Address::from_str("bcrt1qrhgaqu0zvf5q2d0gwwz04w0dh0cuehhqvzpp4w")
+ .unwrap()
+ .assume_checked(),
keychain: KeychainKind::External,
},
"when there's no internal descriptor it should just use external"
use bdk::descriptor::template::Bip84;
use std::collections::HashSet;
- let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let mut wallet =
Wallet::new_no_persist(Bip84(key, KeychainKind::External), None, Network::Regtest).unwrap();
let (mut wallet, _) = get_funded_wallet(get_test_tr_repeated_key());
let addr = wallet.get_address(AddressIndex::New);
- let path = vec![("e5mmg3xh".to_string(), vec![0])]
+ let path = vec![("rn4nre9c".to_string(), vec![0])]
.into_iter()
.collect();
assert_eq!(
input_key_origins,
vec![
- (
- from_str!("b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55"),
- (
- vec![],
- (FromStr::from_str("871fd295").unwrap(), vec![].into())
- )
- ),
(
from_str!("2b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3"),
(
],
(FromStr::from_str("ece52657").unwrap(), vec![].into())
)
+ ),
+ (
+ from_str!("b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55"),
+ (
+ vec![],
+ (FromStr::from_str("871fd295").unwrap(), vec![].into())
+ )
)
],
"Wrong input tap_key_origins"
#[test]
fn test_taproot_psbt_input_tap_tree() {
- use bdk::bitcoin::psbt::serialize::Deserialize;
- use bdk::bitcoin::psbt::TapTree;
use bitcoin::hashes::hex::FromHex;
- use bitcoin::util::taproot;
+ use bitcoin::taproot;
let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree());
let addr = wallet.get_address(AddressIndex::Peek(0));
assert_eq!(
psbt.inputs[0].tap_merkle_root,
Some(
- FromHex::from_hex("61f81509635053e52d9d1217545916167394490da2287aca4693606e43851986")
- .unwrap()
+ TapNodeHash::from_str(
+ "61f81509635053e52d9d1217545916167394490da2287aca4693606e43851986"
+ )
+ .unwrap()
),
);
assert_eq!(
psbt.inputs[0].tap_scripts.clone().into_iter().collect::<Vec<_>>(),
vec![
- (taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b7ef769a745e625ed4b9a4982a4dc08274c59187e73e6f07171108f455081cb2").unwrap()).unwrap(), (from_str!("208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac"), taproot::LeafVersion::TapScript)),
- (taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b9a515f7be31a70186e3c5937ee4a70cc4b4e1efe876c1d38e408222ffc64834").unwrap()).unwrap(), (from_str!("2051494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295ac"), taproot::LeafVersion::TapScript)),
+ (taproot::ControlBlock::decode(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b7ef769a745e625ed4b9a4982a4dc08274c59187e73e6f07171108f455081cb2").unwrap()).unwrap(), (ScriptBuf::from_hex("208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac").unwrap(), taproot::LeafVersion::TapScript)),
+ (taproot::ControlBlock::decode(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b9a515f7be31a70186e3c5937ee4a70cc4b4e1efe876c1d38e408222ffc64834").unwrap()).unwrap(), (ScriptBuf::from_hex("2051494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295ac").unwrap(), taproot::LeafVersion::TapScript)),
],
);
assert_eq!(
psbt.outputs[0].tap_internal_key
);
- assert_eq!(
- psbt.outputs[0].tap_tree,
- Some(TapTree::deserialize(&Vec::<u8>::from_hex("01c022208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac01c0222051494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295ac",).unwrap()).unwrap())
- );
+ let tap_tree: bitcoin::taproot::TapTree = serde_json::from_str(r#"[1,{"Script":["2051494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295ac",192]},1,{"Script":["208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac",192]}]"#).unwrap();
+ assert_eq!(psbt.outputs[0].tap_tree, Some(tap_tree));
}
#[test]
let (mut wallet1, _) = get_funded_wallet(get_test_wpkh());
let (wallet2, _) = get_funded_wallet(get_test_tr_single_sig());
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let utxo = wallet2.list_unspent().next().unwrap();
let psbt_input = wallet2.get_psbt_input(utxo.clone(), None, false).unwrap();
+ #[allow(deprecated)]
let foreign_utxo_satisfaction = wallet2
.get_descriptor_for_keychain(KeychainKind::External)
.max_satisfaction_weight()
#[test]
fn test_taproot_script_spend_sign_include_some_leaves() {
use bdk::signer::TapLeavesOptions;
- use bitcoin::util::taproot::TapLeafHash;
+ use bitcoin::taproot::TapLeafHash;
let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv());
let addr = wallet.get_address(AddressIndex::New);
#[test]
fn test_taproot_script_spend_sign_exclude_some_leaves() {
use bdk::signer::TapLeavesOptions;
- use bitcoin::util::taproot::TapLeafHash;
+ use bitcoin::taproot::TapLeafHash;
let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv());
let addr = wallet.get_address(AddressIndex::New);
let mut builder = wallet.build_tx();
builder
.drain_to(addr.script_pubkey())
- .sighash(SchnorrSighashType::All.into())
+ .sighash(TapSighashType::All.into())
.drain_wallet();
let (mut psbt, _) = builder.finish().unwrap();
#[test]
fn test_taproot_sign_non_default_sighash() {
- let sighash = SchnorrSighashType::NonePlusAnyoneCanPay;
+ let sighash = TapSighashType::NonePlusAnyoneCanPay;
let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig());
let addr = wallet.get_address(New);
.unwrap();
let coinbase_tx = Transaction {
version: 1,
- lock_time: bitcoin::PackedLockTime(0),
+ lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
..Default::default()
// We try to create a transaction, only to notice that all
// our funds are unspendable
- let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+ let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX")
+ .unwrap()
+ .assume_checked();
let mut builder = wallet.build_tx();
builder
.add_recipient(addr.script_pubkey(), balance.immature / 2)
let addr = wallet.get_address(New);
let fee_rate = FeeRate::from_sat_per_vb(1.0);
let mut builder = wallet.build_tx();
- let mut data = vec![0];
+ let mut data = PushBytesBuf::try_from(vec![0]).unwrap();
builder
.drain_to(addr.script_pubkey())
.drain_wallet()
while sig_len < 71 {
// Changing the OP_RETURN data will make the signature change (but not the fee, until
// data[0] is small enough)
- data[0] += 1;
- psbt.unsigned_tx.output[op_return_vout].script_pubkey = Script::new_op_return(&data);
+ data.as_mut_bytes()[0] += 1;
+ psbt.unsigned_tx.output[op_return_vout].script_pubkey = ScriptBuf::new_op_return(&data);
// Clearing the previous signature
psbt.inputs[0].partial_sigs.clear();
// Signing
fn test_tx_cancellation() {
macro_rules! new_tx {
($wallet:expr) => {{
- let addr = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+ let addr = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
+ .unwrap()
+ .assume_checked();
let mut builder = $wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 10_000);