[dependencies]
rand = "^0.8"
-miniscript = { version = "10.0.0", features = ["serde"], default-features = false }
-bitcoin = { version = "0.30.0", features = ["serde", "base64", "rand-std"], default-features = false }
+miniscript = { version = "11.0.0", features = ["serde"], default-features = false }
+bitcoin = { version = "0.31.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.11.0", features = ["miniscript", "serde"], default-features = false }
#[macro_export]
macro_rules! parse_tap_tree {
( @merge $tree_a:expr, $tree_b:expr) => {{
- use $crate::alloc::sync::Arc;
use $crate::miniscript::descriptor::TapTree;
$tree_a
.and_then(|tree_a| Ok((tree_a, $tree_b?)))
.and_then(|((a_tree, mut a_keymap, a_networks), (b_tree, b_keymap, b_networks))| {
a_keymap.extend(b_keymap.into_iter());
- Ok((TapTree::Tree(Arc::new(a_tree), Arc::new(b_tree)), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
+ Ok((TapTree::combine(a_tree, b_tree), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
})
}};
use crate::descriptor::{DescriptorError, DescriptorMeta};
use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
use bitcoin::bip32;
- use bitcoin::network::constants::Network::{Bitcoin, Regtest, Signet, Testnet};
+ use bitcoin::Network::{Bitcoin, Regtest, Signet, Testnet};
use bitcoin::PrivateKey;
// test the descriptor!() macro
#[test]
fn test_bip32_legacy_descriptors() {
- let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
#[test]
fn test_bip32_segwitv0_descriptors() {
- let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
#[test]
fn test_dsl_sortedmulti() {
- let key_1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
- let key_2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
+ let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
let desc_key1 = (key_1, path_1);
// - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
#[test]
fn test_valid_networks() {
- let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key = (xprv, path).into_descriptor_key().unwrap();
[Testnet, Regtest, Signet].iter().cloned().collect()
);
- let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
+ let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
let desc_key = (xprv, path).into_descriptor_key().unwrap();
fn test_key_maps_merged() {
let secp = Secp256k1::new();
- let xprv1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let xprv1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path1 = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key1 = (xprv1, path1.clone()).into_descriptor_key().unwrap();
- let xprv2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
+ let xprv2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
let desc_key2 = (xprv2, path2.clone()).into_descriptor_key().unwrap();
- let xprv3 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap();
+ let xprv3 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap();
let path3 = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
let desc_key3 = (xprv3, path3.clone()).into_descriptor_key().unwrap();
#[test]
fn test_script_context_validation() {
// this compiles
- let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key: DescriptorKey<Legacy> = (xprv, path).into_descriptor_key().unwrap();
/// Miniscript error
Miniscript(miniscript::Error),
/// Hex decoding error
- Hex(bitcoin::hashes::hex::Error),
+ Hex(bitcoin::hex::HexToBytesError),
}
impl From<crate::keys::KeyError> for Error {
}
}
-impl From<bitcoin::hashes::hex::Error> for Error {
- fn from(err: bitcoin::hashes::hex::Error) -> Self {
+impl From<bitcoin::hex::HexToBytesError> for Error {
+ fn from(err: bitcoin::hex::HexToBytesError) -> Self {
Error::Hex(err)
}
}
use alloc::string::String;
use alloc::vec::Vec;
-use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
+use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, KeySource, Xpub};
use bitcoin::{key::XOnlyPublicKey, secp256k1, PublicKey};
use bitcoin::{psbt, taproot};
use bitcoin::{Network, TxOut};
pub(crate) trait DescriptorMeta {
fn is_witness(&self) -> bool;
fn is_taproot(&self) -> bool;
- fn get_extended_keys(&self) -> Vec<DescriptorXKey<ExtendedPubKey>>;
+ fn get_extended_keys(&self) -> Vec<DescriptorXKey<Xpub>>;
fn derive_from_hd_keypaths(
&self,
hd_keypaths: &HdKeyPaths,
self.desc_type() == DescriptorType::Tr
}
- fn get_extended_keys(&self) -> Vec<DescriptorXKey<ExtendedPubKey>> {
+ fn get_extended_keys(&self) -> Vec<DescriptorXKey<Xpub>> {
let mut answer = Vec::new();
self.for_each_key(|pk| {
secp: &SecpCtx,
) -> Option<DerivedDescriptor> {
// Ensure that deriving `xpub` with `path` yields `expected`
- let verify_key = |xpub: &DescriptorXKey<ExtendedPubKey>,
- path: &DerivationPath,
- expected: &SinglePubKey| {
- let derived = xpub
- .xkey
- .derive_pub(secp, path)
- .expect("The path should never contain hardened derivation steps")
- .public_key;
-
- match expected {
- SinglePubKey::FullKey(pk) if &PublicKey::new(derived) == pk => true,
- SinglePubKey::XOnly(pk) if &XOnlyPublicKey::from(derived) == pk => true,
- _ => false,
- }
- };
+ let verify_key =
+ |xpub: &DescriptorXKey<Xpub>, path: &DerivationPath, expected: &SinglePubKey| {
+ let derived = xpub
+ .xkey
+ .derive_pub(secp, path)
+ .expect("The path should never contain hardened derivation steps")
+ .public_key;
+
+ match expected {
+ SinglePubKey::FullKey(pk) if &PublicKey::new(derived) == pk => true,
+ SinglePubKey::XOnly(pk) if &XOnlyPublicKey::from(derived) == pk => true,
+ _ => false,
+ }
+ };
let mut path_found = None;
use core::str::FromStr;
use assert_matches::assert_matches;
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::ScriptBuf;
- use bitcoin::{bip32, psbt::Psbt};
+ use bitcoin::{bip32, Psbt};
use super::*;
use crate::psbt::PsbtUtils;
let secp = Secp256k1::new();
- let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3c3gF1DUWpWNr2SG2XrG8oYPpqYh7hoWsJy9NjabErnzriJPpnGHyKz5NgdXmq1KVbqS1r4NXdCoKitWg5e86zqXHa8kxyB").unwrap();
+ let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3c3gF1DUWpWNr2SG2XrG8oYPpqYh7hoWsJy9NjabErnzriJPpnGHyKz5NgdXmq1KVbqS1r4NXdCoKitWg5e86zqXHa8kxyB").unwrap();
let path = bip32::DerivationPath::from_str("m/0").unwrap();
// here `to_descriptor_key` will set the valid networks for the key to only mainnet, since
let mut xprv_testnet = xprv;
xprv_testnet.network = Network::Testnet;
- let xpub_testnet = bip32::ExtendedPubKey::from_priv(&secp, &xprv_testnet);
+ let xpub_testnet = bip32::Xpub::from_priv(&secp, &xprv_testnet);
let desc_pubkey = DescriptorPublicKey::XPub(DescriptorXKey {
xkey: xpub_testnet,
origin: None,
fn test_descriptor_from_str_from_output_of_macro() {
let secp = Secp256k1::new();
- let tpub = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap();
+ let tpub = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap();
let path = bip32::DerivationPath::from_str("m/1/2").unwrap();
let key = (tpub, path).into_descriptor_key().unwrap();
.update_with_descriptor_unchecked(&descriptor)
.unwrap();
- assert_eq!(psbt_input.redeem_script, Some(script.to_v0_p2wsh()));
+ assert_eq!(psbt_input.redeem_script, Some(script.to_p2wsh()));
assert_eq!(psbt_input.witness_script, Some(script));
}
}
let key_spend_sig =
miniscript::Tap::make_signature(tr.internal_key(), signers, build_sat, secp);
- if tr.taptree().is_none() {
+ if tr.tap_tree().is_none() {
Ok(Some(key_spend_sig))
} else {
let mut items = vec![key_spend_sig];
secp: &SecpCtx,
) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
let path = bip32::DerivationPath::from_str(path).unwrap();
- let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap();
- let tpub = bip32::ExtendedPubKey::from_priv(secp, &tprv);
+ let tprv = bip32::Xpriv::from_str(tprv).unwrap();
+ let tpub = bip32::Xpub::from_priv(secp, &tprv);
let fingerprint = tprv.fingerprint(secp);
let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap();
let pubkey = (tpub, path).into_descriptor_key().unwrap();
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip44;
///
-/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44(key.clone(), KeychainKind::External),
/// Some(Bip44(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip44Public;
///
-/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
+/// let key = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44Public(key.clone(), fingerprint, KeychainKind::External),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip49;
///
-/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49(key.clone(), KeychainKind::External),
/// Some(Bip49(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip49Public;
///
-/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
+/// let key = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49Public(key.clone(), fingerprint, KeychainKind::External),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip84;
///
-/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84(key.clone(), KeychainKind::External),
/// Some(Bip84(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip84Public;
///
-/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84Public(key.clone(), fingerprint, KeychainKind::External),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip86;
///
-/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86(key.clone(), KeychainKind::External),
/// Some(Bip86(key, KeychainKind::Internal)),
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::Bip86Public;
///
-/// let key = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let key = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86Public(key.clone(), fingerprint, KeychainKind::External),
fn test_bip44_template_cointype() {
use bitcoin::bip32::ChildNumber::{self, Hardened};
- let xprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
+ let xprvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K2fpbqApQL69a4oKdGVnVN52R82Ft7d1pSqgKmajF62acJo3aMszZb6qQ22QsVECSFxvf9uyxFUvFYQMq3QbtwtRSMjLAhMf").unwrap();
assert_eq!(Network::Bitcoin, xprvkey.network);
let xdesc = Bip44(xprvkey, KeychainKind::Internal)
.build(Network::Bitcoin)
assert_matches!(coin_type, Hardened { index: 0 });
}
- let tprvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let tprvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
assert_eq!(Network::Testnet, tprvkey.network);
let tdesc = Bip44(tprvkey, KeychainKind::Internal)
.build(Network::Testnet)
// BIP44 `pkh(key/44'/0'/0'/{0,1}/*)`
#[test]
fn test_bip44_template() {
- let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip44(prvkey, KeychainKind::External).build(Network::Bitcoin),
false,
// BIP44 public `pkh(key/{0,1}/*)`
#[test]
fn test_bip44_public_template() {
- let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
+ let pubkey = bitcoin::bip32::Xpub::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip44Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
// BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))`
#[test]
fn test_bip49_template() {
- let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip49(prvkey, KeychainKind::External).build(Network::Bitcoin),
true,
// BIP49 public `sh(wpkh(key/{0,1}/*))`
#[test]
fn test_bip49_public_template() {
- let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
+ let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip49Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
// BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)`
#[test]
fn test_bip84_template() {
- let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let prvkey = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
check(
Bip84(prvkey, KeychainKind::External).build(Network::Bitcoin),
true,
// BIP84 public `wpkh(key/{0,1}/*)`
#[test]
fn test_bip84_public_template() {
- let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
+ let pubkey = bitcoin::bip32::Xpub::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f").unwrap();
check(
Bip84Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
// Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
#[test]
fn test_bip86_template() {
- let prvkey = bitcoin::bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap();
+ let prvkey = bitcoin::bip32::Xpriv::from_str("xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu").unwrap();
check(
Bip86(prvkey, KeychainKind::External).build(Network::Bitcoin),
false,
// Used addresses in test vector in https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki
#[test]
fn test_bip86_public_template() {
- let pubkey = bitcoin::bip32::ExtendedPubKey::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap();
+ let pubkey = bitcoin::bip32::Xpub::from_str("xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ").unwrap();
let fingerprint = bitcoin::bip32::Fingerprint::from_str("73c5da0a").unwrap();
check(
Bip86Public(pubkey, fingerprint, KeychainKind::External).build(Network::Bitcoin),
#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
impl<Ctx: ScriptContext> DerivableKey<Ctx> for Seed {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
- Ok(bip32::ExtendedPrivKey::new_master(Network::Bitcoin, &self[..])?.into())
+ Ok(bip32::Xpriv::new_master(Network::Bitcoin, &self[..])?.into())
}
fn into_descriptor_key(
Ok((public, KeyMap::default(), valid_networks))
}
DescriptorKey::Secret(secret, valid_networks, _) => {
- let mut key_map = KeyMap::with_capacity(1);
+ let mut key_map = KeyMap::new();
let public = secret
.to_public(secp)
/// Enum for extended keys that can be either `xprv` or `xpub`
///
-/// An instance of [`ExtendedKey`] can be constructed from an [`ExtendedPrivKey`](bip32::ExtendedPrivKey)
-/// or an [`ExtendedPubKey`](bip32::ExtendedPubKey) by using the `From` trait.
+/// An instance of [`ExtendedKey`] can be constructed from an [`Xpriv`](bip32::Xpriv)
+/// or an [`Xpub`](bip32::Xpub) by using the `From` trait.
///
/// Defaults to the [`Legacy`](miniscript::Legacy) context.
pub enum ExtendedKey<Ctx: ScriptContext = miniscript::Legacy> {
/// A private extended key, aka an `xprv`
- Private((bip32::ExtendedPrivKey, PhantomData<Ctx>)),
+ Private((bip32::Xpriv, PhantomData<Ctx>)),
/// A public extended key, aka an `xpub`
- Public((bip32::ExtendedPubKey, PhantomData<Ctx>)),
+ Public((bip32::Xpub, PhantomData<Ctx>)),
}
impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
}
}
- /// Transform the [`ExtendedKey`] into an [`ExtendedPrivKey`](bip32::ExtendedPrivKey) for the
+ /// Transform the [`ExtendedKey`] into an [`Xpriv`](bip32::Xpriv) for the
/// given [`Network`], if the key contains the private data
- pub fn into_xprv(self, network: Network) -> Option<bip32::ExtendedPrivKey> {
+ pub fn into_xprv(self, network: Network) -> Option<bip32::Xpriv> {
match self {
ExtendedKey::Private((mut xprv, _)) => {
xprv.network = network;
}
}
- /// Transform the [`ExtendedKey`] into an [`ExtendedPubKey`](bip32::ExtendedPubKey) for the
+ /// Transform the [`ExtendedKey`] into an [`Xpub`](bip32::Xpub) for the
/// given [`Network`]
pub fn into_xpub<C: Signing>(
self,
network: bitcoin::Network,
secp: &Secp256k1<C>,
- ) -> bip32::ExtendedPubKey {
+ ) -> bip32::Xpub {
let mut xpub = match self {
- ExtendedKey::Private((xprv, _)) => bip32::ExtendedPubKey::from_priv(secp, &xprv),
+ ExtendedKey::Private((xprv, _)) => bip32::Xpub::from_priv(secp, &xprv),
ExtendedKey::Public((xpub, _)) => xpub,
};
}
}
-impl<Ctx: ScriptContext> From<bip32::ExtendedPubKey> for ExtendedKey<Ctx> {
- fn from(xpub: bip32::ExtendedPubKey) -> Self {
+impl<Ctx: ScriptContext> From<bip32::Xpub> for ExtendedKey<Ctx> {
+ fn from(xpub: bip32::Xpub) -> Self {
ExtendedKey::Public((xpub, PhantomData))
}
}
-impl<Ctx: ScriptContext> From<bip32::ExtendedPrivKey> for ExtendedKey<Ctx> {
- fn from(xprv: bip32::ExtendedPrivKey) -> Self {
+impl<Ctx: ScriptContext> From<bip32::Xpriv> for ExtendedKey<Ctx> {
+ fn from(xprv: bip32::Xpriv) -> Self {
ExtendedKey::Private((xprv, PhantomData))
}
}
///
/// ## Examples
///
-/// Key types that can be directly converted into an [`ExtendedPrivKey`] or
-/// an [`ExtendedPubKey`] can implement only the required `into_extended_key()` method.
+/// Key types that can be directly converted into an [`Xpriv`] or
+/// an [`Xpub`] can implement only the required `into_extended_key()` method.
///
/// ```
/// use bdk::bitcoin;
///
/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
/// fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
-/// let xprv = bip32::ExtendedPrivKey {
+/// let xprv = bip32::Xpriv {
/// network: self.network,
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
///
/// Types that don't internally encode the [`Network`] in which they are valid need some extra
/// steps to override the set of valid networks, otherwise only the network specified in the
-/// [`ExtendedPrivKey`] or [`ExtendedPubKey`] will be considered valid.
+/// [`Xpriv`] or [`Xpub`] will be considered valid.
///
/// ```
/// use bdk::bitcoin;
///
/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
/// fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
-/// let xprv = bip32::ExtendedPrivKey {
+/// let xprv = bip32::Xpriv {
/// network: bitcoin::Network::Bitcoin, // pick an arbitrary network here
/// depth: 0,
/// parent_fingerprint: bip32::Fingerprint::default(),
/// ```
///
/// [`DerivationPath`]: (bip32::DerivationPath)
-/// [`ExtendedPrivKey`]: (bip32::ExtendedPrivKey)
-/// [`ExtendedPubKey`]: (bip32::ExtendedPubKey)
+/// [`Xpriv`]: (bip32::Xpriv)
+/// [`Xpub`]: (bip32::Xpub)
pub trait DerivableKey<Ctx: ScriptContext = miniscript::Legacy>: Sized {
/// Consume `self` and turn it into an [`ExtendedKey`]
#[cfg_attr(
}
}
-impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpub {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
Ok(self.into())
}
}
-impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey {
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::Xpriv {
fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
Ok(self.into())
}
{
}
-impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::ExtendedPrivKey {
+impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::Xpriv {
type Entropy = [u8; 32];
type Options = ();
entropy: Self::Entropy,
) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
// pick a arbitrary network here, but say that we support all of them
- let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, entropy.as_ref())?;
+ let xprv = bip32::Xpriv::new_master(Network::Bitcoin, entropy.as_ref())?;
Ok(GeneratedKey::new(xprv, any_network()))
}
}
#[test]
fn test_keys_generate_xprv() {
let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
- bip32::ExtendedPrivKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
+ bip32::Xpriv::generate_with_entropy_default(TEST_ENTROPY).unwrap();
assert_eq!(generated_xprv.valid_networks, any_network());
assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
// You may not use this file except in accordance with one or both of these
// licenses.
-//! Additional functions on the `rust-bitcoin` `PartiallySignedTransaction` structure.
+//! Additional functions on the `rust-bitcoin` `Psbt` structure.
use alloc::vec::Vec;
-use bitcoin::psbt::PartiallySignedTransaction as Psbt;
use bitcoin::Amount;
use bitcoin::FeeRate;
+use bitcoin::Psbt;
use bitcoin::TxOut;
// TODO upstream the functions here to `rust-bitcoin`?
fn fee_amount(&self) -> Option<u64>;
/// The transaction's fee rate. This value will only be accurate if calculated AFTER the
- /// `PartiallySignedTransaction` is finalized and all witness/signature data is added to the
+ /// `Psbt` is finalized and all witness/signature data is added to the
/// transaction.
/// If the PSBT is missing a TxOut for an input returns None.
fn fee_rate(&self) -> Option<FeeRate>;
let utxos: Option<Vec<TxOut>> = (0..tx.input.len()).map(|i| self.get_utxo_for(i)).collect();
utxos.map(|inputs| {
- let input_amount: u64 = inputs.iter().map(|i| i.value).sum();
- let output_amount: u64 = self.unsigned_tx.output.iter().map(|o| o.value).sum();
+ let input_amount: u64 = inputs.iter().map(|i| i.value.to_sat()).sum();
+ let output_amount: u64 = self
+ .unsigned_tx
+ .output
+ .iter()
+ .map(|o| o.value.to_sat())
+ .sum();
input_amount
.checked_sub(output_amount)
.expect("input amount must be greater than output amount")
fn fee_rate(&self) -> Option<FeeRate> {
let fee_amount = self.fee_amount();
- fee_amount.map(|fee| {
- let weight = self.clone().extract_tx().weight();
- Amount::from_sat(fee) / weight
- })
+ let weight = self.clone().extract_tx().ok()?.weight();
+ fee_amount.map(|fee| Amount::from_sat(fee) / weight)
}
}
//! .scan(
//! (&mut selected_amount, &mut additional_weight),
//! |(selected_amount, additional_weight), weighted_utxo| {
-//! **selected_amount += weighted_utxo.utxo.txout().value;
+//! **selected_amount += weighted_utxo.utxo.txout().value.to_sat();
//! **additional_weight += Weight::from_wu(
-//! (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight)
+//! (TxIn::default().segwit_weight().to_wu()
+//! + weighted_utxo.satisfaction_weight as u64)
//! as u64,
//! );
//! Some(weighted_utxo.utxo)
impl CoinSelectionResult {
/// The total value of the inputs selected.
pub fn selected_amount(&self) -> u64 {
- self.selected.iter().map(|u| u.txout().value).sum()
+ self.selected.iter().map(|u| u.txout().value.to_sat()).sum()
}
/// The total value of the inputs selected from the local wallet.
self.selected
.iter()
.filter_map(|u| match u {
- Utxo::Local(_) => Some(u.txout().value),
+ Utxo::Local(_) => Some(u.txout().value.to_sat()),
_ => None,
})
.sum()
if must_use || **selected_amount < target_amount + **fee_amount {
**fee_amount += (fee_rate
* Weight::from_wu(
- (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight)
- as u64,
+ TxIn::default().segwit_weight().to_wu()
+ + weighted_utxo.satisfaction_weight as u64,
))
.to_sat();
- **selected_amount += weighted_utxo.utxo.txout().value;
+ **selected_amount += weighted_utxo.utxo.txout().value.to_sat();
Some(weighted_utxo.utxo)
} else {
None
fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self {
let fee = (fee_rate
* Weight::from_wu(
- (TxIn::default().segwit_weight() + weighted_utxo.satisfaction_weight) as u64,
+ TxIn::default().segwit_weight().to_wu() + weighted_utxo.satisfaction_weight as u64,
))
.to_sat();
- let effective_value = weighted_utxo.utxo.txout().value as i64 - fee as i64;
+ let effective_value = weighted_utxo.utxo.txout().value.to_sat() as i64 - fee as i64;
OutputGroup {
weighted_utxo,
fee,
.chain(optional_utxos.iter())
.fold((0, 0), |(mut fees, mut value), utxo| {
fees += utxo.fee;
- value += utxo.weighted_utxo.utxo.txout().value;
+ value += utxo.weighted_utxo.utxo.txout().value.to_sat();
(fees, value)
});
// If we found a solution better than the previous one, or if there wasn't previous
// solution, update the best solution
if best_selection_value.is_none() || curr_value < best_selection_value.unwrap() {
- best_selection = current_selection.clone();
+ best_selection.clone_from(¤t_selection);
best_selection_value = Some(curr_value);
}
use core::str::FromStr;
use bdk_chain::ConfirmationTime;
- use bitcoin::{Amount, OutPoint, ScriptBuf, TxIn, TxOut};
+ use bitcoin::{Amount, ScriptBuf, TxIn, TxOut};
use super::*;
use crate::types::*;
utxo: Utxo::Local(LocalOutput {
outpoint,
txout: TxOut {
- value,
+ value: Amount::from_sat(value),
script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
))
.unwrap(),
txout: TxOut {
- value: rng.gen_range(0..200000000),
+ value: Amount::from_sat(rng.gen_range(0..200000000)),
script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
))
.unwrap(),
txout: TxOut {
- value: utxos_value,
+ value: Amount::from_sat(utxos_value),
script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
utxos.shuffle(&mut rng);
utxos[..utxos_picked_len]
.iter()
- .map(|u| u.utxo.txout().value)
+ .map(|u| u.utxo.txout().value.to_sat())
.sum()
}
fn test_oldest_first_coin_selection_insufficient_funds_high_fees() {
let utxos = get_oldest_first_test_utxos();
- let target_amount: u64 = utxos.iter().map(|wu| wu.utxo.txout().value).sum::<u64>() - 50;
+ let target_amount: u64 = utxos
+ .iter()
+ .map(|wu| wu.utxo.txout().value.to_sat())
+ .sum::<u64>()
+ - 50;
let drain_script = ScriptBuf::default();
OldestFirstCoinSelection
));
// Defensive assertions, for sanity and in case someone changes the test utxos vector.
- let amount: u64 = required.iter().map(|u| u.utxo.txout().value).sum();
+ let amount: u64 = required.iter().map(|u| u.utxo.txout().value.to_sat()).sum();
assert_eq!(amount, 100_000);
- let amount: u64 = optional.iter().map(|u| u.utxo.txout().value).sum();
+ let amount: u64 = optional.iter().map(|u| u.utxo.txout().value.to_sat()).sum();
assert!(amount > 150_000);
let drain_script = ScriptBuf::default();
assert_eq!(result.selected.len(), 1);
assert_eq!(result.selected_amount(), 100_000);
- let input_weight = (TxIn::default().segwit_weight() + P2WPKH_SATISFACTION_SIZE) as u64;
+ let input_weight =
+ TxIn::default().segwit_weight().to_wu() + P2WPKH_SATISFACTION_SIZE as u64;
// the final fee rate should be exactly the same as the fee rate given
let result_feerate = Amount::from_sat(result.fee_amount) / Weight::from_wu(input_weight);
assert_eq!(result_feerate, feerate);
let utxos = get_test_utxos();
let drain_script = ScriptBuf::default();
- let (required, optional) = utxos
- .into_iter()
- .partition(|u| matches!(u, WeightedUtxo { utxo, .. } if utxo.txout().value < 1000));
+ let (required, optional) = utxos.into_iter().partition(
+ |u| matches!(u, WeightedUtxo { utxo, .. } if utxo.txout().value.to_sat() < 1000),
+ );
let selection = BranchAndBoundCoinSelection::default().coin_select(
required,
utxo: Utxo::Local(LocalOutput {
outpoint: OutPoint::new(bitcoin::hashes::Hash::hash(txid.as_bytes()), 0),
txout: TxOut {
- value,
+ value: Amount::from_sat(value),
script_pubkey: ScriptBuf::new(),
},
keychain: KeychainKind::External,
use bdk_chain::{BlockId, ConfirmationTime};
use bitcoin::hashes::Hash;
- use bitcoin::{BlockHash, Network, Transaction};
+ use bitcoin::{transaction, BlockHash, Network, Transaction};
use super::*;
use crate::wallet::Wallet;
let transaction = Transaction {
input: vec![],
output: vec![],
- version: 0,
+ version: transaction::Version::non_standard(0),
lock_time: bitcoin::absolute::LockTime::ZERO,
};
wallet
//! ```
use bitcoin::bip32::Fingerprint;
-use bitcoin::psbt::PartiallySignedTransaction;
use bitcoin::secp256k1::{All, Secp256k1};
+use bitcoin::Psbt;
use hwi::error::Error;
use hwi::types::{HWIChain, HWIDevice};
impl TransactionSigner for HWISigner {
fn sign_transaction(
&self,
- psbt: &mut PartiallySignedTransaction,
+ psbt: &mut Psbt,
_sign_options: &crate::SignOptions,
_secp: &crate::wallet::utils::SecpCtx,
) -> Result<(), SignerError> {
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
IndexedTxGraph, Persist, PersistBackend,
};
+use bitcoin::constants::genesis_block;
use bitcoin::secp256k1::{All, Secp256k1};
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::{
- absolute, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence, Transaction,
- TxOut, Txid, Weight, Witness,
+ absolute, psbt, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence,
+ Transaction, TxOut, Txid, Witness,
};
-use bitcoin::{consensus::encode::serialize, BlockHash};
-use bitcoin::{constants::genesis_block, psbt};
+use bitcoin::{consensus::encode::serialize, transaction, Amount, BlockHash, Psbt};
use core::fmt;
use core::ops::Deref;
use descriptor::error::Error as DescriptorError;
/// ```
///
/// ```rust, no_run
- /// # use bitcoin::psbt::PartiallySignedTransaction;
+ /// # use bitcoin::Psbt;
/// # use bdk::Wallet;
/// # let mut wallet: Wallet<()> = todo!();
- /// # let mut psbt: PartiallySignedTransaction = todo!();
- /// let tx = &psbt.clone().extract_tx();
+ /// # let mut psbt: Psbt = todo!();
+ /// let tx = &psbt.clone().extract_tx().expect("tx");
/// let fee = wallet.calculate_fee(tx).expect("fee");
/// ```
/// [`insert_txout`]: Self::insert_txout
/// ```
///
/// ```rust, no_run
- /// # use bitcoin::psbt::PartiallySignedTransaction;
+ /// # use bitcoin::Psbt;
/// # use bdk::Wallet;
/// # let mut wallet: Wallet<()> = todo!();
- /// # let mut psbt: PartiallySignedTransaction = todo!();
- /// let tx = psbt.clone().extract_tx();
- /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
+ /// # let mut psbt: Psbt = todo!();
+ /// let tx = &psbt.clone().extract_tx().expect("tx");
+ /// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
/// ```
/// [`insert_txout`]: Self::insert_txout
pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
/// ```
///
/// ```rust, no_run
- /// # use bitcoin::psbt::PartiallySignedTransaction;
+ /// # use bitcoin::Psbt;
/// # use bdk::Wallet;
/// # let mut wallet: Wallet<()> = todo!();
- /// # let mut psbt: PartiallySignedTransaction = todo!();
- /// let tx = &psbt.clone().extract_tx();
+ /// # let mut psbt: Psbt = todo!();
+ /// let tx = &psbt.clone().extract_tx().expect("tx");
/// let (sent, received) = wallet.sent_and_received(tx);
/// ```
pub fn sent_and_received(&self, tx: &Transaction) -> (u64, u64) {
&mut self,
coin_selection: Cs,
params: TxParams,
- ) -> Result<psbt::PartiallySignedTransaction, CreateTxError<D::WriteError>>
+ ) -> Result<Psbt, CreateTxError<D::WriteError>>
where
D: PersistBackend<ChangeSet>,
{
};
let mut tx = Transaction {
- version,
+ version: transaction::Version::non_standard(version),
lock_time,
input: vec![],
output: vec![],
let new_out = TxOut {
script_pubkey: script_pubkey.clone(),
- value,
+ value: Amount::from_sat(value),
};
tx.output.push(new_out);
fee_amount += (fee_rate * tx.weight()).to_sat();
- // Segwit transactions' header is 2WU larger than legacy txs' header,
- // as they contain a witness marker (1WU) and a witness flag (1WU) (see BIP144).
- // At this point we really don't know if the resulting transaction will be segwit
- // or legacy, so we just add this 2WU to the fee_amount - overshooting the fee amount
- // is better than undershooting it.
- // If we pass a fee_amount that is slightly higher than the final fee_amount, we
- // end up with a transaction with a slightly higher fee rate than the requested one.
- // If, instead, we undershoot, we may end up with a feerate lower than the requested one
- // - we might come up with non broadcastable txs!
- fee_amount += (fee_rate * Weight::from_wu(2)).to_sat();
-
if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeAllowed
&& internal_descriptor.is_none()
{
// create drain output
let drain_output = TxOut {
- value: *amount,
+ value: Amount::from_sat(*amount),
script_pubkey: drain_script,
};
/// builder.finish()?
/// };
/// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
- /// let tx = psbt.extract_tx();
+ /// let tx = psbt.clone().extract_tx().expect("tx");
/// // broadcast tx but it's taking too long to confirm so we want to bump the fee
/// let mut psbt = {
/// let mut builder = wallet.build_fee_bump(tx.txid())?;
let params = TxParams {
// TODO: figure out what rbf option should be?
- version: Some(tx_builder::Version(tx.version)),
+ version: Some(tx_builder::Version(tx.version.0)),
recipients: tx
.output
.into_iter()
- .map(|txout| (txout.script_pubkey, txout.value))
+ .map(|txout| (txout.script_pubkey, txout.value.to_sat()))
.collect(),
utxos: original_utxos,
bumping_fee: Some(tx_builder::PreviousFee {
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
/// assert!(finalized, "we should have signed all the inputs");
/// # Ok::<(),anyhow::Error>(())
- pub fn sign(
- &self,
- psbt: &mut psbt::PartiallySignedTransaction,
- sign_options: SignOptions,
- ) -> Result<bool, SignerError> {
+ pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<bool, SignerError> {
// This adds all the PSBT metadata for the inputs, which will help us later figure out how
// to derive our keys
self.update_psbt_with_descriptor(psbt)
/// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
pub fn finalize_psbt(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
sign_options: SignOptions,
) -> Result<bool, SignerError> {
let chain_tip = self.chain.tip().block_id();
if must_only_use_confirmed_tx && !confirmation_time.is_confirmed() {
return false;
}
- if tx.is_coin_base() {
+ if tx.is_coinbase() {
debug_assert!(
confirmation_time.is_confirmed(),
"coinbase must always be confirmed"
tx: Transaction,
selected: Vec<Utxo>,
params: TxParams,
- ) -> Result<psbt::PartiallySignedTransaction, CreateTxError<D::WriteError>>
+ ) -> Result<Psbt, CreateTxError<D::WriteError>>
where
D: PersistBackend<ChangeSet>,
{
- let mut psbt = psbt::PartiallySignedTransaction::from_unsigned_tx(tx)?;
+ let mut psbt = Psbt::from_unsigned_tx(tx)?;
if params.add_global_xpubs {
let all_xpubs = self
let is_taproot = foreign_psbt_input
.witness_utxo
.as_ref()
- .map(|txout| txout.script_pubkey.is_v1_p2tr())
+ .map(|txout| txout.script_pubkey.is_p2tr())
.unwrap_or(false);
if !is_taproot
&& !params.only_witness_utxo
Ok(psbt_input)
}
- fn update_psbt_with_descriptor(
- &self,
- psbt: &mut psbt::PartiallySignedTransaction,
- ) -> Result<(), MiniscriptPsbtError> {
+ fn update_psbt_with_descriptor(&self, psbt: &mut Psbt) -> Result<(), MiniscriptPsbtError> {
// We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all
// the input utxos and outputs
let utxos = (0..psbt.inputs.len())
.unwrap();
let address = wallet.get_address(AddressIndex::New).address;
let tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 500_000,
+ value: Amount::from_sat(500_000),
script_pubkey: address.script_pubkey(),
}],
};
//! # use core::str::FromStr;
//! # use bitcoin::secp256k1::{Secp256k1, All};
//! # use bitcoin::*;
-//! # use bitcoin::psbt;
//! # use bdk::signer::*;
//! # use bdk::*;
//! # #[derive(Debug)]
//! # struct CustomHSM;
//! # impl CustomHSM {
-//! # fn hsm_sign_input(&self, _psbt: &mut psbt::PartiallySignedTransaction, _input: usize) -> Result<(), SignerError> {
+//! # fn hsm_sign_input(&self, _psbt: &mut Psbt, _input: usize) -> Result<(), SignerError> {
//! # Ok(())
//! # }
//! # fn connect() -> Self {
//! impl InputSigner for CustomSigner {
//! fn sign_input(
//! &self,
-//! psbt: &mut psbt::PartiallySignedTransaction,
+//! psbt: &mut Psbt,
//! input_index: usize,
//! _sign_options: &SignOptions,
//! _secp: &Secp256k1<All>,
use core::fmt;
use core::ops::{Bound::Included, Deref};
-use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
+use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpriv};
use bitcoin::hashes::hash160;
use bitcoin::secp256k1::Message;
use bitcoin::sighash::{EcdsaSighashType, TapSighash, TapSighashType};
use bitcoin::{ecdsa, psbt, sighash, taproot};
use bitcoin::{key::TapTweak, key::XOnlyPublicKey, secp256k1};
-use bitcoin::{PrivateKey, PublicKey};
+use bitcoin::{PrivateKey, Psbt, PublicKey};
use miniscript::descriptor::{
Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
/// Sign a single psbt input
fn sign_input(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
input_index: usize,
sign_options: &SignOptions,
secp: &SecpCtx,
/// Sign all the inputs of the psbt
fn sign_transaction(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
sign_options: &SignOptions,
secp: &SecpCtx,
) -> Result<(), SignerError>;
impl<T: InputSigner> TransactionSigner for T {
fn sign_transaction(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
sign_options: &SignOptions,
secp: &SecpCtx,
) -> Result<(), SignerError> {
}
}
-impl SignerCommon for SignerWrapper<DescriptorXKey<ExtendedPrivKey>> {
+impl SignerCommon for SignerWrapper<DescriptorXKey<Xpriv>> {
fn id(&self, secp: &SecpCtx) -> SignerId {
SignerId::from(self.root_fingerprint(secp))
}
}
}
-impl InputSigner for SignerWrapper<DescriptorXKey<ExtendedPrivKey>> {
+impl InputSigner for SignerWrapper<DescriptorXKey<Xpriv>> {
fn sign_input(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
input_index: usize,
sign_options: &SignOptions,
secp: &SecpCtx,
.collect()
}
-impl SignerCommon for SignerWrapper<DescriptorMultiXKey<ExtendedPrivKey>> {
+impl SignerCommon for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
fn id(&self, secp: &SecpCtx) -> SignerId {
SignerId::from(self.root_fingerprint(secp))
}
}
}
-impl InputSigner for SignerWrapper<DescriptorMultiXKey<ExtendedPrivKey>> {
+impl InputSigner for SignerWrapper<DescriptorMultiXKey<Xpriv>> {
fn sign_input(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
input_index: usize,
sign_options: &SignOptions,
secp: &SecpCtx,
impl InputSigner for SignerWrapper<PrivateKey> {
fn sign_input(
&self,
- psbt: &mut psbt::PartiallySignedTransaction,
+ psbt: &mut Psbt,
input_index: usize,
sign_options: &SignOptions,
secp: &SecpCtx,
hash_ty: TapSighashType,
secp: &SecpCtx,
) {
- let keypair = secp256k1::KeyPair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
+ let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
let keypair = match leaf_hash {
None => keypair
.tap_tweak(secp, psbt_input.tap_merkle_root)
type SighashType;
fn sighash(
- psbt: &psbt::PartiallySignedTransaction,
+ psbt: &Psbt,
input_index: usize,
extra: Self::Extra,
) -> Result<(Self::Sighash, Self::SighashType), SignerError>;
type SighashType = EcdsaSighashType;
fn sighash(
- psbt: &psbt::PartiallySignedTransaction,
+ psbt: &Psbt,
input_index: usize,
_extra: (),
) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
type SighashType = EcdsaSighashType;
fn sighash(
- psbt: &psbt::PartiallySignedTransaction,
+ psbt: &Psbt,
input_index: usize,
_extra: (),
) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
let psbt_input = &psbt.inputs[input_index];
let tx_input = &psbt.unsigned_tx.input[input_index];
- let sighash = psbt_input
+ let sighash_type = psbt_input
.sighash_type
.unwrap_or_else(|| EcdsaSighashType::All.into())
.ecdsa_hash_ty()
};
let value = utxo.value;
- let script = match psbt_input.witness_script {
- Some(ref witness_script) => witness_script.clone(),
+ let mut sighasher = sighash::SighashCache::new(&psbt.unsigned_tx);
+
+ let sighash = match psbt_input.witness_script {
+ Some(ref witness_script) => {
+ sighasher.p2wsh_signature_hash(input_index, witness_script, value, sighash_type)?
+ }
None => {
- if utxo.script_pubkey.is_v0_p2wpkh() {
- utxo.script_pubkey
- .p2wpkh_script_code()
- .expect("We check above that the spk is a p2wpkh")
+ if utxo.script_pubkey.is_p2wpkh() {
+ sighasher.p2wpkh_signature_hash(
+ input_index,
+ &utxo.script_pubkey,
+ value,
+ sighash_type,
+ )?
} else if psbt_input
.redeem_script
.as_ref()
- .map(|s| s.is_v0_p2wpkh())
+ .map(|s| s.is_p2wpkh())
.unwrap_or(false)
{
- psbt_input
- .redeem_script
- .as_ref()
- .unwrap()
- .p2wpkh_script_code()
- .expect("We check above that the spk is a p2wpkh")
+ let script_pubkey = psbt_input.redeem_script.as_ref().unwrap();
+ sighasher.p2wpkh_signature_hash(
+ input_index,
+ script_pubkey,
+ value,
+ sighash_type,
+ )?
} else {
return Err(SignerError::MissingWitnessScript);
}
}
};
-
- Ok((
- sighash::SighashCache::new(&psbt.unsigned_tx).segwit_signature_hash(
- input_index,
- &script,
- value,
- sighash,
- )?,
- sighash,
- ))
+ Ok((sighash, sighash_type))
}
}
type SighashType = TapSighashType;
fn sighash(
- psbt: &psbt::PartiallySignedTransaction,
+ psbt: &Psbt,
input_index: usize,
extra: Self::Extra,
) -> Result<(Self::Sighash, TapSighashType), SignerError> {
impl TransactionSigner for DummySigner {
fn sign_transaction(
&self,
- _psbt: &mut psbt::PartiallySignedTransaction,
+ _psbt: &mut Psbt,
_sign_options: &SignOptions,
_secp: &SecpCtx,
) -> Result<(), SignerError> {
) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
let secp: Secp256k1<All> = Secp256k1::new();
let path = bip32::DerivationPath::from_str(PATH).unwrap();
- let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap();
- let tpub = bip32::ExtendedPubKey::from_priv(&secp, &tprv);
+ let tprv = bip32::Xpriv::from_str(tprv).unwrap();
+ let tpub = bip32::Xpub::from_priv(&secp, &tprv);
let fingerprint = tprv.fingerprint(&secp);
let prvkey = (tprv, path.clone()).into_descriptor_key().unwrap();
let pubkey = (tpub, path).into_descriptor_key().unwrap();
use core::marker::PhantomData;
use bdk_chain::PersistBackend;
-use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt};
+use bitcoin::psbt::{self, Psbt};
use bitcoin::script::PushBytes;
use bitcoin::{absolute, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid};
use bdk_chain::ConfirmationTime;
use bitcoin::consensus::deserialize;
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
+ use bitcoin::TxOut;
use super::*;
.unwrap()
);
- assert_eq!(tx.output[0].value, 800);
+ assert_eq!(tx.output[0].value.to_sat(), 800);
assert_eq!(tx.output[1].script_pubkey, ScriptBuf::from(vec![0xAA]));
assert_eq!(
tx.output[2].script_pubkey,
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
vout: 0,
},
- txout: Default::default(),
+ txout: TxOut::NULL,
keychain: KeychainKind::External,
is_spent: false,
confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
vout: 1,
},
- txout: Default::default(),
+ txout: TxOut::NULL,
keychain: KeychainKind::Internal,
is_spent: false,
confirmation_time: ConfirmationTime::Confirmed {
.require_network(Network::Bitcoin)
.unwrap()
.script_pubkey();
- assert!(script_p2wpkh.is_v0_p2wpkh());
+ assert!(script_p2wpkh.is_p2wpkh());
assert!(293.is_dust(&script_p2wpkh));
assert!(!294.is_dust(&script_p2wpkh));
}
use bdk_chain::indexed_tx_graph::Indexer;
use bdk_chain::{BlockId, ConfirmationTime};
use bitcoin::hashes::Hash;
-use bitcoin::{Address, BlockHash, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut, Txid};
+use bitcoin::{
+ transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut,
+ Txid,
+};
use std::str::FromStr;
// Return a fake wallet that appears to be funded for testing.
.unwrap();
let tx0 = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: bitcoin::absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
witness: Default::default(),
}],
output: vec![TxOut {
- value: 76_000,
+ value: Amount::from_sat(76_000),
script_pubkey: change_address.script_pubkey(),
}],
};
let tx1 = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: bitcoin::absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
}],
output: vec![
TxOut {
- value: 50_000,
+ value: Amount::from_sat(50_000),
script_pubkey: change_address.script_pubkey(),
},
TxOut {
- value: 25_000,
+ value: Amount::from_sat(25_000),
script_pubkey: sendto_address.script_pubkey(),
},
],
-use bdk::bitcoin::FeeRate;
-use bdk::bitcoin::TxIn;
+use bdk::bitcoin::{Amount, FeeRate, Psbt, TxIn};
use bdk::wallet::AddressIndex;
use bdk::wallet::AddressIndex::New;
use bdk::{psbt, SignOptions};
-use bitcoin::psbt::PartiallySignedTransaction as Psbt;
use core::str::FromStr;
mod common;
use common::*;
use bdk::signer::{SignerContext, SignerOrdering, SignerWrapper};
use bdk::KeychainKind;
use bitcoin::key::TapTweak;
- use bitcoin::secp256k1::{schnorr, KeyPair, Message, Secp256k1, XOnlyPublicKey};
+ use bitcoin::secp256k1::{schnorr, Keypair, Message, Secp256k1, XOnlyPublicKey};
use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType};
use bitcoin::{PrivateKey, TxOut};
use std::sync::Arc;
let wif = "cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG";
let desc = format!("tr({})", wif);
let prv = PrivateKey::from_wif(wif).unwrap();
- let keypair = KeyPair::from_secret_key(&secp, &prv.inner);
+ let keypair = Keypair::from_secret_key(&secp, &prv.inner);
let (mut wallet, _) = get_funded_wallet(&desc);
let to_spend = wallet.get_balance().total();
// the prevout we're spending
let prevouts = &[TxOut {
script_pubkey: send_to.script_pubkey(),
- value: to_spend,
+ value: Amount::from_sat(to_spend),
}];
let prevouts = Prevouts::All(prevouts);
let input_index = 0;
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::taproot::TapNodeHash;
use bitcoin::{
- absolute, Address, Amount, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, Sequence,
- Transaction, TxIn, TxOut, Txid, Weight,
+ absolute, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, ScriptBuf,
+ Sequence, Transaction, TxIn, TxOut, Txid, Weight,
};
mod common;
fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) -> OutPoint {
let tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(LastUnused).script_pubkey(),
- value,
+ value: Amount::from_sat(value),
}],
};
assert_eq!(txos.len(), 2);
for (op, txo) in txos {
if op.txid == txid {
- assert_eq!(txo.txout.value, 50_000);
+ assert_eq!(txo.txout.value.to_sat(), 50_000);
assert!(!txo.is_spent);
} else {
- assert_eq!(txo.txout.value, 76_000);
+ assert_eq!(txo.txout.value.to_sat(), 76_000);
assert!(txo.is_spent);
}
}
($psbt:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
let psbt = $psbt.clone();
#[allow(unused_mut)]
- let mut tx = $psbt.clone().extract_tx();
+ let mut tx = $psbt.clone().extract_tx().expect("failed to extract tx");
$(
$( $add_signature )*
for txin in &mut tx.input {
let fee_amount = psbt
.inputs
.iter()
- .fold(0, |acc, i| acc + i.witness_utxo.as_ref().unwrap().value)
+ .fold(0, |acc, i| acc + i.witness_utxo.as_ref().unwrap().value.to_sat())
- psbt
.unsigned_tx
.output
.iter()
- .fold(0, |acc, o| acc + o.value);
+ .fold(0, |acc, o| acc + o.value.to_sat());
assert_eq!(fee_amount, $fees);
.version(42);
let psbt = builder.finish().unwrap();
- assert_eq!(psbt.unsigned_tx.version, 42);
+ assert_eq!(psbt.unsigned_tx.version.0, 42);
}
#[test]
macro_rules! check_fee {
($wallet:expr, $psbt: expr) => {{
- let tx = $psbt.clone().extract_tx();
+ let tx = $psbt.clone().extract_tx().expect("failed to extract tx");
let tx_fee = $wallet.calculate_fee(&tx).ok();
assert_eq!(tx_fee, $psbt.fee_amount());
tx_fee
let fee = check_fee!(wallet, psbt);
assert_eq!(psbt.unsigned_tx.output.len(), 1);
- assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0));
+ assert_eq!(
+ psbt.unsigned_tx.output[0].value.to_sat(),
+ 50_000 - fee.unwrap_or(0)
+ );
}
#[test]
.iter()
.find(|x| x.script_pubkey == drain_addr.script_pubkey())
.unwrap();
- assert_eq!(main_output.value, 20_000,);
- assert_eq!(drain_output.value, 30_000 - fee.unwrap_or(0));
+ assert_eq!(main_output.value.to_sat(), 20_000,);
+ assert_eq!(drain_output.value.to_sat(), 30_000 - fee.unwrap_or(0));
}
#[test]
let fee = check_fee!(wallet, psbt);
assert_eq!(psbt.unsigned_tx.output.len(), 1);
- assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0));
+ assert_eq!(
+ psbt.unsigned_tx.output[0].value.to_sat(),
+ 50_000 - fee.unwrap_or(0)
+ );
}
#[test]
assert_eq!(fee.unwrap_or(0), 100);
assert_eq!(psbt.unsigned_tx.output.len(), 1);
- assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0));
+ assert_eq!(
+ psbt.unsigned_tx.output[0].value.to_sat(),
+ 50_000 - fee.unwrap_or(0)
+ );
}
#[test]
assert_eq!(fee.unwrap_or(0), 0);
assert_eq!(psbt.unsigned_tx.output.len(), 1);
- assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0));
+ assert_eq!(
+ psbt.unsigned_tx.output[0].value.to_sat(),
+ 50_000 - fee.unwrap_or(0)
+ );
}
#[test]
let fee = check_fee!(wallet, psbt);
assert_eq!(psbt.unsigned_tx.output.len(), 2);
- assert_eq!(psbt.unsigned_tx.output[0].value, 25_000);
- assert_eq!(psbt.unsigned_tx.output[1].value, 25_000 - fee.unwrap_or(0));
+ assert_eq!(psbt.unsigned_tx.output[0].value.to_sat(), 25_000);
+ assert_eq!(
+ psbt.unsigned_tx.output[1].value.to_sat(),
+ 25_000 - fee.unwrap_or(0)
+ );
}
#[test]
let fee = check_fee!(wallet, psbt);
assert_eq!(psbt.unsigned_tx.output.len(), 1);
- assert_eq!(psbt.unsigned_tx.output[0].value, 49_800);
+ assert_eq!(psbt.unsigned_tx.output[0].value.to_sat(), 49_800);
assert_eq!(fee.unwrap_or(0), 200);
}
let fee = check_fee!(wallet, psbt);
assert_eq!(psbt.unsigned_tx.output.len(), 3);
- assert_eq!(psbt.unsigned_tx.output[0].value, 10_000 - fee.unwrap_or(0));
- assert_eq!(psbt.unsigned_tx.output[1].value, 10_000);
- assert_eq!(psbt.unsigned_tx.output[2].value, 30_000);
+ assert_eq!(
+ psbt.unsigned_tx.output[0].value.to_sat(),
+ 10_000 - fee.unwrap_or(0)
+ );
+ assert_eq!(psbt.unsigned_tx.output[1].value.to_sat(), 10_000);
+ assert_eq!(psbt.unsigned_tx.output[2].value.to_sat(), 30_000);
}
#[test]
#[test]
fn test_create_tx_set_redeem_script_p2sh() {
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
let (mut wallet, _) =
get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
#[test]
fn test_create_tx_set_witness_script_p2wsh() {
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
let (mut wallet, _) =
get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
)
.unwrap();
- assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_v0_p2wsh()));
+ assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_p2wsh()));
assert_eq!(psbt.inputs[0].witness_script, Some(script));
}
let small_output_tx = Transaction {
input: vec![],
output: vec![TxOut {
- value: 25_000,
+ value: Amount::from_sat(25_000),
script_pubkey: wallet.get_address(New).address.script_pubkey(),
}],
- version: 0,
+ version: transaction::Version::non_standard(0),
lock_time: absolute::LockTime::ZERO,
};
wallet
})
.unwrap();
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
assert_eq!(
psbt.unsigned_tx.input.len(),
let small_output_tx = Transaction {
input: vec![],
output: vec![TxOut {
- value: 25_000,
+ value: Amount::from_sat(25_000),
script_pubkey: wallet.get_address(New).address.script_pubkey(),
}],
- version: 0,
+ version: transaction::Version::non_standard(0),
lock_time: absolute::LockTime::ZERO,
};
let mut wallet = Wallet::new_no_persist(descriptors, None, Network::Regtest).unwrap();
let tx = Transaction {
- version: 0,
+ version: transaction::Version::non_standard(0),
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 50_000,
+ value: Amount::from_sat(50_000),
script_pubkey: wallet.get_address(New).script_pubkey(),
}],
};
#[test]
fn test_create_tx_global_xpubs_with_origin() {
use bitcoin::bip32;
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)");
let addr = wallet.get_address(New);
.add_global_xpubs();
let psbt = builder.finish().unwrap();
- let key = bip32::ExtendedPubKey::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap();
+ let key = bip32::Xpub::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap();
let fingerprint = bip32::Fingerprint::from_hex("73756c7f").unwrap();
let path = bip32::DerivationPath::from_str("m/48'/0'/0'/2'").unwrap();
let mut psbt = builder.finish().unwrap();
wallet1.insert_txout(utxo.outpoint, utxo.txout);
let fee = check_fee!(wallet1, psbt);
- let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
assert_eq!(
sent_received.0 - sent_received.1,
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
wallet1.calculate_fee(&tx).unwrap();
}
#[test]
fn test_create_tx_global_xpubs_master_without_origin() {
use bitcoin::bip32;
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)");
let addr = wallet.get_address(New);
.add_global_xpubs();
let psbt = builder.finish().unwrap();
- let key = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap();
+ let key = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap();
let fingerprint = bip32::Fingerprint::from_hex("997a323b").unwrap();
assert_eq!(psbt.xpub.len(), 1);
builder.add_recipient(addr.script_pubkey(), 25_000);
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
builder.add_recipient(addr.script_pubkey(), 25_000);
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
let psbt = builder.finish().unwrap();
let feerate = psbt.fee_rate().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.add_recipient(addr.script_pubkey(), 25_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let original_sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let original_fee = check_fee!(wallet, psbt);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.fee_rate(feerate).enable_rbf();
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 25_000
+ Amount::from_sat(25_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
builder.fee_absolute(200);
builder.enable_rbf();
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 25_000
+ Amount::from_sat(25_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
.drain_wallet()
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.clone().extract_tx();
+ let tx = psbt.clone().extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let original_fee = check_fee!(wallet, psbt);
let txid = tx.txid();
.allow_shrinking(addr.script_pubkey())
.unwrap();
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0);
let tx = &psbt.unsigned_tx;
assert_eq!(tx.output.len(), 1);
- assert_eq!(tx.output[0].value + fee.unwrap_or(0), sent_received.0);
+ assert_eq!(
+ tx.output[0].value.to_sat() + fee.unwrap_or(0),
+ sent_received.0
+ );
assert_fee_rate!(psbt, fee.unwrap_or(0), feerate, @add_signature);
}
.enable_rbf();
let psbt = builder.finish().unwrap();
let original_fee = check_fee!(wallet, psbt);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
wallet
assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0));
assert_eq!(tx.output.len(), 1);
- assert_eq!(tx.output[0].value + fee.unwrap_or(0), sent_received.0);
+ assert_eq!(
+ tx.output[0].value.to_sat() + fee.unwrap_or(0),
+ sent_received.0
+ );
assert_eq!(fee.unwrap_or(0), 300);
}
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
// receive an extra tx so that our wallet has two utxos.
let tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 25_000,
+ value: Amount::from_sat(25_000),
script_pubkey: wallet.get_address(New).script_pubkey(),
}],
};
.manually_selected_only()
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
.unwrap()
.fee_rate(FeeRate::from_sat_per_vb_unchecked(5));
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.extract_tx());
+ let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx"));
assert_eq!(sent_received.0, 75_000);
}
// existing output. In other words, bump_fee + manually_selected_only is always an error
// unless you've also set "allow_shrinking" OR there is a change output.
let init_tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(New).script_pubkey(),
- value: 25_000,
+ value: Amount::from_sat(25_000),
}],
};
wallet
.manually_selected_only()
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
wallet
fn test_bump_fee_add_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let init_tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
script_pubkey: wallet.get_address(New).script_pubkey(),
- value: 25_000,
+ value: Amount::from_sat(25_000),
}],
};
let pos = wallet
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let original_details = wallet.sent_and_received(&tx);
let txid = tx.txid();
wallet
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50));
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_details.0 + 25_000);
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 45_000
+ Amount::from_sat(45_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
wallet
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.fee_absolute(6_000);
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 45_000
+ Amount::from_sat(45_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
.manually_selected_only()
.enable_rbf();
let psbt = builder.finish().unwrap();
- let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let original_sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let original_fee = check_fee!(wallet, psbt);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50));
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
let original_send_all_amount = original_sent_received.0 - original_fee.unwrap_or(0);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- original_send_all_amount
+ Amount::from_sat(original_send_all_amount)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
75_000 - original_send_all_amount - fee.unwrap_or(0)
);
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let original_sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let original_sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let original_fee = check_fee!(wallet, psbt);
- let mut tx = psbt.extract_tx();
+ let mut tx = psbt.extract_tx().expect("failed to extract tx");
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // to get realistic weight
}
let fee_abs = 50_000 + 25_000 - 45_000 - 10;
builder.fee_rate(Amount::from_sat(fee_abs) / new_tx_weight);
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(original_sent_received.1, 5_000 - original_fee.unwrap_or(0));
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 45_000
+ Amount::from_sat(45_000)
);
assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(140), @dust_change, @add_signature);
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let mut tx = psbt.extract_tx();
+ let mut tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
for txin in &mut tx.input {
.unwrap()
.fee_rate(FeeRate::from_sat_per_vb_unchecked(5));
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 45_000
+ Amount::from_sat(45_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
.add_recipient(addr.script_pubkey(), 45_000)
.enable_rbf();
let psbt = builder.finish().unwrap();
- let mut tx = psbt.extract_tx();
+ let mut tx = psbt.extract_tx().expect("failed to extract tx");
let original_sent_received = wallet.sent_and_received(&tx);
let txid = tx.txid();
// skip saving the new utxos, we know they can't be used anyways
let mut builder = wallet.build_fee_bump(txid).unwrap();
builder.add_utxo(incoming_op).unwrap().fee_absolute(250);
let psbt = builder.finish().unwrap();
- let sent_received = wallet.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000);
.find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap()
.value,
- 45_000
+ Amount::from_sat(45_000)
);
assert_eq!(
tx.output
.iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap()
- .value,
+ .value
+ .to_sat(),
sent_received.1
);
25_000,
ConfirmationTime::Unconfirmed { last_seen: 0 },
);
- let mut tx = psbt.extract_tx();
+ let mut tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
.drain_to(addr.script_pubkey())
.enable_rbf();
let psbt = builder.finish().unwrap();
- let mut tx = psbt.extract_tx();
+ let mut tx = psbt.extract_tx().expect("failed to extract tx");
let txid = tx.txid();
for txin in &mut tx.input {
txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
assert!(finalized);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(extracted.input[0].witness.len(), 2);
}
// add another input to the psbt that is at least passable.
let dud_input = bitcoin::psbt::Input {
witness_utxo: Some(TxOut {
- value: 100_000,
+ value: Amount::from_sat(100_000),
script_pubkey: miniscript::Descriptor::<bitcoin::PublicKey>::from_str(
"wpkh(025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357)",
)
"Should finalize the input since we can produce signatures"
);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(
*extracted.input[0].witness.to_vec()[0].last().unwrap(),
sighash.to_u32() as u8,
#[test]
fn test_get_address() {
use bdk::descriptor::template::Bip84;
- let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let mut wallet = Wallet::new_no_persist(
Bip84(key, KeychainKind::External),
Some(Bip84(key, KeychainKind::Internal)),
use bdk::descriptor::template::Bip84;
use std::collections::HashSet;
- let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+ let key = bitcoin::bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let mut wallet =
Wallet::new_no_persist(Bip84(key, KeychainKind::External), None, Network::Regtest).unwrap();
#[test]
fn test_taproot_psbt_input_tap_tree() {
- use bitcoin::hashes::hex::FromHex;
+ use bitcoin::hex::FromHex;
use bitcoin::taproot;
let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree());
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap();
let psbt = builder.finish().unwrap();
- let sent_received = wallet1.sent_and_received(&psbt.clone().extract_tx());
+ let sent_received =
+ wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
wallet1.insert_txout(utxo.outpoint, utxo.txout);
let fee = check_fee!(wallet1, psbt);
"Should finalize the input since we can produce signatures"
);
- let extracted = psbt.extract_tx();
+ let extracted = psbt.extract_tx().expect("failed to extract tx");
assert_eq!(
*extracted.input[0].witness.to_vec()[0].last().unwrap(),
sighash as u8,
})
.unwrap();
let coinbase_tx = Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
..Default::default()
}],
output: vec![TxOut {
- value: 25_000,
+ value: Amount::from_sat(25_000),
script_pubkey: wallet.get_address(New).address.script_pubkey(),
}],
};
.unwrap();
assert_eq!(change_derivation_2, (KeychainKind::Internal, 1));
- wallet.cancel_tx(&psbt1.extract_tx());
+ wallet.cancel_tx(&psbt1.extract_tx().expect("failed to extract tx"));
let psbt3 = new_tx!(wallet);
let change_derivation_3 = psbt3
.unwrap();
assert_eq!(change_derivation_3, (KeychainKind::Internal, 2));
- wallet.cancel_tx(&psbt3.extract_tx());
+ wallet.cancel_tx(&psbt3.extract_tx().expect("failed to extract tx"));
let psbt3 = new_tx!(wallet);
let change_derivation_4 = psbt3
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
-bitcoin = { version = "0.30", default-features = false }
-bitcoincore-rpc = { version = "0.17" }
+bitcoin = { version = "0.31", default-features = false }
+bitcoincore-rpc = { version = "0.18" }
bdk_chain = { path = "../chain", version = "0.11", default-features = false }
[dev-dependencies]
.rpc_client()
.get_new_address(None, None)?
.assume_checked();
- let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros());
+ let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros());
let addr_to_track = Address::from_script(&spk_to_track, bitcoin::Network::Regtest)?;
// setup receiver
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
-bitcoin = { version = "0.30.0", default-features = false }
+bitcoin = { version = "0.31.0", default-features = false }
serde_crate = { package = "serde", version = "1", optional = true, features = ["derive", "rc"] }
# Use hashbrown as a feature flag to have HashSet and HashMap from it.
hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
-miniscript = { version = "10.0.0", optional = true, default-features = false }
+miniscript = { version = "11.0.0", optional = true, default-features = false }
[dev-dependencies]
rand = "0.8"
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
indexed_tx_graph::Indexer,
};
-use bitcoin::{self, OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid};
+use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid};
/// An index storing [`TxOut`]s that have a script pubkey that matches those in a list.
///
for txin in &tx.input {
if let Some((_, txout)) = self.txout(txin.previous_output) {
- sent += txout.value;
+ sent += txout.value.to_sat();
}
}
for txout in &tx.output {
if self.index_of_spk(&txout.script_pubkey).is_some() {
- received += txout.value;
+ received += txout.value.to_sat();
}
}
///
/// [`insert_txout`]: Self::insert_txout
pub fn calculate_fee(&self, tx: &Transaction) -> Result<u64, CalculateFeeError> {
- if tx.is_coin_base() {
+ if tx.is_coinbase() {
return Ok(0);
}
(sum, missing_outpoints)
}
Some(txout) => {
- sum += txout.value as i64;
+ sum += txout.value.to_sat() as i64;
(sum, missing_outpoints)
}
},
let outputs_sum = tx
.output
.iter()
- .map(|txout| txout.value as i64)
+ .map(|txout| txout.value.to_sat() as i64)
.sum::<i64>();
let fee = inputs_sum - outputs_sum;
TxNodeInternal::Whole(tx) => {
// A coinbase tx that is not anchored in the best chain cannot be unconfirmed and
// should always be filtered out.
- if tx.as_ref().is_coin_base() {
+ if tx.is_coinbase() {
return Ok(None);
}
tx.clone()
txout,
chain_position,
spent_by,
- is_on_coinbase: tx_node.tx.as_ref().is_coin_base(),
+ is_on_coinbase: tx_node.tx.is_coinbase(),
},
)))
},
match &txout.chain_position {
ChainPosition::Confirmed(_) => {
if txout.is_confirmed_and_spendable(chain_tip.height) {
- confirmed += txout.txout.value;
+ confirmed += txout.txout.value.to_sat();
} else if !txout.is_mature(chain_tip.height) {
- immature += txout.txout.value;
+ immature += txout.txout.value.to_sat();
}
}
ChainPosition::Unconfirmed(_) => {
if trust_predicate(&spk_i, &txout.txout.script_pubkey) {
- trusted_pending += txout.txout.value;
+ trusted_pending += txout.txout.value.to_sat();
} else {
- untrusted_pending += txout.txout.value;
+ untrusted_pending += txout.txout.value.to_sat();
}
}
}
#[allow(unused)]
pub fn new_tx(lt: u32) -> bitcoin::Transaction {
bitcoin::Transaction {
- version: 0x00,
+ version: bitcoin::transaction::Version::non_standard(0x00),
lock_time: bitcoin::absolute::LockTime::from_consensus(lt),
input: vec![],
output: vec![],
use bdk_chain::{tx_graph::TxGraph, Anchor, SpkTxOutIndex};
use bitcoin::{
- locktime::absolute::LockTime, secp256k1::Secp256k1, OutPoint, ScriptBuf, Sequence, Transaction,
- TxIn, TxOut, Txid, Witness,
+ locktime::absolute::LockTime, secp256k1::Secp256k1, transaction, Amount, OutPoint, ScriptBuf,
+ Sequence, Transaction, TxIn, TxOut, Txid, Witness,
};
use miniscript::Descriptor;
for (bogus_txin_vout, tx_tmp) in tx_templates.into_iter().enumerate() {
let tx = Transaction {
- version: 0,
+ version: transaction::Version::non_standard(0),
lock_time: LockTime::ZERO,
input: tx_tmp
.inputs
.iter()
.map(|output| match &output.spk_index {
None => TxOut {
- value: output.value,
+ value: Amount::from_sat(output.value),
script_pubkey: ScriptBuf::new(),
},
Some(index) => TxOut {
- value: output.value,
+ value: Amount::from_sat(output.value),
script_pubkey: spk_index.spk_at_index(index).unwrap().to_owned(),
},
})
local_chain::LocalChain,
tx_graph, ChainPosition, ConfirmationHeightAnchor,
};
-use bitcoin::{secp256k1::Secp256k1, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut};
+use bitcoin::{
+ secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
+};
use miniscript::Descriptor;
/// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented
let tx_a = Transaction {
output: vec![
TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: spk_0,
},
TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: spk_1,
},
],
..Default::default()
}],
output: vec![TxOut {
- value: 70000,
+ value: Amount::from_sat(70000),
script_pubkey: trusted_spks[0].to_owned(),
}],
..common::new_tx(0)
// tx2 is an incoming transaction received at untrusted keychain at block 1.
let tx2 = Transaction {
output: vec![TxOut {
- value: 30000,
+ value: Amount::from_sat(30000),
script_pubkey: untrusted_spks[0].to_owned(),
}],
..common::new_tx(0)
..Default::default()
}],
output: vec![TxOut {
- value: 10000,
+ value: Amount::from_sat(10000),
script_pubkey: trusted_spks[1].to_owned(),
}],
..common::new_tx(0)
// tx4 is an external transaction receiving at untrusted keychain, unconfirmed.
let tx4 = Transaction {
output: vec![TxOut {
- value: 20000,
+ value: Amount::from_sat(20000),
script_pubkey: untrusted_spks[1].to_owned(),
}],
..common::new_tx(0)
// tx5 is spending tx3 and receiving change at trusted keychain, unconfirmed.
let tx5 = Transaction {
output: vec![TxOut {
- value: 15000,
+ value: Amount::from_sat(15000),
script_pubkey: trusted_spks[2].to_owned(),
}],
..common::new_tx(0)
Append,
};
-use bitcoin::{secp256k1::Secp256k1, OutPoint, ScriptBuf, Transaction, TxOut};
+use bitcoin::{secp256k1::Secp256k1, Amount, OutPoint, ScriptBuf, Transaction, TxOut};
use miniscript::{Descriptor, DescriptorPublicKey};
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
.at_derivation_index(external_index)
.unwrap()
.script_pubkey(),
- value: 10_000,
+ value: Amount::from_sat(10_000),
},
TxOut {
script_pubkey: internal_desc
.at_derivation_index(internal_index)
.unwrap()
.script_pubkey(),
- value: 10_000,
+ value: Amount::from_sat(10_000),
},
],
..common::new_tx(external_index)
let op = OutPoint::new(h!("fake tx"), spk_i);
let txout = TxOut {
script_pubkey: spk.clone(),
- value: 0,
+ value: Amount::ZERO,
};
let changeset = txout_index.index_txout(op, &txout);
let op = OutPoint::new(h!("fake tx"), 41);
let txout = TxOut {
script_pubkey: spk_41,
- value: 0,
+ value: Amount::ZERO,
};
let changeset = txout_index.index_txout(op, &txout);
assert!(changeset.is_empty());
use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex};
-use bitcoin::{absolute, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
+use bitcoin::{absolute, transaction, Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut};
#[test]
fn spk_txout_sent_and_received() {
index.insert_spk(1, spk2.clone());
let tx1 = Transaction {
- version: 0x02,
+ version: transaction::Version::TWO,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 42_000,
+ value: Amount::from_sat(42_000),
script_pubkey: spk1.clone(),
}],
};
);
let tx2 = Transaction {
- version: 0x1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
}],
output: vec![
TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: spk2,
},
TxOut {
script_pubkey: spk1,
- value: 30_000,
+ value: Amount::from_sat(30_000),
},
],
};
assert!(spk_index.is_used(&1));
let tx1 = Transaction {
- version: 0x02,
+ version: transaction::Version::TWO,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 42_000,
+ value: Amount::from_sat(42_000),
script_pubkey: spk1,
}],
};
Anchor, Append, BlockId, ChainOracle, ChainPosition, ConfirmationHeightAnchor,
};
use bitcoin::{
- absolute, hashes::Hash, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid,
+ absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn,
+ TxOut, Txid,
};
use common::*;
use core::iter;
(
OutPoint::new(h!("tx1"), 1),
TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
},
),
(
OutPoint::new(h!("tx1"), 2),
TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
},
),
let update_ops = [(
OutPoint::new(h!("tx2"), 0),
TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
},
)];
// One full transaction to be included in the update
let update_txs = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
..Default::default()
}],
output: vec![TxOut {
- value: 30_000,
+ value: Amount::from_sat(30_000),
script_pubkey: ScriptBuf::new(),
}],
};
(
1u32,
&TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
}
),
(
2u32,
&TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
}
)
[(
0u32,
&TxOut {
- value: 30_000,
+ value: Amount::from_sat(30_000),
script_pubkey: ScriptBuf::new()
}
)]
#[test]
fn insert_tx_graph_doesnt_count_coinbase_as_spent() {
let tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
#[test]
fn insert_tx_graph_keeps_track_of_spend() {
let tx1 = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
};
let op = OutPoint {
};
let tx2 = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: op,
#[test]
fn insert_tx_can_retrieve_full_tx_from_graph() {
let tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
..Default::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
};
let mut graph = TxGraph::<()>::default();
fn insert_tx_displaces_txouts() {
let mut tx_graph = TxGraph::<()>::default();
let tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 42_000,
- script_pubkey: ScriptBuf::default(),
+ value: Amount::from_sat(42_000),
+ script_pubkey: ScriptBuf::new(),
}],
};
vout: 0,
},
TxOut {
- value: 1_337_000,
+ value: Amount::from_sat(1_337_000),
script_pubkey: ScriptBuf::default(),
},
);
vout: 0,
},
TxOut {
- value: 1_000_000_000,
- script_pubkey: ScriptBuf::default(),
+ value: Amount::from_sat(1_000_000_000),
+ script_pubkey: ScriptBuf::new(),
},
);
})
.unwrap()
.value,
- 42_000
+ Amount::from_sat(42_000)
);
assert_eq!(
tx_graph.get_txout(OutPoint {
fn insert_txout_does_not_displace_tx() {
let mut tx_graph = TxGraph::<()>::default();
let tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 42_000,
- script_pubkey: ScriptBuf::default(),
+ value: Amount::from_sat(42_000),
+ script_pubkey: ScriptBuf::new(),
}],
};
vout: 0,
},
TxOut {
- value: 1_337_000,
- script_pubkey: ScriptBuf::default(),
+ value: Amount::from_sat(1_337_000),
+ script_pubkey: ScriptBuf::new(),
},
);
vout: 0,
},
TxOut {
- value: 1_000_000_000,
- script_pubkey: ScriptBuf::default(),
+ value: Amount::from_sat(1_000_000_000),
+ script_pubkey: ScriptBuf::new(),
},
);
})
.unwrap()
.value,
- 42_000
+ Amount::from_sat(42_000)
);
assert_eq!(
tx_graph.get_txout(OutPoint {
fn test_calculate_fee() {
let mut graph = TxGraph::<()>::default();
let intx1 = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 100,
- ..Default::default()
+ value: Amount::from_sat(100),
+ script_pubkey: ScriptBuf::new(),
}],
};
let intx2 = Transaction {
- version: 0x02,
+ version: transaction::Version::TWO,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![TxOut {
- value: 200,
- ..Default::default()
+ value: Amount::from_sat(200),
+ script_pubkey: ScriptBuf::new(),
}],
};
vout: 0,
},
TxOut {
- value: 300,
- ..Default::default()
+ value: Amount::from_sat(300),
+ script_pubkey: ScriptBuf::new(),
},
);
let _ = graph.insert_txout(intxout1.0, intxout1.1);
let mut tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![
TxIn {
},
],
output: vec![TxOut {
- value: 500,
- ..Default::default()
+ value: Amount::from_sat(500),
+ script_pubkey: ScriptBuf::new(),
}],
};
#[test]
fn test_calculate_fee_on_coinbase() {
let tx = Transaction {
- version: 0x01,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint::null(),
..Default::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
};
let graph = TxGraph::<()>::default();
previous_output: OutPoint::new(h!("op0"), 0),
..TxIn::default()
}],
- output: vec![TxOut::default(), TxOut::default()],
+ output: vec![TxOut::NULL, TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_a0.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default(), TxOut::default()],
+ output: vec![TxOut::NULL, TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_a0.txid(), 1),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(h!("op1"), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_b0.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_b0.txid(), 1),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
..TxIn::default()
},
],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(h!("op2"), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_c1.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
..TxIn::default()
},
],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_d1.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output,
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(0)
};
previous_output,
..TxIn::default()
}],
- output: vec![TxOut::default(), TxOut::default()],
+ output: vec![TxOut::NULL, TxOut::NULL],
..common::new_tx(1)
};
previous_output: OutPoint::new(tx_a.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(2)
};
#[test]
fn test_descendants_no_repeat() {
let tx_a = Transaction {
- output: vec![TxOut::default(), TxOut::default(), TxOut::default()],
+ output: vec![TxOut::NULL, TxOut::NULL, TxOut::NULL],
..common::new_tx(0)
};
previous_output: OutPoint::new(tx_a.txid(), vout),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(1)
})
.collect::<Vec<_>>();
previous_output: OutPoint::new(txs_b[vout as usize].txid(), vout),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(2)
})
.collect::<Vec<_>>();
..TxIn::default()
},
],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(3)
};
previous_output: OutPoint::new(tx_d.txid(), 0),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(4)
};
previous_output: OutPoint::new(h!("tx_does_not_exist"), v),
..TxIn::default()
}],
- output: vec![TxOut::default()],
+ output: vec![TxOut::NULL],
..common::new_tx(v)
})
.collect::<Vec<_>>();
input: vec![],
output: vec![
TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
},
TxOut {
- value: 20_000,
+ value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
},
],
}],
output: vec![
TxOut {
- value: 5_000,
+ value: Amount::from_sat(5_000),
script_pubkey: ScriptBuf::new(),
},
TxOut {
- value: 5_000,
+ value: Amount::from_sat(5_000),
script_pubkey: ScriptBuf::new(),
},
],
}],
output: vec![
TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
},
TxOut {
- value: 10_000,
+ value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
},
],
[dependencies]
bdk_chain = { path = "../chain", version = "0.11.0", default-features = false }
-electrum-client = { version = "0.18" }
+electrum-client = { version = "0.19" }
#rustls = { version = "=0.21.1", optional = true, features = ["dangerous_configuration"] }
[dev-dependencies]
-bdk_testenv = { path = "../testenv", version = "0.1.0", default-features = false }
-electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
+bdk_testenv = { path = "../testenv", default-features = false }
+electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
anyhow = "1"
\ No newline at end of file
.client
.get_new_address(None, None)?
.assume_checked();
- let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros());
+ let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros());
let addr_to_track = Address::from_script(&spk_to_track, bdk_chain::bitcoin::Network::Regtest)?;
// Setup receiver.
.client
.get_new_address(None, None)?
.assume_checked();
- let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros());
+ let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros());
let addr_to_track = Address::from_script(&spk_to_track, bdk_chain::bitcoin::Network::Regtest)?;
// Setup receiver.
[dependencies]
bdk_chain = { path = "../chain", version = "0.11.0", default-features = false }
-esplora-client = { version = "0.6.0", default-features = false }
+esplora-client = { version = "0.7.0", default-features = false }
async-trait = { version = "0.1.66", optional = true }
futures = { version = "0.3.26", optional = true }
# use these dependencies if you need to enable their /no-std features
-bitcoin = { version = "0.30.0", optional = true, default-features = false }
-miniscript = { version = "10.0.0", optional = true, default-features = false }
+bitcoin = { version = "0.31.0", optional = true, default-features = false }
+miniscript = { version = "11.0.0", optional = true, default-features = false }
[dev-dependencies]
-bdk_testenv = { path = "../testenv", version = "0.1.0", default_features = false }
-electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
+bdk_testenv = { path = "../testenv", default_features = false }
+electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
[features]
use async_trait::async_trait;
use bdk_chain::collections::btree_map;
use bdk_chain::{
- bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
+ bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
collections::BTreeMap,
local_chain::{self, CheckPoint},
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
},
TxOut {
script_pubkey: prevout.scriptpubkey.clone(),
- value: prevout.value,
+ value: Amount::from_sat(prevout.value),
},
))
});
use bdk_chain::collections::btree_map;
use bdk_chain::collections::BTreeMap;
use bdk_chain::{
- bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
+ bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
local_chain::{self, CheckPoint},
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
};
},
TxOut {
script_pubkey: prevout.scriptpubkey.clone(),
- value: prevout.value,
+ value: Amount::from_sat(prevout.value),
},
))
});
pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap());
- let client = Builder::new(base_url.as_str()).build_blocking()?;
+ let client = Builder::new(base_url.as_str()).build_blocking();
let receive_address0 =
Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm")?.assume_checked();
pub fn test_update_tx_graph_stop_gap() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap());
- let client = Builder::new(base_url.as_str()).build_blocking()?;
+ let client = Builder::new(base_url.as_str()).build_blocking();
let _block_hashes = env.mine_blocks(101, None)?;
// Now let's test the gap limit. First of all get a chain of 10 addresses.
// so new blocks can be seen by Electrs
let env = env.reset_electrsd()?;
let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap());
- let client = Builder::new(base_url.as_str()).build_blocking()?;
+ let client = Builder::new(base_url.as_str()).build_blocking();
struct TestCase {
name: &'static str,
[dependencies]
bdk = { path = "../bdk" }
-hwi = { version = "0.7.0", features = [ "miniscript"] }
+hwi = { version = "0.8.0", features = [ "miniscript"] }
use bdk::bitcoin::bip32::Fingerprint;
-use bdk::bitcoin::psbt::PartiallySignedTransaction;
use bdk::bitcoin::secp256k1::{All, Secp256k1};
+use bdk::bitcoin::Psbt;
use hwi::error::Error;
use hwi::types::{HWIChain, HWIDevice};
impl TransactionSigner for HWISigner {
fn sign_transaction(
&self,
- psbt: &mut PartiallySignedTransaction,
+ psbt: &mut Psbt,
_sign_options: &bdk::SignOptions,
_secp: &Secp256k1<All>,
) -> Result<(), SignerError> {
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-bitcoincore-rpc = { version = "0.17" }
+bitcoincore-rpc = { version = "0.18" }
bdk_chain = { path = "../chain", version = "0.11", default-features = false }
-electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
+electrsd = { version= "0.27.1", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
anyhow = { version = "1" }
[features]
use bdk_chain::bitcoin::{
address::NetworkChecked, block::Header, hash_types::TxMerkleNode, hashes::Hash,
- secp256k1::rand::random, Address, Amount, Block, BlockHash, CompactTarget, ScriptBuf,
- ScriptHash, Transaction, TxIn, TxOut, Txid,
+ secp256k1::rand::random, transaction, Address, Amount, Block, BlockHash, CompactTarget,
+ ScriptBuf, ScriptHash, Transaction, TxIn, TxOut, Txid,
};
use bitcoincore_rpc::{
bitcoincore_rpc_json::{GetBlockTemplateModes, GetBlockTemplateRules},
)?;
let txdata = vec![Transaction {
- version: 1,
+ version: transaction::Version::ONE,
lock_time: bdk_chain::bitcoin::absolute::LockTime::from_height(0)?,
input: vec![TxIn {
previous_output: bdk_chain::bitcoin::OutPoint::default(),
witness: bdk_chain::bitcoin::Witness::new(),
}],
output: vec![TxOut {
- value: 0,
+ value: Amount::ZERO,
script_pubkey: ScriptBuf::new_p2sh(&ScriptHash::all_zeros()),
}],
}];
use bdk_coin_select::{coin_select_bnb, CoinSelector, CoinSelectorOpt, WeightedValue};
use bdk_file_store::Store;
use serde::{de::DeserializeOwned, Serialize};
-use std::{cmp::Reverse, collections::HashMap, path::PathBuf, sync::Mutex, time::Duration};
+use std::{cmp::Reverse, collections::BTreeMap, path::PathBuf, sync::Mutex, time::Duration};
use bdk_chain::{
bitcoin::{
- absolute, address, psbt::Prevouts, secp256k1::Secp256k1, sighash::SighashCache, Address,
- Network, Sequence, Transaction, TxIn, TxOut,
+ absolute, address,
+ secp256k1::Secp256k1,
+ sighash::{Prevouts, SighashCache},
+ transaction, Address, Amount, Network, Sequence, Transaction, TxIn, TxOut,
},
indexed_tx_graph::{self, IndexedTxGraph},
keychain::{self, KeychainTxOutIndex},
pub fn create_tx<A: Anchor, O: ChainOracle>(
graph: &mut KeychainTxGraph<A>,
chain: &O,
- keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>,
+ keymap: &BTreeMap<DescriptorPublicKey, DescriptorSecretKey>,
cs_algorithm: CoinSelectionAlgo,
address: Address,
value: u64,
.iter()
.map(|(plan, utxo)| {
WeightedValue::new(
- utxo.txout.value,
+ utxo.txout.value.to_sat(),
plan.expected_weight() as _,
plan.witness_version().is_some(),
)
.collect();
let mut outputs = vec![TxOut {
- value,
+ value: Amount::from_sat(value),
script_pubkey: address.script_pubkey(),
}];
.expect("failed to obtain change plan");
let mut change_output = TxOut {
- value: 0,
+ value: Amount::ZERO,
script_pubkey: change_script,
};
let selected_txos = selection.apply_selection(&candidates).collect::<Vec<_>>();
if let Some(drain_value) = selection_meta.drain_value {
- change_output.value = drain_value;
+ change_output.value = Amount::from_sat(drain_value);
// if the selection tells us to use change and the change value is sufficient, we add it as an output
outputs.push(change_output)
}
let mut transaction = Transaction {
- version: 0x02,
+ version: transaction::Version::TWO,
// because the temporary planning module does not support timelocks, we can use the chain
// tip as the `lock_time` for anti-fee-sniping purposes
lock_time: absolute::LockTime::from_height(chain.get_chain_tip()?.height)
graph: &Mutex<KeychainTxGraph<A>>,
db: &Mutex<Database<C>>,
chain: &Mutex<O>,
- keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>,
+ keymap: &BTreeMap<DescriptorPublicKey, DescriptorSecretKey>,
network: Network,
broadcast: impl FnOnce(S, &Transaction) -> anyhow::Result<()>,
cmd: Commands<CS, S>,
_ => panic!("unsupported network"),
});
- let client = esplora_client::Builder::new(esplora_url).build_blocking()?;
+ let client = esplora_client::Builder::new(esplora_url).build_blocking();
Ok(client)
}
}
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
assert!(finalized);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx()?;
client.transaction_broadcast(&tx)?;
println!("Tx broadcasted! Txid: {}", tx.txid());
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
assert!(finalized);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx()?;
client.broadcast(&tx).await?;
println!("Tx broadcasted! Txid: {}", tx.txid());
print!("Syncing...");
let client =
- esplora_client::Builder::new("https://blockstream.info/testnet/api").build_blocking()?;
+ esplora_client::Builder::new("https://blockstream.info/testnet/api").build_blocking();
let prev_tip = wallet.latest_checkpoint();
let keychain_spks = wallet
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
assert!(finalized);
- let tx = psbt.extract_tx();
+ let tx = psbt.extract_tx()?;
client.broadcast(&tx)?;
println!("Tx broadcasted! Txid: {}", tx.txid());
) -> Self {
let mut tx = Transaction {
input: vec![],
- version: 1,
+ version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
output: txouts.to_vec(),
};
target_value: if txouts.is_empty() {
None
} else {
- Some(txouts.iter().map(|txout| txout.value).sum())
+ Some(txouts.iter().map(|txout| txout.value.to_sat()).sum())
},
..Self::from_weights(
base_weight.to_wu() as u32,
bitcoin,
collections::{BTreeSet, HashMap},
};
-use bitcoin::{absolute, Transaction, TxOut};
+use bitcoin::{absolute, transaction, Transaction, TxOut};
use core::fmt::{Debug, Display};
mod coin_selector;
// Shamelessly copied from
// https://github.com/rust-bitcoin/rust-miniscript/blob/d5615acda1a7fdc4041a11c1736af139b8c7ebe8/src/util.rs#L8
pub(crate) fn varint_size(v: usize) -> u32 {
- bitcoin::VarInt(v as u64).len() as u32
+ bitcoin::VarInt(v as u64).size() as u32
}
use bdk_chain::{bitcoin, collections::*, miniscript};
use bitcoin::{
absolute,
- address::WitnessVersion,
bip32::{DerivationPath, Fingerprint, KeySource},
blockdata::transaction::Sequence,
ecdsa,
hashes::{hash160, ripemd160, sha256},
secp256k1::Secp256k1,
taproot::{self, LeafVersion, TapLeafHash},
- ScriptBuf, TxIn, Witness,
+ ScriptBuf, TxIn, Witness, WitnessVersion,
};
use miniscript::{
descriptor::{InnerXKey, Tr},
};
pub(crate) fn varint_len(v: usize) -> usize {
- bitcoin::VarInt(v as u64).len() as usize
+ bitcoin::VarInt(v as u64).size() as usize
}
mod plan_impls;
use bitcoin::{
bip32,
- hashes::{hash160, ripemd160, sha256},
+ hashes::{hash160, ripemd160, sha256, Hash},
key::XOnlyPublicKey,
- psbt::Prevouts,
- secp256k1::{KeyPair, Message, PublicKey, Signing, Verification},
+ secp256k1::{Keypair, Message, PublicKey, Signing, Verification},
sighash,
- sighash::{EcdsaSighashType, SighashCache, TapSighashType},
+ sighash::{EcdsaSighashType, Prevouts, SighashCache, TapSighashType},
taproot, Transaction, TxOut,
};
let tweak =
taproot::TapTweakHash::from_key_and_tweak(x_only_pubkey, merkle_root.clone());
- let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone())
+ let keypair = Keypair::from_secret_key(&secp, &secret_key.clone())
.add_xonly_tweak(&secp, &tweak.to_scalar())
.unwrap();
- let msg = Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes");
+ let msg = Message::from_digest(sighash.to_byte_array());
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
let bitcoin_sig = taproot::Signature {
todo!();
}
};
- let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone());
- let msg =
- Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes");
+ let keypair = Keypair::from_secret_key(&secp, &secret_key.clone());
+ let msg = Message::from_digest(sighash.to_byte_array());
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
let bitcoin_sig = taproot::Signature {
sig,