From 88e49fee1504177809139511523a6fc8fe149994 Mon Sep 17 00:00:00 2001 From: LLFourn Date: Mon, 11 Apr 2022 14:45:26 +1000 Subject: [PATCH] Add find_derivation_index_for_spk To replace the functionality lost by changing `update_desc` --- src/descriptor/mod.rs | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 6e6416871..62be4561a 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -23,6 +23,7 @@ //! these with BIP32 paths, pay-to-contract instructions, etc. //! +use std::ops::Range; use std::{collections::HashMap, sync::Arc}; use std::{ fmt, @@ -762,6 +763,30 @@ impl Descriptor { descriptor.to_string() } + + /// Utility method for deriving the descriptor at each index in a range to find one matching + /// `script_pubkey`. + /// + /// If it finds a match then it returns the index it was derived it and the concrete descriptor + /// at that index. If the descriptor is non-derivable then it will simply check the script + /// pubkey against the descriptor (and in that case the index returned will be meaningless). + pub fn find_derivation_index_for_spk( + &self, + secp: &secp256k1::Secp256k1, + script_pubkey: &Script, + range: Range, + ) -> Result)>, ConversionError> { + let range = if self.is_deriveable() { range } else { 0..1 }; + + for i in range { + let concrete = self.derived_descriptor(&secp, i)?; + if &concrete.script_pubkey() == script_pubkey { + return Ok(Some((i, concrete))); + } + } + + Ok(None) + } } impl expression::FromTree for Descriptor @@ -1734,4 +1759,31 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))"; let descriptor: Descriptor = descriptor_str.parse().unwrap(); assert_eq!(descriptor.to_string(), "sh(wsh(pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))#6c6hwr22"); } + + #[test] + fn test_find_derivation_index_for_spk() { + let secp = secp256k1::Secp256k1::verification_only(); + let descriptor = Descriptor::from_str("tr([73c5da0a/86'/0'/0']xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ/0/*)").unwrap(); + let script_at_0_1 = Script::from_str( + "5120a82f29944d65b86ae6b5e5cc75e294ead6c59391a1edc5e016e3498c67fc7bbb", + ) + .unwrap(); + let expected_concrete = Descriptor::from_str( + "tr(0283dfe85a3151d2517290da461fe2815591ef69f2b18a2ce63f01697a8b313145)", + ) + .unwrap(); + + assert_eq!( + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..1), + Ok(None) + ); + assert_eq!( + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..2), + Ok(Some((1, expected_concrete.clone()))) + ); + assert_eq!( + descriptor.find_derivation_index_for_spk(&secp, &script_at_0_1, 0..10), + Ok(Some((1, expected_concrete))) + ); + } }