Skip to content

Commit fb8fd49

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 cddc22d commit fb8fd49

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
@@ -388,6 +388,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
388388
/// ```
389389
/// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator, hash256};
390390
/// use std::str::FromStr;
391+
/// use miniscript::translate_hash_fail;
391392
/// use std::collections::HashMap;
392393
/// use miniscript::bitcoin::hashes::{sha256, hash160, ripemd160};
393394
/// let alice_key = "0270cf3c71f65a3d93d285d9149fddeeb638f87a2d4d8cf16c525f71c417439777";
@@ -413,23 +414,8 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
413414
/// unreachable!("Policy does not contain any pkh fragment");
414415
/// }
415416
///
416-
/// // If our policy also contained other fragments, we could provide the translation here.
417-
/// fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, ()> {
418-
/// unreachable!("Policy does not contain any sha256 fragment");
419-
/// }
420-
///
421-
/// // If our policy also contained other fragments, we could provide the translation here.
422-
/// fn hash256(&mut self, sha256: &String) -> Result<hash256::Hash, ()> {
423-
/// unreachable!("Policy does not contain any sha256 fragment");
424-
/// }
425-
///
426-
/// fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, ()> {
427-
/// unreachable!("Policy does not contain any ripemd160 fragment");
428-
/// }
429-
///
430-
/// fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, ()> {
431-
/// unreachable!("Policy does not contain any hash160 fragment");
432-
/// }
417+
/// // Fail for hash types
418+
/// translate_hash_fail!(String, bitcoin::PublicKey, ());
433419
/// }
434420
///
435421
/// 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
@@ -34,8 +34,8 @@ use bitcoin::{self, EcdsaSighashType, LockTime, SchnorrSighashType, Script, Sequ
3434
use crate::miniscript::iter::PkPkh;
3535
use crate::prelude::*;
3636
use crate::{
37-
descriptor, interpreter, DefiniteDescriptorKey, Descriptor, MiniscriptKey, PkTranslator,
38-
Preimage32, Satisfier, ToPublicKey, TranslatePk,
37+
descriptor, interpreter, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, MiniscriptKey,
38+
Preimage32, Satisfier, ToPublicKey, TranslatePk, Translator,
3939
};
4040

4141
mod finalizer;
@@ -934,7 +934,7 @@ struct XOnlyHashLookUp(
934934
pub secp256k1::Secp256k1<VerifyOnly>,
935935
);
936936

937-
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
937+
impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
938938
for XOnlyHashLookUp
939939
{
940940
fn pk(
@@ -954,6 +954,13 @@ impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::Convers
954954
self.0.insert(hash, xonly);
955955
Ok(hash)
956956
}
957+
958+
// Clone all the associated types in translation
959+
translate_hash_clone!(
960+
DescriptorPublicKey,
961+
bitcoin::PublicKey,
962+
descriptor::ConversionError
963+
);
957964
}
958965

959966
// Traverse the pkh lookup while maintaining a reverse map for storing the map
@@ -963,7 +970,7 @@ struct KeySourceLookUp(
963970
pub secp256k1::Secp256k1<VerifyOnly>,
964971
);
965972

966-
impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
973+
impl Translator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::ConversionError>
967974
for KeySourceLookUp
968975
{
969976
fn pk(
@@ -984,6 +991,12 @@ impl PkTranslator<DefiniteDescriptorKey, bitcoin::PublicKey, descriptor::Convers
984991
) -> Result<hash160::Hash, descriptor::ConversionError> {
985992
Ok(self.pk(xpk)?.to_pubkeyhash())
986993
}
994+
995+
translate_hash_clone!(
996+
DescriptorPublicKey,
997+
bitcoin::PublicKey,
998+
descriptor::ConversionError
999+
);
9871000
}
9881001

9891002
fn update_input_with_descriptor_helper(

0 commit comments

Comments
 (0)