diff --git a/bitcoind-tests/tests/setup/test_util.rs b/bitcoind-tests/tests/setup/test_util.rs index ffffe661c..64ffa6f5a 100644 --- a/bitcoind-tests/tests/setup/test_util.rs +++ b/bitcoind-tests/tests/setup/test_util.rs @@ -26,7 +26,7 @@ use bitcoin::secp256k1; use miniscript::descriptor::{SinglePub, SinglePubKey}; use miniscript::{ bitcoin, hash256, Descriptor, DescriptorPublicKey, Error, Miniscript, ScriptContext, - TranslatePk, Translator, + Translator, }; use rand::RngCore; use secp256k1::XOnlyPublicKey; @@ -155,8 +155,11 @@ pub fn parse_insane_ms( #[derive(Debug, Clone)] struct StrDescPubKeyTranslator<'a>(usize, &'a PubData); -impl<'a> Translator for StrDescPubKeyTranslator<'a> { - fn pk(&mut self, pk_str: &String) -> Result { +impl<'a> Translator for StrDescPubKeyTranslator<'a> { + type TargetPk = DescriptorPublicKey; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk_str: &String) -> Result { let avail = !pk_str.ends_with('!'); if avail { self.0 += 1; @@ -181,22 +184,22 @@ impl<'a> Translator for StrDescPubKeyTranslator } } - fn sha256(&mut self, sha256: &String) -> Result { + fn sha256(&mut self, sha256: &String) -> Result { let sha = sha256::Hash::from_str(sha256).unwrap(); Ok(sha) } - fn hash256(&mut self, hash256: &String) -> Result { + fn hash256(&mut self, hash256: &String) -> Result { let hash256 = hash256::Hash::from_str(hash256).unwrap(); Ok(hash256) } - fn ripemd160(&mut self, ripemd160: &String) -> Result { + fn ripemd160(&mut self, ripemd160: &String) -> Result { let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap(); Ok(ripemd160) } - fn hash160(&mut self, hash160: &String) -> Result { + fn hash160(&mut self, hash160: &String) -> Result { let hash160 = hash160::Hash::from_str(hash160).unwrap(); Ok(hash160) } @@ -208,8 +211,11 @@ impl<'a> Translator for StrDescPubKeyTranslator #[derive(Debug, Clone)] struct StrTranslatorLoose<'a>(usize, &'a PubData); -impl<'a> Translator for StrTranslatorLoose<'a> { - fn pk(&mut self, pk_str: &String) -> Result { +impl<'a> Translator for StrTranslatorLoose<'a> { + type TargetPk = DescriptorPublicKey; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk_str: &String) -> Result { let avail = !pk_str.ends_with('!'); if avail { self.0 += 1; @@ -238,22 +244,22 @@ impl<'a> Translator for StrTranslatorLoose<'a> } } - fn sha256(&mut self, sha256: &String) -> Result { + fn sha256(&mut self, sha256: &String) -> Result { let sha = sha256::Hash::from_str(sha256).unwrap(); Ok(sha) } - fn hash256(&mut self, hash256: &String) -> Result { + fn hash256(&mut self, hash256: &String) -> Result { let hash256 = hash256::Hash::from_str(hash256).unwrap(); Ok(hash256) } - fn ripemd160(&mut self, ripemd160: &String) -> Result { + fn ripemd160(&mut self, ripemd160: &String) -> Result { let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap(); Ok(ripemd160) } - fn hash160(&mut self, hash160: &String) -> Result { + fn hash160(&mut self, hash160: &String) -> Result { let hash160 = hash160::Hash::from_str(hash160).unwrap(); Ok(hash160) } diff --git a/examples/big.rs b/examples/big.rs index cf0bd099a..230d656b6 100644 --- a/examples/big.rs +++ b/examples/big.rs @@ -18,7 +18,7 @@ use miniscript::policy::{Concrete, Liftable}; use miniscript::psbt::PsbtExt; use miniscript::{ translate_hash_fail, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, - TranslatePk, Translator, + Translator, }; use secp256k1::Secp256k1; fn main() { @@ -82,12 +82,15 @@ struct StrPkTranslator { pk_map: HashMap, } -impl Translator for StrPkTranslator { - fn pk(&mut self, pk: &String) -> Result { +impl Translator for StrPkTranslator { + type TargetPk = XOnlyPublicKey; + type Error = (); + + fn pk(&mut self, pk: &String) -> Result { self.pk_map.get(pk).copied().ok_or(()) } // We don't need to implement these methods as we are not using them in the policy. // Fail if we encounter any hash fragments. See also translate_hash_clone! macro. - translate_hash_fail!(String, XOnlyPublicKey, ()); + translate_hash_fail!(String, XOnlyPublicKey, Self::Error); } diff --git a/examples/taproot.rs b/examples/taproot.rs index 3ac20c4ec..1e04f7b60 100644 --- a/examples/taproot.rs +++ b/examples/taproot.rs @@ -8,7 +8,7 @@ use miniscript::bitcoin::secp256k1::rand; use miniscript::bitcoin::{Network, WitnessVersion}; use miniscript::descriptor::DescriptorType; use miniscript::policy::Concrete; -use miniscript::{translate_hash_fail, Descriptor, Miniscript, Tap, TranslatePk, Translator}; +use miniscript::{translate_hash_fail, Descriptor, Miniscript, Tap, Translator}; // Refer to https://github.com/sanket1729/adv_btc_workshop/blob/master/workshop.md#creating-a-taproot-descriptor // for a detailed explanation of the policy and it's compilation @@ -17,14 +17,17 @@ struct StrPkTranslator { pk_map: HashMap, } -impl Translator for StrPkTranslator { - fn pk(&mut self, pk: &String) -> Result { +impl Translator for StrPkTranslator { + type TargetPk = XOnlyPublicKey; + type Error = (); + + fn pk(&mut self, pk: &String) -> Result { self.pk_map.get(pk).copied().ok_or(()) } // We don't need to implement these methods as we are not using them in the policy. // Fail if we encounter any hash fragments. See also translate_hash_clone! macro. - translate_hash_fail!(String, XOnlyPublicKey, ()); + translate_hash_fail!(String, XOnlyPublicKey, Self::Error); } fn main() { diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 66be5d6d4..176137ad8 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -23,7 +23,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, - TranslateErr, TranslatePk, Translator, + TranslateErr, Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -92,6 +92,14 @@ impl Bare { let scriptsig_len = self.ms.max_satisfaction_size()?; Ok(4 * (varint_len(scriptsig_len) + scriptsig_len)) } + + /// Converts the keys in the script from one type to another. + pub fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> + where + T: Translator, + { + Bare::new(self.ms.translate_pk(t)?).map_err(TranslateErr::OuterError) + } } impl Bare { @@ -190,21 +198,6 @@ impl ForEachKey for Bare { } } -impl TranslatePk for Bare

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Bare; - - fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> - where - T: Translator, - { - Bare::new(self.ms.translate_pk(t)?).map_err(TranslateErr::OuterError) - } -} - /// A bare PkH descriptor at top level #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct Pkh { @@ -260,6 +253,18 @@ impl Pkh { note = "Use max_weight_to_satisfy instead. The method to count bytes was redesigned and the results will differ from max_weight_to_satisfy. For more details check rust-bitcoin/rust-miniscript#476." )] pub fn max_satisfaction_weight(&self) -> usize { 4 * (1 + 73 + BareCtx::pk_len(&self.pk)) } + + /// Converts the keys in a script from one type to another. + pub fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> + where + T: Translator, + { + let res = Pkh::new(t.pk(&self.pk)?); + match res { + Ok(pk) => Ok(pk), + Err(e) => Err(TranslateErr::OuterError(Error::from(e))), + } + } } impl Pkh { @@ -391,22 +396,3 @@ impl core::str::FromStr for Pkh { impl ForEachKey for Pkh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool { pred(&self.pk) } } - -impl TranslatePk for Pkh

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Pkh; - - fn translate_pk(&self, t: &mut T) -> Result> - where - T: Translator, - { - let res = Pkh::new(t.pk(&self.pk)?); - match res { - Ok(pk) => Ok(pk), - Err(e) => Err(TranslateErr::OuterError(Error::from(e))), - } - } -} diff --git a/src/descriptor/key.rs b/src/descriptor/key.rs index 0ca62fc9f..7e034ef99 100644 --- a/src/descriptor/key.rs +++ b/src/descriptor/key.rs @@ -1003,9 +1003,7 @@ impl DefiniteDescriptorKey { /// always return a compressed key /// /// Will return an error if the descriptor key has any hardened derivation steps in its path. To - /// avoid this error you should replace any such public keys first with [`translate_pk`]. - /// - /// [`translate_pk`]: crate::TranslatePk::translate_pk + /// avoid this error you should replace any such public keys first with [`crate::Descriptor::translate_pk`]. pub fn derive_public_key( &self, secp: &Secp256k1, diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 0b0bd02b6..1a2a7da16 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -28,7 +28,7 @@ use crate::plan::{AssetProvider, Plan}; use crate::prelude::*; use crate::{ expression, hash256, BareCtx, Error, ForEachKey, FromStrKey, MiniscriptKey, Satisfier, - ToPublicKey, TranslateErr, TranslatePk, Translator, + ToPublicKey, TranslateErr, Translator, }; mod bare; @@ -359,6 +359,25 @@ impl Descriptor { }; Ok(weight) } + + /// Converts a descriptor using one kind of keys to another kind of key. + pub fn translate_pk( + &self, + t: &mut T, + ) -> Result, TranslateErr> + where + T: Translator, + { + let desc = match *self { + Descriptor::Bare(ref bare) => Descriptor::Bare(bare.translate_pk(t)?), + Descriptor::Pkh(ref pk) => Descriptor::Pkh(pk.translate_pk(t)?), + Descriptor::Wpkh(ref pk) => Descriptor::Wpkh(pk.translate_pk(t)?), + Descriptor::Sh(ref sh) => Descriptor::Sh(sh.translate_pk(t)?), + Descriptor::Wsh(ref wsh) => Descriptor::Wsh(wsh.translate_pk(t)?), + Descriptor::Tr(ref tr) => Descriptor::Tr(tr.translate_pk(t)?), + }; + Ok(desc) + } } impl Descriptor { @@ -551,30 +570,6 @@ impl Descriptor { } } -impl TranslatePk for Descriptor

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Descriptor; - - /// Converts a descriptor using abstract keys to one using specific keys. - fn translate_pk(&self, t: &mut T) -> Result> - where - T: Translator, - { - let desc = match *self { - Descriptor::Bare(ref bare) => Descriptor::Bare(bare.translate_pk(t)?), - Descriptor::Pkh(ref pk) => Descriptor::Pkh(pk.translate_pk(t)?), - Descriptor::Wpkh(ref pk) => Descriptor::Wpkh(pk.translate_pk(t)?), - Descriptor::Sh(ref sh) => Descriptor::Sh(sh.translate_pk(t)?), - Descriptor::Wsh(ref wsh) => Descriptor::Wsh(wsh.translate_pk(t)?), - Descriptor::Tr(ref tr) => Descriptor::Tr(tr.translate_pk(t)?), - }; - Ok(desc) - } -} - impl ForEachKey for Descriptor { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: F) -> bool { match *self { @@ -607,7 +602,10 @@ impl Descriptor { ) -> Result, ConversionError> { struct Derivator(u32); - impl Translator for Derivator { + impl Translator for Derivator { + type TargetPk = DefiniteDescriptorKey; + type Error = ConversionError; + fn pk( &mut self, pk: &DescriptorPublicKey, @@ -698,9 +696,10 @@ impl Descriptor { struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1); - impl<'a, C: secp256k1::Signing> Translator - for KeyMapWrapper<'a, C> - { + impl<'a, C: secp256k1::Signing> Translator for KeyMapWrapper<'a, C> { + type TargetPk = DescriptorPublicKey; + type Error = Error; + fn pk(&mut self, pk: &String) -> Result { parse_key(pk, &mut self.0, self.1) } @@ -745,29 +744,35 @@ impl Descriptor { pub fn to_string_with_secret(&self, key_map: &KeyMap) -> String { struct KeyMapLookUp<'a>(&'a KeyMap); - impl<'a> Translator for KeyMapLookUp<'a> { - fn pk(&mut self, pk: &DescriptorPublicKey) -> Result { + impl<'a> Translator for KeyMapLookUp<'a> { + type TargetPk = String; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result { key_to_string(pk, self.0) } - fn sha256(&mut self, sha256: &sha256::Hash) -> Result { + fn sha256(&mut self, sha256: &sha256::Hash) -> Result { Ok(sha256.to_string()) } - fn hash256(&mut self, hash256: &hash256::Hash) -> Result { + fn hash256(&mut self, hash256: &hash256::Hash) -> Result { Ok(hash256.to_string()) } - fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result { + fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result { Ok(ripemd160.to_string()) } - fn hash160(&mut self, hash160: &hash160::Hash) -> Result { + fn hash160(&mut self, hash160: &hash160::Hash) -> Result { Ok(hash160.to_string()) } } - fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result { + fn key_to_string( + pk: &DescriptorPublicKey, + key_map: &KeyMap, + ) -> Result { Ok(match key_map.get(pk) { Some(secret) => secret.to_string(), None => pk.to_string(), @@ -842,7 +847,10 @@ impl Descriptor { // Now, transform the multipath key of each descriptor into a single-key using each index. struct IndexChoser(usize); - impl Translator for IndexChoser { + impl Translator for IndexChoser { + type TargetPk = DescriptorPublicKey; + type Error = Error; + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result { match pk { DescriptorPublicKey::Single(..) | DescriptorPublicKey::XPub(..) => { @@ -899,10 +907,10 @@ impl Descriptor { ) -> Result, ConversionError> { struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1); - impl<'a, C: secp256k1::Verification> - Translator - for Derivator<'a, C> - { + impl<'a, C: secp256k1::Verification> Translator for Derivator<'a, C> { + type TargetPk = bitcoin::PublicKey; + type Error = ConversionError; + fn pk( &mut self, pk: &DefiniteDescriptorKey, diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index b04c1ad3a..2f2532b85 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -22,7 +22,7 @@ use crate::prelude::*; use crate::util::varint_len; use crate::{ Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, - TranslateErr, TranslatePk, Translator, + TranslateErr, Translator, }; /// A Segwitv0 wsh descriptor #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -128,6 +128,18 @@ impl Wsh { varint_len(max_sat_elems) + max_sat_size) } + + /// Converts the keys in a script from one type to another. + pub fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> + where + T: Translator, + { + let inner = match self.inner { + WshInner::SortedMulti(ref smv) => WshInner::SortedMulti(smv.translate_pk(t)?), + WshInner::Ms(ref ms) => WshInner::Ms(ms.translate_pk(t)?), + }; + Ok(Wsh { inner }) + } } impl Wsh { @@ -291,25 +303,6 @@ impl ForEachKey for Wsh { } } -impl TranslatePk for Wsh

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Wsh; - - fn translate_pk(&self, t: &mut T) -> Result> - where - T: Translator, - { - let inner = match self.inner { - WshInner::SortedMulti(ref smv) => WshInner::SortedMulti(smv.translate_pk(t)?), - WshInner::Ms(ref ms) => WshInner::Ms(ms.translate_pk(t)?), - }; - Ok(Wsh { inner }) - } -} - /// A bare Wpkh descriptor at top level #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct Wpkh { @@ -370,6 +363,18 @@ impl Wpkh { note = "Use max_weight_to_satisfy instead. The method to count bytes was redesigned and the results will differ from max_weight_to_satisfy. For more details check rust-bitcoin/rust-miniscript#476." )] pub fn max_satisfaction_weight(&self) -> usize { 4 + 1 + 73 + Segwitv0::pk_len(&self.pk) } + + /// Converts the keys in a script from one type to another. + pub fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> + where + T: Translator, + { + let res = Wpkh::new(t.pk(&self.pk)?); + match res { + Ok(pk) => Ok(pk), + Err(e) => Err(TranslateErr::OuterError(Error::from(e))), + } + } } impl Wpkh { @@ -509,22 +514,3 @@ impl core::str::FromStr for Wpkh { impl ForEachKey for Wpkh { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool { pred(&self.pk) } } - -impl TranslatePk for Wpkh

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Wpkh; - - fn translate_pk(&self, t: &mut T) -> Result> - where - T: Translator, - { - let res = Wpkh::new(t.pk(&self.pk)?); - match res { - Ok(pk) => Ok(pk), - Err(e) => Err(TranslateErr::OuterError(Error::from(e))), - } - } -} diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index c575c3476..cf05c1b71 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -25,7 +25,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier, - Segwitv0, ToPublicKey, TranslateErr, TranslatePk, Translator, + Segwitv0, ToPublicKey, TranslateErr, Translator, }; /// A Legacy p2sh Descriptor @@ -259,6 +259,20 @@ impl Sh { } }) } + + /// Converts the keys in a script from one type to another. + pub fn translate_pk(&self, t: &mut T) -> Result, TranslateErr> + where + T: Translator, + { + let inner = match self.inner { + ShInner::Wsh(ref wsh) => ShInner::Wsh(wsh.translate_pk(t)?), + ShInner::Wpkh(ref wpkh) => ShInner::Wpkh(wpkh.translate_pk(t)?), + ShInner::SortedMulti(ref smv) => ShInner::SortedMulti(smv.translate_pk(t)?), + ShInner::Ms(ref ms) => ShInner::Ms(ms.translate_pk(t)?), + }; + Ok(Sh { inner }) + } } impl Sh { @@ -444,24 +458,3 @@ impl ForEachKey for Sh { } } } - -impl TranslatePk for Sh

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Sh; - - fn translate_pk(&self, t: &mut T) -> Result> - where - T: Translator, - { - let inner = match self.inner { - ShInner::Wsh(ref wsh) => ShInner::Wsh(wsh.translate_pk(t)?), - ShInner::Wpkh(ref wpkh) => ShInner::Wpkh(wpkh.translate_pk(t)?), - ShInner::SortedMulti(ref smv) => ShInner::SortedMulti(smv.translate_pk(t)?), - ShInner::Ms(ref ms) => ShInner::Ms(ms.translate_pk(t)?), - }; - Ok(Sh { inner }) - } -} diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index 5b7079292..b8a378a26 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -77,13 +77,12 @@ impl SortedMultiVec { /// This will panic if fpk returns an uncompressed key when /// converting to a Segwit descriptor. To prevent this panic, ensure /// fpk returns an error in this case instead. - pub fn translate_pk( + pub fn translate_pk( &self, t: &mut T, - ) -> Result, TranslateErr> + ) -> Result, TranslateErr> where - T: Translator, - Q: MiniscriptKey, + T: Translator, { let ret = SortedMultiVec { inner: self.inner.translate_ref(|pk| t.pk(pk))?, diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 6018551c9..2f505780c 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -24,7 +24,7 @@ use crate::prelude::*; use crate::util::{varint_len, witness_size}; use crate::{ errstr, Error, ForEachKey, FromStrKey, MiniscriptKey, Satisfier, ScriptContext, Tap, Threshold, - ToPublicKey, TranslateErr, TranslatePk, Translator, + ToPublicKey, TranslateErr, Translator, }; /// A Taproot Tree representation. @@ -132,10 +132,9 @@ impl TapTree { pub fn iter(&self) -> TapTreeIter { TapTreeIter { stack: vec![(0, self)] } } // Helper function to translate keys - fn translate_helper(&self, t: &mut T) -> Result, TranslateErr> + fn translate_helper(&self, t: &mut T) -> Result, TranslateErr> where - T: Translator, - Q: MiniscriptKey, + T: Translator, { let frag = match *self { TapTree::Tree { ref left, ref right, ref height } => TapTree::Tree { @@ -351,6 +350,23 @@ impl Tr { .max() .ok_or(Error::ImpossibleSatisfaction) } + + /// Converts keys from one type of public key to another. + pub fn translate_pk( + &self, + translate: &mut T, + ) -> Result, TranslateErr> + where + T: Translator, + { + let tree = match &self.tree { + Some(tree) => Some(tree.translate_helper(translate)?), + None => None, + }; + let translate_desc = + Tr::new(translate.pk(&self.internal_key)?, tree).map_err(TranslateErr::OuterError)?; + Ok(translate_desc) + } } impl Tr { @@ -652,27 +668,6 @@ impl ForEachKey for Tr { } } -impl TranslatePk for Tr

-where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - type Output = Tr; - - fn translate_pk(&self, translate: &mut T) -> Result> - where - T: Translator, - { - let tree = match &self.tree { - Some(tree) => Some(tree.translate_helper(translate)?), - None => None, - }; - let translate_desc = Tr::new(translate.pk(&self.internal_key)?, tree) - .map_err(|e| TranslateErr::OuterError(e))?; - Ok(translate_desc) - } -} - // Helper function to compute the len of control block at a given depth fn control_block_len(depth: u8) -> usize { TAPROOT_CONTROL_BASE_SIZE + (depth as usize) * TAPROOT_CONTROL_NODE_SIZE diff --git a/src/interpreter/inner.rs b/src/interpreter/inner.rs index e607266e7..49134c6de 100644 --- a/src/interpreter/inner.rs +++ b/src/interpreter/inner.rs @@ -356,12 +356,15 @@ impl ToNoChecks for Miniscript { fn to_no_checks_ms(&self) -> Miniscript { struct TranslateFullPk; - impl Translator for TranslateFullPk { - fn pk(&mut self, pk: &bitcoin::PublicKey) -> Result { + impl Translator for TranslateFullPk { + type TargetPk = BitcoinKey; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk: &bitcoin::PublicKey) -> Result { Ok(BitcoinKey::Fullkey(*pk)) } - translate_hash_clone!(bitcoin::PublicKey, BitcoinKey, ()); + translate_hash_clone!(bitcoin::PublicKey, BitcoinKey, Self::Error); } self.translate_pk_ctx(&mut TranslateFullPk) @@ -371,15 +374,17 @@ impl ToNoChecks for Miniscript { impl ToNoChecks for Miniscript { fn to_no_checks_ms(&self) -> Miniscript { - // specify the () error type as this cannot error struct TranslateXOnlyPk; - impl Translator for TranslateXOnlyPk { - fn pk(&mut self, pk: &bitcoin::key::XOnlyPublicKey) -> Result { + impl Translator for TranslateXOnlyPk { + type TargetPk = BitcoinKey; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk: &bitcoin::key::XOnlyPublicKey) -> Result { Ok(BitcoinKey::XOnlyPublicKey(*pk)) } - translate_hash_clone!(bitcoin::key::XOnlyPublicKey, BitcoinKey, ()); + translate_hash_clone!(bitcoin::key::XOnlyPublicKey, BitcoinKey, Self::Error); } self.translate_pk_ctx(&mut TranslateXOnlyPk) .expect("Translation should succeed") diff --git a/src/lib.rs b/src/lib.rs index b463807ce..4cf566392 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -296,25 +296,38 @@ impl ToPublicKey for bitcoin::secp256k1::XOnlyPublicKey { /// Describes an object that can translate various keys and hashes from one key to the type /// associated with the other key. Used by the [`TranslatePk`] trait to do the actual translations. -pub trait Translator -where - P: MiniscriptKey, - Q: MiniscriptKey, -{ - /// Translates public keys P -> Q. - fn pk(&mut self, pk: &P) -> Result; - - /// Provides the translation from P::Sha256 -> Q::Sha256 - fn sha256(&mut self, sha256: &P::Sha256) -> Result; - - /// Provides the translation from P::Hash256 -> Q::Hash256 - fn hash256(&mut self, hash256: &P::Hash256) -> Result; - - /// Translates ripemd160 hashes from P::Ripemd160 -> Q::Ripemd160 - fn ripemd160(&mut self, ripemd160: &P::Ripemd160) -> Result; - - /// Translates hash160 hashes from P::Hash160 -> Q::Hash160 - fn hash160(&mut self, hash160: &P::Hash160) -> Result; +pub trait Translator { + /// The public key (and associated hash types that this translator converts to. + type TargetPk: MiniscriptKey; + /// An error that may occur during transalation. + type Error; + + /// Translates keys. + fn pk(&mut self, pk: &P) -> Result; + + /// Translates SHA256 hashes. + fn sha256( + &mut self, + sha256: &P::Sha256, + ) -> Result<::Sha256, Self::Error>; + + /// Translates HASH256 hashes. + fn hash256( + &mut self, + hash256: &P::Hash256, + ) -> Result<::Hash256, Self::Error>; + + /// Translates RIPEMD160 hashes. + fn ripemd160( + &mut self, + ripemd160: &P::Ripemd160, + ) -> Result<::Ripemd160, Self::Error>; + + /// Translates HASH160 hashes. + fn hash160( + &mut self, + hash160: &P::Hash160, + ) -> Result<::Hash160, Self::Error>; } /// An enum for representing translation errors @@ -368,31 +381,14 @@ impl fmt::Debug for TranslateErr { /// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do /// the actual translation function calls. +#[deprecated(since = "TBD", note = "This trait no longer needs to be imported.")] pub trait TranslatePk where P: MiniscriptKey, Q: MiniscriptKey, { - /// The associated output type. This must be `Self`. - type Output; - - /// Translates a struct from one generic to another where the translations - /// for Pk are provided by the given [`Translator`]. - fn translate_pk(&self, translator: &mut T) -> Result> - where - T: Translator; } -/// Either a key or keyhash, but both contain Pk -// pub struct ForEach<'a, Pk: MiniscriptKey>(&'a Pk); - -// impl<'a, Pk: MiniscriptKey> ForEach<'a, Pk> { -// /// Convenience method to avoid distinguishing between keys and hashes when these are the same type -// pub fn as_key(&self) -> &'a Pk { -// self.0 -// } -// } - /// Trait describing the ability to iterate over every key pub trait ForEachKey { /// Run a predicate on every key in the descriptor, returning whether diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 5a48d74a2..1a68606ba 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -43,8 +43,7 @@ use self::lex::{lex, TokenIter}; pub use crate::miniscript::context::ScriptContext; use crate::miniscript::decode::Terminal; use crate::{ - expression, plan, Error, ForEachKey, FromStrKey, MiniscriptKey, ToPublicKey, TranslatePk, - Translator, + expression, plan, Error, ForEachKey, FromStrKey, MiniscriptKey, ToPublicKey, Translator, }; #[cfg(test)] mod ms_tests; @@ -514,33 +513,26 @@ impl ForEachKey for Miniscript TranslatePk for Miniscript -where - Pk: MiniscriptKey, - Q: MiniscriptKey, - Ctx: ScriptContext, -{ - type Output = Miniscript; - +impl Miniscript { /// Translates a struct from one generic to another where the translation /// for Pk is provided by [`Translator`] - fn translate_pk(&self, t: &mut T) -> Result> + pub fn translate_pk( + &self, + t: &mut T, + ) -> Result, TranslateErr> where - T: Translator, + T: Translator, { self.translate_pk_ctx(t) } -} -impl Miniscript { - pub(super) fn translate_pk_ctx( + pub(super) fn translate_pk_ctx( &self, t: &mut T, - ) -> Result, TranslateErr> + ) -> Result, TranslateErr> where - Q: MiniscriptKey, CtxQ: ScriptContext, - T: Translator, + T: Translator, { let mut translated = vec![]; for data in self.rtl_post_order_iter() { @@ -837,7 +829,7 @@ mod tests { use crate::policy::Liftable; use crate::prelude::*; use crate::test_utils::{StrKeyTranslator, StrXOnlyKeyTranslator}; - use crate::{hex_script, Error, ExtParams, RelLockTime, Satisfier, ToPublicKey, TranslatePk}; + use crate::{hex_script, Error, ExtParams, RelLockTime, Satisfier, ToPublicKey}; type Segwitv0Script = Miniscript; type Tapscript = Miniscript; diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 6382d837b..8e31d5474 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -507,10 +507,9 @@ impl Policy { /// Converts a policy using one kind of public key to another type of public key. /// /// For example usage please see [`crate::policy::semantic::Policy::translate_pk`]. - pub fn translate_pk(&self, t: &mut T) -> Result, E> + pub fn translate_pk(&self, t: &mut T) -> Result, T::Error> where - T: Translator, - Q: MiniscriptKey, + T: Translator, { use Policy::*; @@ -1140,15 +1139,26 @@ mod tests { #[test] fn tranaslate_pk() { pub struct TestTranslator; - impl Translator for TestTranslator { - fn pk(&mut self, pk: &String) -> Result { + impl Translator for TestTranslator { + type TargetPk = String; + type Error = core::convert::Infallible; + + fn pk(&mut self, pk: &String) -> Result { let new = format!("NEW-{}", pk); Ok(new.to_string()) } - fn sha256(&mut self, hash: &String) -> Result { Ok(hash.to_string()) } - fn hash256(&mut self, hash: &String) -> Result { Ok(hash.to_string()) } - fn ripemd160(&mut self, hash: &String) -> Result { Ok(hash.to_string()) } - fn hash160(&mut self, hash: &String) -> Result { Ok(hash.to_string()) } + fn sha256(&mut self, hash: &String) -> Result { + Ok(hash.to_string()) + } + fn hash256(&mut self, hash: &String) -> Result { + Ok(hash.to_string()) + } + fn ripemd160(&mut self, hash: &String) -> Result { + Ok(hash.to_string()) + } + fn hash160(&mut self, hash: &String) -> Result { + Ok(hash.to_string()) + } } let policy = Policy::::from_str("or(and(pk(A),pk(B)),pk(C))").unwrap(); let mut t = TestTranslator; diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 7d2959764..62487a54a 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -120,8 +120,11 @@ impl Policy { /// /// // If we also wanted to provide mapping of other associated types (sha256, older etc), /// // we would use the general [`Translator`] trait. - /// impl Translator for StrPkTranslator { - /// fn pk(&mut self, pk: &String) -> Result { + /// impl Translator for StrPkTranslator { + /// type TargetPk = bitcoin::PublicKey; + /// type Error = (); + /// + /// fn pk(&mut self, pk: &String) -> Result { /// self.pk_map.get(pk).copied().ok_or(()) // Dummy Err /// } /// @@ -140,10 +143,9 @@ impl Policy { /// let expected_policy = Policy::from_str(&format!("and(pk({}),pk({}))", alice_pk, bob_pk)).unwrap(); /// assert_eq!(real_policy, expected_policy); /// ``` - pub fn translate_pk(&self, t: &mut T) -> Result, E> + pub fn translate_pk(&self, t: &mut T) -> Result, T::Error> where - T: Translator, - Q: MiniscriptKey, + T: Translator, { use Policy::*; diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 2c489ca89..96615df4c 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -25,7 +25,7 @@ use crate::miniscript::context::SigType; use crate::prelude::*; use crate::{ descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey, - Preimage32, Satisfier, ToPublicKey, TranslatePk, Translator, + Preimage32, Satisfier, ToPublicKey, Translator, }; mod finalizer; @@ -976,9 +976,10 @@ struct KeySourceLookUp( pub secp256k1::Secp256k1, ); -impl Translator - for KeySourceLookUp -{ +impl Translator for KeySourceLookUp { + type TargetPk = bitcoin::PublicKey; + type Error = descriptor::ConversionError; + fn pk( &mut self, xpk: &DefiniteDescriptorKey, diff --git a/src/pub_macros.rs b/src/pub_macros.rs index bdb0d59b4..538d37f3c 100644 --- a/src/pub_macros.rs +++ b/src/pub_macros.rs @@ -27,9 +27,12 @@ /// /// // If we also wanted to provide mapping of other associated types(sha256, older etc), /// // we would use the general Translator Trait. -/// impl Translator for StrPkTranslator { +/// impl Translator for StrPkTranslator { +/// type TargetPk = bitcoin::PublicKey; +/// type Error = (); +/// /// // Provides the translation public keys P -> Q -/// fn pk(&mut self, pk: &String) -> Result { +/// fn pk(&mut self, pk: &String) -> Result { /// self.pk_map.get(pk).copied().ok_or(()) // Dummy Err /// } /// diff --git a/src/test_utils.rs b/src/test_utils.rs index 170e3c7f6..9d52b7c25 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -2,6 +2,7 @@ //! Generally useful utilities for test scripts +use core::convert::Infallible; use std::collections::HashMap; use std::str::FromStr; @@ -25,8 +26,11 @@ pub struct StrKeyTranslator { pub hash160_map: HashMap, } -impl Translator for StrKeyTranslator { - fn pk(&mut self, pk: &String) -> Result { +impl Translator for StrKeyTranslator { + type TargetPk = bitcoin::PublicKey; + type Error = Infallible; + + fn pk(&mut self, pk: &String) -> Result { let key = self.pk_map.get(pk).copied().unwrap_or_else(|| { bitcoin::PublicKey::from_str( "02c2122e30e73f7fe37986e3f81ded00158e94b7ad472369b83bbdd28a9a198a39", @@ -36,7 +40,7 @@ impl Translator for StrKeyTranslator { Ok(key) } - fn sha256(&mut self, _sha256: &String) -> Result { + fn sha256(&mut self, _sha256: &String) -> Result { let hash = sha256::Hash::from_str( "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", ) @@ -44,7 +48,7 @@ impl Translator for StrKeyTranslator { Ok(hash) } - fn hash256(&mut self, _hash256: &String) -> Result { + fn hash256(&mut self, _hash256: &String) -> Result { // hard coded value let hash = hash256::Hash::from_str( "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", @@ -53,12 +57,12 @@ impl Translator for StrKeyTranslator { Ok(hash) } - fn ripemd160(&mut self, _ripemd160: &String) -> Result { + fn ripemd160(&mut self, _ripemd160: &String) -> Result { let hash = ripemd160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); Ok(hash) } - fn hash160(&mut self, _hash160: &String) -> Result { + fn hash160(&mut self, _hash160: &String) -> Result { let hash = hash160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); Ok(hash) } @@ -74,8 +78,11 @@ pub struct StrXOnlyKeyTranslator { pub hash160_map: HashMap, } -impl Translator for StrXOnlyKeyTranslator { - fn pk(&mut self, pk: &String) -> Result { +impl Translator for StrXOnlyKeyTranslator { + type TargetPk = XOnlyPublicKey; + type Error = Infallible; + + fn pk(&mut self, pk: &String) -> Result { let key = self.pk_map.get(pk).copied().unwrap_or_else(|| { XOnlyPublicKey::from_str( "c2122e30e73f7fe37986e3f81ded00158e94b7ad472369b83bbdd28a9a198a39", @@ -85,7 +92,7 @@ impl Translator for StrXOnlyKeyTranslator { Ok(key) } - fn sha256(&mut self, _sha256: &String) -> Result { + fn sha256(&mut self, _sha256: &String) -> Result { let hash = sha256::Hash::from_str( "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", ) @@ -93,7 +100,7 @@ impl Translator for StrXOnlyKeyTranslator { Ok(hash) } - fn hash256(&mut self, _hash256: &String) -> Result { + fn hash256(&mut self, _hash256: &String) -> Result { let hash = hash256::Hash::from_str( "4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260", ) @@ -101,12 +108,12 @@ impl Translator for StrXOnlyKeyTranslator { Ok(hash) } - fn ripemd160(&mut self, _ripemd160: &String) -> Result { + fn ripemd160(&mut self, _ripemd160: &String) -> Result { let hash = ripemd160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); Ok(hash) } - fn hash160(&mut self, _hash160: &String) -> Result { + fn hash160(&mut self, _hash160: &String) -> Result { let hash = hash160::Hash::from_str("4ae81572f06e1b88fd5ced7a1a00094543a0069").unwrap(); Ok(hash) }