Skip to content

Commit f8c8176

Browse files
committed
descriptor: add convenience method variants of pktranslate for common cases
1 parent 54497be commit f8c8176

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

src/descriptor/mod.rs

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,7 @@ pub trait PkTranslate<P: MiniscriptKey, Q: MiniscriptKey> {
222222
) -> Result<Self::Output, E>
223223
where
224224
Fpk: FnMut(&P) -> Result<Q, E>,
225-
Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>,
226-
Q: MiniscriptKey;
225+
Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>;
227226

228227
/// Calls `translate_pk` with conversion functions that cannot fail
229228
fn translate_pk_infallible<Fpk, Fpkh>(
@@ -234,13 +233,68 @@ pub trait PkTranslate<P: MiniscriptKey, Q: MiniscriptKey> {
234233
where
235234
Fpk: FnMut(&P) -> Q,
236235
Fpkh: FnMut(&P::Hash) -> Q::Hash,
237-
Q: MiniscriptKey,
238236
{
239237
self.translate_pk::<_, _, ()>(|pk| Ok(translatefpk(pk)), |pkh| Ok(translatefpkh(pkh)))
240238
.expect("infallible translation function")
241239
}
242240
}
243241

242+
/// Variant of `PkTranslate` where P and Q both have the same hash
243+
/// type, and the hashes can be converted by just cloning them
244+
pub trait PkTranslate1<P: MiniscriptKey, Q: MiniscriptKey<Hash = P::Hash>>:
245+
PkTranslate<P, Q>
246+
{
247+
/// Translate a struct from one generic to another where the
248+
/// translation for Pk is provided by translatefpk
249+
fn translate_pk1<Fpk, E>(
250+
&self,
251+
translatefpk: Fpk,
252+
) -> Result<<Self as PkTranslate<P, Q>>::Output, E>
253+
where
254+
Fpk: FnMut(&P) -> Result<Q, E>,
255+
{
256+
self.translate_pk(translatefpk, |h| Ok(h.clone()))
257+
}
258+
259+
/// Translate a struct from one generic to another where the
260+
/// translation for Pk is provided by translatefpk
261+
fn translate_pk1_infallible<Fpk: FnMut(&P) -> Q>(
262+
&self,
263+
translatefpk: Fpk,
264+
) -> <Self as PkTranslate<P, Q>>::Output {
265+
self.translate_pk_infallible(translatefpk, P::Hash::clone)
266+
}
267+
}
268+
impl<P: MiniscriptKey, Q: MiniscriptKey<Hash = P::Hash>, T: PkTranslate<P, Q>> PkTranslate1<P, Q>
269+
for T
270+
{
271+
}
272+
273+
/// Variant of `PkTranslate` where P's hash is P, so the hashes
274+
/// can be converted by reusing the key-conversion function
275+
pub trait PkTranslate2<P: MiniscriptKey<Hash = P>, Q: MiniscriptKey>: PkTranslate<P, Q> {
276+
/// Translate a struct from one generic to another where the
277+
/// translation for Pk is provided by translatefpk
278+
fn translate_pk2<Fpk: Fn(&P) -> Result<Q, E>, E>(
279+
&self,
280+
translatefpk: Fpk,
281+
) -> Result<<Self as PkTranslate<P, Q>>::Output, E> {
282+
self.translate_pk(&translatefpk, |h| {
283+
translatefpk(h).map(|q| q.to_pubkeyhash())
284+
})
285+
}
286+
287+
/// Translate a struct from one generic to another where the
288+
/// translation for Pk is provided by translatefpk
289+
fn translate_pk2_infallible<Fpk: Fn(&P) -> Q>(
290+
&self,
291+
translatefpk: Fpk,
292+
) -> <Self as PkTranslate<P, Q>>::Output {
293+
self.translate_pk_infallible(&translatefpk, |h| translatefpk(h).to_pubkeyhash())
294+
}
295+
}
296+
impl<P: MiniscriptKey<Hash = P>, Q: MiniscriptKey, T: PkTranslate<P, Q>> PkTranslate2<P, Q> for T {}
297+
244298
// There are some additional convenience functions we could add to `PkTranslate`
245299
// for the common special cases where `P::Hash == Q::Hash`, or when `P == P::Hash`,
246300
// but these are blocked on https://github.com/rust-lang/rust/issues/20041 which
@@ -568,10 +622,7 @@ where
568622
impl Descriptor<DescriptorPublicKey> {
569623
/// Derives all wildcard keys in the descriptor using the supplied `child_number`
570624
pub fn derive(&self, child_number: bip32::ChildNumber) -> Descriptor<DescriptorPublicKey> {
571-
self.translate_pk_infallible(
572-
|pk| pk.clone().derive(child_number),
573-
|pk| pk.clone().derive(child_number),
574-
)
625+
self.translate_pk2_infallible(|pk| pk.clone().derive(child_number))
575626
}
576627

577628
/// Parse a descriptor that may contain secret keys

src/miniscript/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ serde_string_impl_pk!(Miniscript, "a miniscript", Ctx; ScriptContext);
416416
mod tests {
417417
use super::Segwitv0;
418418
use super::{Miniscript, ScriptContext};
419-
use descriptor::PkTranslate;
419+
use descriptor::{PkTranslate, PkTranslate1};
420420
use hex_script;
421421
use miniscript::types::{self, ExtData, Property, Type};
422422
use miniscript::Terminal;
@@ -482,6 +482,9 @@ mod tests {
482482

483483
let translated = script.translate_pk_infallible(Pk::clone, Pk::Hash::clone);
484484
assert_eq!(translated, script);
485+
486+
let translated = script.translate_pk1_infallible(Pk::clone);
487+
assert_eq!(translated, script);
485488
}
486489

487490
fn script_rtt<Str1: Into<Option<&'static str>>>(script: Segwitv0Script, expected_hex: Str1) {

0 commit comments

Comments
 (0)