Skip to content

Commit ab1d73b

Browse files
committed
feat(wallet): derive wallet_name_from_descriptor from public descriptor checksums
- Update `wallet_name_from_descriptor` to compute descriptor checksum explicitly - Remove reliance on `to_string()` implicitly containing `#checksum` - Clarify that wallet name is defined by public descriptor checksums - Add regression test for equivalent xpub/xprv wallet names
1 parent 6dca318 commit ab1d73b

1 file changed

Lines changed: 41 additions & 16 deletions

File tree

src/wallet/mod.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ pub(crate) mod utils;
6666

6767
use crate::collections::{BTreeMap, HashMap, HashSet};
6868
use crate::descriptor::{
69-
check_wallet_descriptor, error::Error as DescriptorError, policy::BuildSatisfaction,
70-
DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor,
71-
Policy, XKeyUtils,
69+
check_wallet_descriptor, checksum::calc_checksum, error::Error as DescriptorError,
70+
policy::BuildSatisfaction, DerivedDescriptor, DescriptorMeta, ExtendedDescriptor,
71+
ExtractPolicy, IntoWalletDescriptor, Policy, XKeyUtils,
7272
};
7373
use crate::psbt::PsbtUtils;
7474
use crate::types::*;
@@ -2784,9 +2784,10 @@ impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime>> for Wallet {
27842784
}
27852785
}
27862786

2787-
/// Deterministically generate a unique name given the descriptors defining the [`Wallet`].
2787+
/// Generate a wallet name from the checksums of the wallet's public descriptors.
27882788
///
2789-
/// Compatible with [`wallet_name_from_descriptor`].
2789+
/// The name is derived from the checksums of the provided descriptor(s), ensuring
2790+
/// it's based on public information only.
27902791
pub fn wallet_name_from_descriptor<T>(
27912792
descriptor: T,
27922793
change_descriptor: Option<T>,
@@ -2796,18 +2797,14 @@ pub fn wallet_name_from_descriptor<T>(
27962797
where
27972798
T: IntoWalletDescriptor,
27982799
{
2799-
// TODO: check descriptors contains only public keys
2800-
let descriptor = descriptor
2801-
.into_wallet_descriptor(secp, network_kind)?
2802-
.0
2803-
.to_string();
2804-
let mut wallet_name = descriptor.split_once('#').unwrap().1.to_string();
2800+
// Wallet name is defined by the checksums of the wallet's public descriptors.
2801+
let (descriptor, _keymap) = descriptor.into_wallet_descriptor(secp, network_kind)?;
2802+
let mut wallet_name = calc_checksum(&descriptor.to_string())?;
2803+
28052804
if let Some(change_descriptor) = change_descriptor {
2806-
let change_descriptor = change_descriptor
2807-
.into_wallet_descriptor(secp, network_kind)?
2808-
.0
2809-
.to_string();
2810-
wallet_name.push_str(change_descriptor.split_once('#').unwrap().1);
2805+
let (change_descriptor, _change_keymap) =
2806+
change_descriptor.into_wallet_descriptor(secp, network_kind)?;
2807+
wallet_name.push_str(&calc_checksum(&change_descriptor.to_string())?);
28112808
}
28122809

28132810
Ok(wallet_name)
@@ -3064,4 +3061,32 @@ mod test {
30643061
let wallet = params.network(Network::Testnet).create_wallet_no_persist();
30653062
assert!(wallet.is_err());
30663063
}
3064+
#[test]
3065+
fn test_wallet_name_from_descriptor_public_key_check() {
3066+
let secp = SecpCtx::new();
3067+
3068+
// Test with a public descriptor
3069+
let public_descriptor = "wpkh([31a30ffd/84'/1'/0']tpubDCG4yNzDpNYw5ZMuR2usfbPKcnaKjFGwgyussBdhjy2mXmLWnzkwUTZBQPrQxPVcfwh6uFPN4Q7Jk2DPRFb2c4xbrStpqCbKzLkGhvcJvSx/1/*)#vn4aqs37";
3070+
let public_result =
3071+
wallet_name_from_descriptor(public_descriptor, None, NetworkKind::Test, &secp);
3072+
assert!(public_result.is_ok());
3073+
3074+
// Test with equivalent private descriptor (should produce same name)
3075+
let private_descriptor = "wpkh(tprv8ZgxMBicQKsPctT28ZYaU77s1UFjHv7o7cafmDntdggZ2dFtNn38RYMzJiDVMBqnqBFDP8rHxsiVRudhyrqi6mgPc4gekgxChgnkTSxHAZ5/84'/1'/0'/1/*)#7z7rgndh";
3076+
let private_result =
3077+
wallet_name_from_descriptor(private_descriptor, None, NetworkKind::Test, &secp);
3078+
assert!(private_result.is_ok());
3079+
assert_eq!(public_result.unwrap(), private_result.unwrap()); // Same wallet name
3080+
3081+
// Test with change descriptor
3082+
let change_descriptor = "wpkh([76011771/84'/1'/0']tpubDC3fWoucXCvSyfh6YbyHu1mSQdFjCz5Ejx62eUnRkKdr9bsHGgLEjAaCRNNuaeLjCttfz8sXgshqzawtgWvtozE84rH9BvQn2PUyMCiU1fT/1/*)#jgrerlc3";
3083+
let result_with_change = wallet_name_from_descriptor(
3084+
public_descriptor,
3085+
Some(change_descriptor),
3086+
NetworkKind::Test,
3087+
&secp,
3088+
);
3089+
assert!(result_with_change.is_ok());
3090+
// Wallet name should be main_checksum + change_checksum
3091+
}
30673092
}

0 commit comments

Comments
 (0)