Skip to content

Commit f3198dc

Browse files
committed
Add find_derivation_index_for_spk
To replace the functionality lost by changing `update_desc`
1 parent 148112c commit f3198dc

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

src/descriptor/mod.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
//! these with BIP32 paths, pay-to-contract instructions, etc.
2424
//!
2525
26+
use std::ops::Range;
2627
use std::{collections::HashMap, sync::Arc};
2728
use std::{
2829
fmt,
@@ -749,6 +750,30 @@ impl Descriptor<DescriptorPublicKey> {
749750

750751
descriptor.to_string()
751752
}
753+
754+
/// Utility method for deriving the descriptor at each index in a range to find one matching
755+
/// `script_pubkey`.
756+
///
757+
/// If it finds a match then it returns the index it was derived it and the concrete descriptor
758+
/// at that index. If the descriptor is non-derivable then it will simply check the script
759+
/// pubkey against the descriptor (and in that case the index returned will be meaningless).
760+
pub fn find_derivation_index_for_spk<C: secp256k1::Verification>(
761+
&self,
762+
secp: &secp256k1::Secp256k1<C>,
763+
script_pubkey: &Script,
764+
range: Range<u32>,
765+
) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> {
766+
let range = if self.is_deriveable() { range } else { 0..1 };
767+
768+
for i in range {
769+
let concrete = self.derived_descriptor(&secp, i)?;
770+
if &concrete.script_pubkey() == script_pubkey {
771+
return Ok(Some((i, concrete)));
772+
}
773+
}
774+
775+
Ok(None)
776+
}
752777
}
753778

754779
impl<Pk> expression::FromTree for Descriptor<Pk>
@@ -1736,4 +1761,31 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
17361761
Descriptor::<DescriptorPublicKey>::from_str(&format!("wsh(pk({}))", x_only_key))
17371762
.unwrap_err();
17381763
}
1764+
1765+
#[test]
1766+
fn test_find_derivation_index_for_spk() {
1767+
let secp = secp256k1::Secp256k1::verification_only();
1768+
let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap();
1769+
let script_at_0_1 = Script::from_str(
1770+
"5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb",
1771+
)
1772+
.unwrap();
1773+
let expected_concrete = Descriptor::from_str(
1774+
"tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)",
1775+
)
1776+
.unwrap();
1777+
1778+
assert_eq!(
1779+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1),
1780+
Ok(None)
1781+
);
1782+
assert_eq!(
1783+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2),
1784+
Ok(Some((1, expected_concrete.clone())))
1785+
);
1786+
assert_eq!(
1787+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10),
1788+
Ok(Some((1, expected_concrete)))
1789+
);
1790+
}
17391791
}

0 commit comments

Comments
 (0)