Skip to content

Commit 372377a

Browse files
committed
Remove PkTranslator trait
Create macros for writing Translator functions The trait has a general implementation of Translator like `impl Translator for PkTranslator where P::Sha256 ...`. However, this blanket implementation has constraints on associated types and makes it impossible to implement the trait for a generic type downstream. Rust compiler does not support trait specialization yet, so we should only provide a macro to ease implementation rather than a blanket implementation that causes duplicate conflicts downstream
1 parent 2f1535e commit 372377a

File tree

8 files changed

+169
-119
lines changed

8 files changed

+169
-119
lines changed

examples/taproot.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::collections::HashMap;
22
use std::str::FromStr;
33

4-
use bitcoin::hashes::{hash160, ripemd160, sha256};
4+
use bitcoin::hashes::hash160;
55
use bitcoin::util::address::WitnessVersion;
66
use bitcoin::Network;
77
use miniscript::descriptor::DescriptorType;
88
use miniscript::policy::Concrete;
9-
use miniscript::{hash256, Descriptor, Miniscript, Tap, TranslatePk, Translator};
9+
use miniscript::{translate_hash_fail, Descriptor, Miniscript, Tap, TranslatePk, Translator};
1010
use secp256k1::{rand, KeyPair};
1111

1212
// Refer to https://github.com/sanket1729/adv_btc_workshop/blob/master/workshop.md#creating-a-taproot-descriptor
@@ -25,21 +25,10 @@ impl Translator<String, bitcoin::XOnlyPublicKey, ()> for StrPkTranslator {
2525
unreachable!("Policy doesn't contain any pkh fragment");
2626
}
2727

28-
fn sha256(&mut self, _sha256: &String) -> Result<sha256::Hash, ()> {
29-
unreachable!("Policy does not contain any sha256 fragment");
30-
}
31-
32-
fn hash256(&mut self, _sha256: &String) -> Result<hash256::Hash, ()> {
33-
unreachable!("Policy does not contain any hash256 fragment");
34-
}
35-
36-
fn ripemd160(&mut self, _ripemd160: &String) -> Result<ripemd160::Hash, ()> {
37-
unreachable!("Policy does not contain any ripemd160 fragment");
38-
}
39-
40-
fn hash160(&mut self, _hash160: &String) -> Result<hash160::Hash, ()> {
41-
unreachable!("Policy does not contain any hash160 fragment");
42-
}
28+
// We don't need to implement these methods as we are not using them in the policy
29+
// Fail if we encounter any hash fragments.
30+
// See also translate_hash_clone! macro
31+
translate_hash_fail!(String, bitcoin::XOnlyPublicKey, ());
4332
}
4433

4534
fn main() {

src/descriptor/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ use self::checksum::verify_checksum;
3737
use crate::miniscript::{Legacy, Miniscript, Segwitv0};
3838
use crate::prelude::*;
3939
use crate::{
40-
expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, PkTranslator,
41-
Satisfier, ToPublicKey, TranslatePk, Translator,
40+
expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier,
41+
ToPublicKey, TranslatePk, Translator,
4242
};
4343

4444
mod bare;
@@ -532,14 +532,16 @@ impl Descriptor<DescriptorPublicKey> {
532532
pub fn at_derivation_index(&self, index: u32) -> Descriptor<DefiniteDescriptorKey> {
533533
struct Derivator(u32);
534534

535-
impl PkTranslator<DescriptorPublicKey, DefiniteDescriptorKey, ()> for Derivator {
535+
impl Translator<DescriptorPublicKey, DefiniteDescriptorKey, ()> for Derivator {
536536
fn pk(&mut self, pk: &DescriptorPublicKey) -> Result<DefiniteDescriptorKey, ()> {
537537
Ok(pk.clone().at_derivation_index(self.0))
538538
}
539539

540540
fn pkh(&mut self, pkh: &DescriptorPublicKey) -> Result<DefiniteDescriptorKey, ()> {
541541
Ok(pkh.clone().at_derivation_index(self.0))
542542
}
543+
544+
translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ());
543545
}
544546
self.translate_pk(&mut Derivator(index))
545547
.expect("BIP 32 key index substitution cannot fail")
@@ -766,7 +768,7 @@ impl Descriptor<DefiniteDescriptorKey> {
766768
struct Derivator<'a, C: secp256k1::Verification>(&'a secp256k1::Secp256k1<C>);
767769

768770
impl<'a, C: secp256k1::Verification>
769-
PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError>
771+
Translator<DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError>
770772
for Derivator<'a, C>
771773
{
772774
fn pk(
@@ -782,6 +784,8 @@ impl Descriptor<DefiniteDescriptorKey> {
782784
) -> Result<bitcoin::hashes::hash160::Hash, ConversionError> {
783785
Ok(pkh.derive_public_key(&self.0)?.to_pubkeyhash())
784786
}
787+
788+
translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError);
785789
}
786790

787791
let derived = self.translate_pk(&mut Derivator(secp))?;

src/interpreter/inner.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use bitcoin::util::taproot::{ControlBlock, TAPROOT_ANNEX_PREFIX};
2020
use super::{stack, BitcoinKey, Error, Stack, TypedHash160};
2121
use crate::miniscript::context::{NoChecks, ScriptContext};
2222
use crate::prelude::*;
23-
use crate::{BareCtx, Legacy, Miniscript, MiniscriptKey, PkTranslator, Segwitv0, Tap};
23+
use crate::{BareCtx, Legacy, Miniscript, MiniscriptKey, Segwitv0, Tap, Translator};
2424

2525
/// Attempts to parse a slice as a Bitcoin public key, checking compressedness
2626
/// if asked to, but otherwise dropping it
@@ -377,14 +377,16 @@ impl<Ctx: ScriptContext> ToNoChecks for Miniscript<bitcoin::PublicKey, Ctx> {
377377
fn to_no_checks_ms(&self) -> Miniscript<BitcoinKey, NoChecks> {
378378
struct TranslateFullPk;
379379

380-
impl PkTranslator<bitcoin::PublicKey, BitcoinKey, ()> for TranslateFullPk {
380+
impl Translator<bitcoin::PublicKey, BitcoinKey, ()> for TranslateFullPk {
381381
fn pk(&mut self, pk: &bitcoin::PublicKey) -> Result<BitcoinKey, ()> {
382382
Ok(BitcoinKey::Fullkey(*pk))
383383
}
384384

385385
fn pkh(&mut self, pkh: &hash160::Hash) -> Result<TypedHash160, ()> {
386386
Ok(TypedHash160::FullKey(*pkh))
387387
}
388+
389+
translate_hash_clone!(bitcoin::PublicKey, BitcoinKey, ());
388390
}
389391

390392
self.real_translate_pk(&mut TranslateFullPk)
@@ -397,14 +399,15 @@ impl<Ctx: ScriptContext> ToNoChecks for Miniscript<bitcoin::XOnlyPublicKey, Ctx>
397399
// specify the () error type as this cannot error
398400
struct TranslateXOnlyPk;
399401

400-
impl PkTranslator<bitcoin::XOnlyPublicKey, BitcoinKey, ()> for TranslateXOnlyPk {
402+
impl Translator<bitcoin::XOnlyPublicKey, BitcoinKey, ()> for TranslateXOnlyPk {
401403
fn pk(&mut self, pk: &bitcoin::XOnlyPublicKey) -> Result<BitcoinKey, ()> {
402404
Ok(BitcoinKey::XOnlyPublicKey(*pk))
403405
}
404406

405407
fn pkh(&mut self, pkh: &hash160::Hash) -> Result<TypedHash160, ()> {
406408
Ok(TypedHash160::XonlyKey(*pkh))
407409
}
410+
translate_hash_clone!(bitcoin::XOnlyPublicKey, BitcoinKey, ());
408411
}
409412
self.real_translate_pk(&mut TranslateXOnlyPk)
410413
.expect("Translation should succeed")

src/lib.rs

Lines changed: 5 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ extern crate test;
115115
#[macro_use]
116116
mod macros;
117117

118+
#[macro_use]
119+
mod pub_macros;
120+
121+
pub use pub_macros::*;
122+
118123
pub mod descriptor;
119124
pub mod expression;
120125
pub mod interpreter;
@@ -586,63 +591,6 @@ where
586591
fn hash160(&mut self, hash160: &P::Hash160) -> Result<Q::Hash160, E>;
587592
}
588593

589-
/// Provides the conversion information required in [`TranslatePk`].
590-
/// Same as [`Translator`], but useful when all the associated types apart
591-
/// from Pk/Pkh don't change in translation
592-
pub trait PkTranslator<P, Q, E>
593-
where
594-
P: MiniscriptKey,
595-
Q: MiniscriptKey<Sha256 = P::Sha256>,
596-
{
597-
/// Provides the translation public keys P -> Q
598-
fn pk(&mut self, pk: &P) -> Result<Q, E>;
599-
600-
/// Provides the translation public keys hashes P::Hash -> Q::Hash
601-
fn pkh(&mut self, pkh: &P::RawPkHash) -> Result<Q::RawPkHash, E>;
602-
}
603-
604-
impl<P, Q, E, T> Translator<P, Q, E> for T
605-
where
606-
T: PkTranslator<P, Q, E>,
607-
P: MiniscriptKey,
608-
Q: MiniscriptKey<
609-
Sha256 = P::Sha256,
610-
Hash256 = P::Hash256,
611-
Ripemd160 = P::Ripemd160,
612-
Hash160 = P::Hash160,
613-
>,
614-
{
615-
fn pk(&mut self, pk: &P) -> Result<Q, E> {
616-
<Self as PkTranslator<P, Q, E>>::pk(self, pk)
617-
}
618-
619-
fn pkh(
620-
&mut self,
621-
pkh: &<P as MiniscriptKey>::RawPkHash,
622-
) -> Result<<Q as MiniscriptKey>::RawPkHash, E> {
623-
<Self as PkTranslator<P, Q, E>>::pkh(self, pkh)
624-
}
625-
626-
fn sha256(&mut self, sha256: &<P as MiniscriptKey>::Sha256) -> Result<<Q>::Sha256, E> {
627-
Ok(sha256.clone())
628-
}
629-
630-
fn hash256(&mut self, hash256: &<P as MiniscriptKey>::Hash256) -> Result<<Q>::Hash256, E> {
631-
Ok(hash256.clone())
632-
}
633-
634-
fn ripemd160(
635-
&mut self,
636-
ripemd160: &<P as MiniscriptKey>::Ripemd160,
637-
) -> Result<<Q>::Ripemd160, E> {
638-
Ok(ripemd160.clone())
639-
}
640-
641-
fn hash160(&mut self, hash160: &<P as MiniscriptKey>::Hash160) -> Result<<Q>::Hash160, E> {
642-
Ok(hash160.clone())
643-
}
644-
}
645-
646594
/// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do
647595
/// the actual translation function calls.
648596
pub trait TranslatePk<P, Q>

src/policy/concrete.rs

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
684684
/// ```
685685
/// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator, hash256};
686686
/// use std::str::FromStr;
687+
/// use miniscript::translate_hash_fail;
687688
/// use std::collections::HashMap;
688689
/// use miniscript::bitcoin::hashes::{sha256, hash160, ripemd160};
689690
/// let alice_key = "0270cf3c71f65a3d93d285d9149fddeeb638f87a2d4d8cf16c525f71c417439777";
@@ -709,23 +710,8 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
709710
/// unreachable!("Policy does not contain any pkh fragment");
710711
/// }
711712
///
712-
/// // If our policy also contained other fragments, we could provide the translation here.
713-
/// fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, ()> {
714-
/// unreachable!("Policy does not contain any sha256 fragment");
715-
/// }
716-
///
717-
/// // If our policy also contained other fragments, we could provide the translation here.
718-
/// fn hash256(&mut self, sha256: &String) -> Result<hash256::Hash, ()> {
719-
/// unreachable!("Policy does not contain any sha256 fragment");
720-
/// }
721-
///
722-
/// fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, ()> {
723-
/// unreachable!("Policy does not contain any ripemd160 fragment");
724-
/// }
725-
///
726-
/// fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, ()> {
727-
/// unreachable!("Policy does not contain any hash160 fragment");
728-
/// }
713+
/// // Fail for hash types
714+
/// translate_hash_fail!(String, bitcoin::PublicKey, ());
729715
/// }
730716
///
731717
/// let mut pk_map = HashMap::new();

src/policy/semantic.rs

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
9999
///
100100
/// ```
101101
/// use miniscript::{bitcoin::{hashes::{hash160, ripemd160}, PublicKey}, policy::semantic::Policy, Translator, hash256};
102+
/// use miniscript::translate_hash_fail;
102103
/// use std::str::FromStr;
103104
/// use std::collections::HashMap;
104105
/// use miniscript::bitcoin::hashes::sha256;
@@ -125,23 +126,9 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
125126
/// self.pk_map.get(pkh).copied().ok_or(()) // Dummy Err
126127
/// }
127128
///
128-
/// // If our policy also contained other fragments, we could provide the translation here.
129-
/// fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, ()> {
130-
/// unreachable!("Policy does not contain any sha256 fragment");
131-
/// }
132-
///
133-
/// // If our policy also contained other fragments, we could provide the translation here.
134-
/// fn hash256(&mut self, sha256: &String) -> Result<hash256::Hash, ()> {
135-
/// unreachable!("Policy does not contain any sha256 fragment");
136-
/// }
137-
///
138-
/// fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, ()> {
139-
/// unreachable!("Policy does not contain any ripemd160 fragment");
140-
/// }
141-
///
142-
/// fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, ()> {
143-
/// unreachable!("Policy does not contain any hash160 fragment");
144-
/// }
129+
/// // Handy macro for failing if we encounter any other fragment.
130+
/// // also see translate_hash_clone! for cloning instead of failing
131+
/// translate_hash_fail!(String, bitcoin::PublicKey, ());
145132
/// }
146133
///
147134
/// let mut pk_map = HashMap::new();

src/psbt/mod.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ use bitcoin::{self, EcdsaSighashType, LockTime, SchnorrSighashType, Script, Sequ
3636
use crate::miniscript::iter::PkPkh;
3737
use crate::prelude::*;
3838
use crate::{
39-
descriptor, interpreter, DefiniteDescriptorKey, Descriptor, MiniscriptKey, PkTranslator,
40-
Preimage32, Satisfier, ToPublicKey, TranslatePk,
39+
descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey,
40+
Preimage32, Satisfier, ToPublicKey, TranslatePk, Translator,
4141
};
4242

4343
mod finalizer;
@@ -1005,7 +1005,7 @@ struct XOnlyHashLookUp(
10051005
pub secp256k1::Secp256k1<VerifyOnly>,
10061006
);
10071007

1008-
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
1008+
impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
10091009
for XOnlyHashLookUp
10101010
{
10111011
fn pk(
@@ -1025,6 +1025,13 @@ impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::Convers
10251025
self.0.insert(hash, xonly);
10261026
Ok(hash)
10271027
}
1028+
1029+
// Clone all the associated types in translation
1030+
translate_hash_clone!(
1031+
DescriptorPublicKey,
1032+
bitcoin::PublicKey,
1033+
descriptor::ConversionError
1034+
);
10281035
}
10291036

10301037
// Traverse the pkh lookup while maintaining a reverse map for storing the map
@@ -1034,7 +1041,7 @@ struct KeySourceLookUp(
10341041
pub secp256k1::Secp256k1<VerifyOnly>,
10351042
);
10361043

1037-
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
1044+
impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
10381045
for KeySourceLookUp
10391046
{
10401047
fn pk(
@@ -1055,6 +1062,12 @@ impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::Convers
10551062
) -> Result<hash160::Hash, descriptor::ConversionError> {
10561063
Ok(self.pk(xpk)?.to_pubkeyhash())
10571064
}
1065+
1066+
translate_hash_clone!(
1067+
DescriptorPublicKey,
1068+
bitcoin::PublicKey,
1069+
descriptor::ConversionError
1070+
);
10581071
}
10591072

10601073
// Provides generalized access to PSBT fields common to inputs and outputs

0 commit comments

Comments
 (0)