|
23 | 23 | //! these with BIP32 paths, pay-to-contract instructions, etc.
|
24 | 24 | //!
|
25 | 25 |
|
| 26 | +use std::ops::Range; |
26 | 27 | use std::{collections::HashMap, sync::Arc};
|
27 | 28 | use std::{
|
28 | 29 | fmt,
|
29 | 30 | str::{self, FromStr},
|
30 | 31 | };
|
31 | 32 |
|
32 | 33 | use bitcoin::blockdata::witness::Witness;
|
| 34 | +use bitcoin::util::address::WitnessVersion; |
33 | 35 | use bitcoin::{self, secp256k1, Script};
|
34 | 36 |
|
35 | 37 | use self::checksum::verify_checksum;
|
@@ -259,6 +261,22 @@ pub enum DescriptorType {
|
259 | 261 | Tr,
|
260 | 262 | }
|
261 | 263 |
|
| 264 | +impl DescriptorType { |
| 265 | + /// Returns the segwit version implied by the descriptor type. |
| 266 | + /// |
| 267 | + /// This will return `Some(WitnessVersion::V0)` whether it is "native" segwitv0 or "wrapped" p2sh segwit. |
| 268 | + pub fn segwit_version(&self) -> Option<WitnessVersion> { |
| 269 | + use self::DescriptorType::*; |
| 270 | + match self { |
| 271 | + Tr => Some(WitnessVersion::V1), |
| 272 | + Wpkh | ShWpkh | Wsh | ShWsh | ShWshSortedMulti | WshSortedMulti => { |
| 273 | + Some(WitnessVersion::V0) |
| 274 | + } |
| 275 | + Bare | Sh | Pkh | ShSortedMulti => None, |
| 276 | + } |
| 277 | + } |
| 278 | +} |
| 279 | + |
262 | 280 | impl<Pk: MiniscriptKey> Descriptor<Pk> {
|
263 | 281 | // Keys
|
264 | 282 |
|
@@ -749,6 +767,31 @@ impl Descriptor<DescriptorPublicKey> {
|
749 | 767 |
|
750 | 768 | descriptor.to_string()
|
751 | 769 | }
|
| 770 | + |
| 771 | + /// Utility method for deriving the descriptor at each index in a range to find one matching |
| 772 | + /// `script_pubkey`. |
| 773 | + /// |
| 774 | + /// If it finds a match then it returns the index it was derived at and the concrete |
| 775 | + /// descriptor at that index. If the descriptor is non-derivable then it will simply check the |
| 776 | + /// script pubkey against the descriptor and return it if it matches (in this case the index |
| 777 | + /// returned will be meaningless). |
| 778 | + pub fn find_derivation_index_for_spk<C: secp256k1::Verification>( |
| 779 | + &self, |
| 780 | + secp: &secp256k1::Secp256k1<C>, |
| 781 | + script_pubkey: &Script, |
| 782 | + range: Range<u32>, |
| 783 | + ) -> Result<Option<(u32, Descriptor<bitcoin::PublicKey>)>, ConversionError> { |
| 784 | + let range = if self.is_deriveable() { range } else { 0..1 }; |
| 785 | + |
| 786 | + for i in range { |
| 787 | + let concrete = self.derived_descriptor(&secp, i)?; |
| 788 | + if &concrete.script_pubkey() == script_pubkey { |
| 789 | + return Ok(Some((i, concrete))); |
| 790 | + } |
| 791 | + } |
| 792 | + |
| 793 | + Ok(None) |
| 794 | + } |
752 | 795 | }
|
753 | 796 |
|
754 | 797 | impl<Pk> expression::FromTree for Descriptor<Pk>
|
@@ -1736,4 +1779,31 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
|
1736 | 1779 | Descriptor::<DescriptorPublicKey>::from_str(&format!("wsh(pk({}))", x_only_key))
|
1737 | 1780 | .unwrap_err();
|
1738 | 1781 | }
|
| 1782 | + |
| 1783 | + #[test] |
| 1784 | + fn test_find_derivation_index_for_spk() { |
| 1785 | + let secp = secp256k1::Secp256k1::verification_only(); |
| 1786 | + let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); |
| 1787 | + let script_at_0_1 = Script::from_str( |
| 1788 | + "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", |
| 1789 | + ) |
| 1790 | + .unwrap(); |
| 1791 | + let expected_concrete = Descriptor::from_str( |
| 1792 | + "tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)", |
| 1793 | + ) |
| 1794 | + .unwrap(); |
| 1795 | + |
| 1796 | + assert_eq!( |
| 1797 | + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1), |
| 1798 | + Ok(None) |
| 1799 | + ); |
| 1800 | + assert_eq!( |
| 1801 | + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2), |
| 1802 | + Ok(Some((1, expected_concrete.clone()))) |
| 1803 | + ); |
| 1804 | + assert_eq!( |
| 1805 | + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10), |
| 1806 | + Ok(Some((1, expected_concrete))) |
| 1807 | + ); |
| 1808 | + } |
1739 | 1809 | }
|
0 commit comments