Skip to content

Commit 9009f1f

Browse files
committed
Add find_derivation_index_for_spk
To replace the functionality lost by changing `update_desc`
1 parent 829da29 commit 9009f1f

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,
@@ -762,6 +763,30 @@ impl Descriptor<DescriptorPublicKey> {
762763

763764
descriptor.to_string()
764765
}
766+
767+
/// Utility method for deriving the descriptor at each index in a range to find one matching
768+
/// `script_pubkey`.
769+
///
770+
/// If it finds a match then it returns the index it was derived it and the concrete descriptor
771+
/// at that index. If the descriptor is non-derivable then it will simply check the script
772+
/// pubkey against the descriptor (and in that case the index returned will be meaningless).
773+
pub fn find_derivation_index_for_spk<C: secp256k1::Verification>(
774+
&self,
775+
secp: &secp256k1::Secp256k1<C>,
776+
script_pubkey: &Script,
777+
range: Range<u32>,
778+
) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> {
779+
let range = if self.is_deriveable() { range } else { 0..1 };
780+
781+
for i in range {
782+
let concrete = self.derived_descriptor(&secp, i)?;
783+
if &concrete.script_pubkey() == script_pubkey {
784+
return Ok(Some((i, concrete)));
785+
}
786+
}
787+
788+
Ok(None)
789+
}
765790
}
766791

767792
impl<Pk> expression::FromTree for Descriptor<Pk>
@@ -1734,4 +1759,31 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
17341759
let descriptor: Descriptor<DescriptorPublicKey> = descriptor_str.parse().unwrap();
17351760
assert_eq!(descriptor.to_string(), "sh(wsh(pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))#6c6hwr22");
17361761
}
1762+
1763+
#[test]
1764+
fn test_find_derivation_index_for_spk() {
1765+
let secp = secp256k1::Secp256k1::verification_only();
1766+
let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap();
1767+
let script_at_0_1 = Script::from_str(
1768+
"5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb",
1769+
)
1770+
.unwrap();
1771+
let expected_concrete = Descriptor::from_str(
1772+
"tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)",
1773+
)
1774+
.unwrap();
1775+
1776+
assert_eq!(
1777+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1),
1778+
Ok(None)
1779+
);
1780+
assert_eq!(
1781+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2),
1782+
Ok(Some((1, expected_concrete.clone())))
1783+
);
1784+
assert_eq!(
1785+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10),
1786+
Ok(Some((1, expected_concrete)))
1787+
);
1788+
}
17371789
}

0 commit comments

Comments
 (0)