Skip to content

Commit 0b5e495

Browse files
committed
Add find_derivation_index_for_spk
To replace the functionality lost by changing `update_desc`
1 parent d8cc633 commit 0b5e495

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>
@@ -1721,4 +1746,31 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
17211746
let descriptor: Descriptor<DescriptorPublicKey> = descriptor_str.parse().unwrap();
17221747
assert_eq!(descriptor.to_string(), "sh(wsh(pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))#6c6hwr22");
17231748
}
1749+
1750+
#[test]
1751+
fn test_find_derivation_index_for_spk() {
1752+
let secp = secp256k1::Secp256k1::verification_only();
1753+
let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap();
1754+
let script_at_0_1 = Script::from_str(
1755+
"5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb",
1756+
)
1757+
.unwrap();
1758+
let expected_concrete = Descriptor::from_str(
1759+
"tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)",
1760+
)
1761+
.unwrap();
1762+
1763+
assert_eq!(
1764+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1),
1765+
Ok(None)
1766+
);
1767+
assert_eq!(
1768+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2),
1769+
Ok(Some((1, expected_concrete.clone())))
1770+
);
1771+
assert_eq!(
1772+
descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10),
1773+
Ok(Some((1, expected_concrete)))
1774+
);
1775+
}
17241776
}

0 commit comments

Comments
 (0)