Skip to content

Commit

Permalink
refactor(bdk)!: Make Wallet require a change descriptor
Browse files Browse the repository at this point in the history
All `Wallet` constructors are modified to require a change
descriptor, where previously it was optional. Additionally
we enforce uniqueness of the change descriptor to avoid
ambiguity when deriving scripts and ensure the wallet will
always have two distinct keychains.

Notable changes

* Add error DescriptorError::NonUnique
* Remove error CreateTxError::ChangePolicyDescriptor
* No longer rely on `map_keychain`
  • Loading branch information
ValuedMammal committed Mar 27, 2024
1 parent 380bc40 commit 9ee0540
Show file tree
Hide file tree
Showing 16 changed files with 340 additions and 289 deletions.
3 changes: 2 additions & 1 deletion crates/bdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ fn main() {
let db = bdk_file_store::Store::<ChangeSet>::open_or_create_new(b"magic_bytes", "path/to/my_wallet.db").expect("create store");
let descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/0/*)";
let mut wallet = Wallet::new_or_load(descriptor, None, db, Network::Testnet).expect("create or load wallet");
let change_descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfSbKK1sKMLmC7EAk438btHQrSdu3jGGQa6PA71nvH5nkDexhLteJqkM4dQmWF9g/84'/1'/0'/1/*)";
let mut wallet = Wallet::new_or_load(descriptor, change_descriptor, db, Network::Testnet).expect("create or load wallet");
// Insert a single `TxOut` at `OutPoint` into the wallet.
let _ = wallet.insert_txout(outpoint, txout);
Expand Down
45 changes: 38 additions & 7 deletions crates/bdk/examples/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,52 @@ use bdk::{KeychainKind, Wallet};
/// This example demonstrates the interaction between a bdk wallet and miniscript policy.
fn main() -> Result<(), Box<dyn Error>> {
// We start with a generic miniscript policy string
let policy_str = "or(10@thresh(4,pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec),pk(02a27c8b850a00f67da3499b60562673dcf5fdfb82b7e17652a7ac54416812aefd),pk(03e618ec5f384d6e19ca9ebdb8e2119e5bef978285076828ce054e55c4daf473e2)),1@and(older(4209713),thresh(2,pk(03deae92101c790b12653231439f27b8897264125ecb2f46f48278603102573165),pk(033841045a531e1adf9910a6ec279589a90b3b8a904ee64ffd692bd08a8996c1aa),pk(02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068))))";
// We start with a miniscript policy string
let policy_str = "or(
10@thresh(4,
pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec),pk(02a27c8b850a00f67da3499b60562673dcf5fdfb82b7e17652a7ac54416812aefd),pk(03e618ec5f384d6e19ca9ebdb8e2119e5bef978285076828ce054e55c4daf473e2)
),1@and(
older(4209713),
thresh(2,
pk(03deae92101c790b12653231439f27b8897264125ecb2f46f48278603102573165),pk(033841045a531e1adf9910a6ec279589a90b3b8a904ee64ffd692bd08a8996c1aa),pk(02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068)
)
)
)"
.replace(&[' ', '\n', '\t'][..], "");

println!("Compiling policy: \n{}", policy_str);

// Parse the string as a [`Concrete`] type miniscript policy.
let policy = Concrete::<String>::from_str(policy_str)?;
let policy = Concrete::<String>::from_str(&policy_str)?;

// Create a `wsh` type descriptor from the policy.
// `policy.compile()` returns the resulting miniscript from the policy.
let descriptor = Descriptor::new_wsh(policy.compile()?)?;
let descriptor = Descriptor::new_wsh(policy.compile()?)?.to_string();

println!("Compiled into Descriptor: \n{}", descriptor);

// Do the same for another (internal) keychain
let policy_str = "or(
10@thresh(2,
pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec)
),1@and(
pk(03deae92101c790b12653231439f27b8897264125ecb2f46f48278603102573165),
older(12960)
)
)"
.replace(&[' ', '\n', '\t'][..], "");

println!("Compiled into following Descriptor: \n{}", descriptor);
println!("Compiling internal policy: \n{}", policy_str);

let policy = Concrete::<String>::from_str(&policy_str)?;
let internal_descriptor = Descriptor::new_wsh(policy.compile()?)?.to_string();
println!(
"Compiled into internal Descriptor: \n{}",
internal_descriptor
);

// Create a new wallet from this descriptor
let mut wallet = Wallet::new_no_persist(&format!("{}", descriptor), None, Network::Regtest)?;
// Create a new wallet from descriptors
let mut wallet = Wallet::new_no_persist(&descriptor, &internal_descriptor, Network::Regtest)?;

println!(
"First derived address from the descriptor: \n{}",
Expand Down
6 changes: 6 additions & 0 deletions crates/bdk/src/descriptor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
// licenses.

//! Descriptor errors
use core::fmt;

use super::ExtendedDescriptor;

/// Errors related to the parsing and usage of descriptors
#[derive(Debug)]
pub enum Error {
Expand Down Expand Up @@ -42,6 +45,8 @@ pub enum Error {
Miniscript(miniscript::Error),
/// Hex decoding error
Hex(bitcoin::hashes::hex::Error),
/// The provided wallet descriptors are not unique
NonUnique(ExtendedDescriptor),
}

impl From<crate::keys::KeyError> for Error {
Expand Down Expand Up @@ -79,6 +84,7 @@ impl fmt::Display for Error {
Self::Pk(err) => write!(f, "Key-related error: {}", err),
Self::Miniscript(err) => write!(f, "Miniscript error: {}", err),
Self::Hex(err) => write!(f, "Hex decoding error: {}", err),
Self::NonUnique(d) => write!(f, "Non unique change descriptor: {}", d),
}
}
}
Expand Down
41 changes: 25 additions & 16 deletions crates/bdk/src/descriptor/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ impl<T: DescriptorTemplate> IntoWalletDescriptor for T {
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::P2Pkh;
///
/// let key =
/// let key_a =
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
/// let mut wallet = Wallet::new_no_persist(P2Pkh(key), None, Network::Testnet)?;
/// let key_b =
/// bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
/// let mut wallet = Wallet::new_no_persist(P2Pkh(key_a), P2Pkh(key_b), Network::Testnet)?;
///
/// assert_eq!(
/// wallet.get_address(New).to_string(),
Expand All @@ -105,9 +107,12 @@ impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for P2Pkh<K> {
/// use bdk::template::P2Wpkh_P2Sh;
/// use bdk::wallet::AddressIndex;
///
/// let key =
/// let key_a =
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
/// let mut wallet = Wallet::new_no_persist(P2Wpkh_P2Sh(key), None, Network::Testnet)?;
/// let key_b =
/// bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
/// let mut wallet =
/// Wallet::new_no_persist(P2Wpkh_P2Sh(key_a), P2Wpkh_P2Sh(key_b), Network::Testnet)?;
///
/// assert_eq!(
/// wallet.get_address(AddressIndex::New).to_string(),
Expand All @@ -134,9 +139,11 @@ impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh_P2Sh<K> {
/// use bdk::template::P2Wpkh;
/// use bdk::wallet::AddressIndex::New;
///
/// let key =
/// let key_a =
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
/// let mut wallet = Wallet::new_no_persist(P2Wpkh(key), None, Network::Testnet)?;
/// let key_b =
/// bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
/// let mut wallet = Wallet::new_no_persist(P2Wpkh(key_a), P2Wpkh(key_b), Network::Testnet)?;
///
/// assert_eq!(
/// wallet.get_address(New).to_string(),
Expand All @@ -162,9 +169,11 @@ impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh<K> {
/// # use bdk::wallet::AddressIndex::New;
/// use bdk::template::P2TR;
///
/// let key =
/// let key_a =
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
/// let mut wallet = Wallet::new_no_persist(P2TR(key), None, Network::Testnet)?;
/// let key_b =
/// bitcoin::PrivateKey::from_wif("cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW")?;
/// let mut wallet = Wallet::new_no_persist(P2TR(key_a), P2TR(key_b), Network::Testnet)?;
///
/// assert_eq!(
/// wallet.get_address(New).to_string(),
Expand Down Expand Up @@ -198,7 +207,7 @@ impl<K: IntoDescriptorKey<Tap>> DescriptorTemplate for P2TR<K> {
/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44(key.clone(), KeychainKind::External),
/// Some(Bip44(key, KeychainKind::Internal)),
/// Bip44(key, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -236,7 +245,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44<K> {
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip44Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip44Public(key, fingerprint, KeychainKind::Internal)),
/// Bip44Public(key, fingerprint, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -273,7 +282,7 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for Bip44Public<K> {
/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49(key.clone(), KeychainKind::External),
/// Some(Bip49(key, KeychainKind::Internal)),
/// Bip49(key, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -311,7 +320,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49<K> {
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip49Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip49Public(key, fingerprint, KeychainKind::Internal)),
/// Bip49Public(key, fingerprint, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -348,7 +357,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip49Public<K> {
/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84(key.clone(), KeychainKind::External),
/// Some(Bip84(key, KeychainKind::Internal)),
/// Bip84(key, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -386,7 +395,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip84<K> {
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip84Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip84Public(key, fingerprint, KeychainKind::Internal)),
/// Bip84Public(key, fingerprint, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -423,7 +432,7 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for Bip84Public<K> {
/// let key = bitcoin::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86(key.clone(), KeychainKind::External),
/// Some(Bip86(key, KeychainKind::Internal)),
/// Bip86(key, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down Expand Up @@ -461,7 +470,7 @@ impl<K: DerivableKey<Tap>> DescriptorTemplate for Bip86<K> {
/// let fingerprint = bitcoin::bip32::Fingerprint::from_str("c55b303f")?;
/// let mut wallet = Wallet::new_no_persist(
/// Bip86Public(key.clone(), fingerprint, KeychainKind::External),
/// Some(Bip86Public(key, fingerprint, KeychainKind::Internal)),
/// Bip86Public(key, fingerprint, KeychainKind::Internal),
/// Network::Testnet,
/// )?;
///
Expand Down
8 changes: 0 additions & 8 deletions crates/bdk/src/wallet/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ pub enum CreateTxError<P> {
NoUtxosSelected,
/// Output created is under the dust limit, 546 satoshis
OutputBelowDustLimit(usize),
/// The `change_policy` was set but the wallet does not have a change_descriptor
ChangePolicyDescriptor,
/// There was an error with coin selection
CoinSelection(coin_selection::Error),
/// Wallet's UTXO set is not enough to cover recipient's requested plus fee
Expand Down Expand Up @@ -180,12 +178,6 @@ where
CreateTxError::OutputBelowDustLimit(limit) => {
write!(f, "Output below the dust limit: {}", limit)
}
CreateTxError::ChangePolicyDescriptor => {
write!(
f,
"The `change_policy` can be set only if the wallet has a change_descriptor"
)
}
CreateTxError::CoinSelection(e) => e.fmt(f),
CreateTxError::InsufficientFunds { needed, available } => {
write!(
Expand Down
47 changes: 21 additions & 26 deletions crates/bdk/src/wallet/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
//! let import = FullyNodedExport::from_str(import)?;
//! let wallet = Wallet::new_no_persist(
//! &import.descriptor(),
//! import.change_descriptor().as_ref(),
//! &import.change_descriptor().expect("change descriptor"),
//! Network::Testnet,
//! )?;
//! # Ok::<_, Box<dyn std::error::Error>>(())
Expand All @@ -44,7 +44,7 @@
//! # use bdk::*;
//! let wallet = Wallet::new_no_persist(
//! "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
//! Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
//! "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)",
//! Network::Testnet,
//! )?;
//! let export = FullyNodedExport::export_wallet(&wallet, "exported wallet", true).unwrap();
Expand Down Expand Up @@ -142,19 +142,17 @@ impl FullyNodedExport {
blockheight,
};

let change_descriptor = match wallet.public_descriptor(KeychainKind::Internal).is_some() {
false => None,
true => {
let descriptor = wallet
.get_descriptor_for_keychain(KeychainKind::Internal)
.to_string_with_secret(
&wallet
.get_signers(KeychainKind::Internal)
.as_key_map(wallet.secp_ctx()),
);
Some(remove_checksum(descriptor))
}
let change_descriptor = {
let descriptor = wallet
.get_descriptor_for_keychain(KeychainKind::Internal)
.to_string_with_secret(
&wallet
.get_signers(KeychainKind::Internal)
.as_key_map(wallet.secp_ctx()),
);
Some(remove_checksum(descriptor))
};

if export.change_descriptor() != change_descriptor {
return Err("Incompatible change descriptor");
}
Expand Down Expand Up @@ -221,11 +219,7 @@ mod test {
use super::*;
use crate::wallet::Wallet;

fn get_test_wallet(
descriptor: &str,
change_descriptor: Option<&str>,
network: Network,
) -> Wallet<()> {
fn get_test_wallet(descriptor: &str, change_descriptor: &str, network: Network) -> Wallet<()> {
let mut wallet = Wallet::new_no_persist(descriptor, change_descriptor, network).unwrap();
let transaction = Transaction {
input: vec![],
Expand Down Expand Up @@ -256,7 +250,7 @@ mod test {
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";

let wallet = get_test_wallet(descriptor, Some(change_descriptor), Network::Bitcoin);
let wallet = get_test_wallet(descriptor, change_descriptor, Network::Bitcoin);
let export = FullyNodedExport::export_wallet(&wallet, "Test Label", true).unwrap();

assert_eq!(export.descriptor(), descriptor);
Expand All @@ -268,13 +262,14 @@ mod test {
#[test]
#[should_panic(expected = "Incompatible change descriptor")]
fn test_export_no_change() {
// This wallet explicitly doesn't have a change descriptor. It should be impossible to
// This wallet has a bad change descriptor (no glob). It should be impossible to
// export, because exporting this kind of external descriptor normally implies the
// existence of an internal descriptor
// existence of a compatible internal descriptor

let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/0)";

let wallet = get_test_wallet(descriptor, None, Network::Bitcoin);
let wallet = get_test_wallet(descriptor, change_descriptor, Network::Bitcoin);
FullyNodedExport::export_wallet(&wallet, "Test Label", true).unwrap();
}

Expand All @@ -287,7 +282,7 @@ mod test {
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)";

let wallet = get_test_wallet(descriptor, Some(change_descriptor), Network::Bitcoin);
let wallet = get_test_wallet(descriptor, change_descriptor, Network::Bitcoin);
FullyNodedExport::export_wallet(&wallet, "Test Label", true).unwrap();
}

Expand All @@ -304,7 +299,7 @@ mod test {
[c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\
))";

let wallet = get_test_wallet(descriptor, Some(change_descriptor), Network::Testnet);
let wallet = get_test_wallet(descriptor, change_descriptor, Network::Testnet);
let export = FullyNodedExport::export_wallet(&wallet, "Test Label", true).unwrap();

assert_eq!(export.descriptor(), descriptor);
Expand All @@ -318,7 +313,7 @@ mod test {
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";

let wallet = get_test_wallet(descriptor, Some(change_descriptor), Network::Bitcoin);
let wallet = get_test_wallet(descriptor, change_descriptor, Network::Bitcoin);
let export = FullyNodedExport::export_wallet(&wallet, "Test Label", true).unwrap();

assert_eq!(export.to_string(), "{\"descriptor\":\"wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44\'/0\'/0\'/0/*)\",\"blockheight\":5000,\"label\":\"Test Label\"}");
Expand Down
Loading

0 comments on commit 9ee0540

Please sign in to comment.