Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework translate API to allow associated types to be translated #426

Merged
merged 3 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/xpub_descriptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::str::FromStr;

use miniscript::bitcoin::secp256k1::{Secp256k1, Verification};
use miniscript::bitcoin::{Address, Network};
use miniscript::{Descriptor, DescriptorPublicKey, TranslatePk2};
use miniscript::{Descriptor, DescriptorPublicKey};

const XPUB_1: &str = "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB";
const XPUB_2: &str = "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH";
Expand All @@ -42,7 +42,7 @@ fn p2wsh<C: Verification>(secp: &Secp256k1<C>) -> Address {

let address = Descriptor::<DescriptorPublicKey>::from_str(&s)
.unwrap()
.translate_pk2(|xpk| xpk.derive_public_key(secp))
.derived_descriptor(&secp, 0) // dummy index value if it not a wildcard
.unwrap()
.address(Network::Bitcoin)
.unwrap();
Expand Down
69 changes: 21 additions & 48 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//!

use core::fmt;
use core::str::FromStr;

use bitcoin::blockdata::script;
use bitcoin::{Address, Network, Script};
Expand All @@ -32,7 +31,7 @@ use crate::prelude::*;
use crate::util::{varint_len, witness_to_scriptsig};
use crate::{
BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey,
TranslatePk,
TranslatePk, Translator,
};

/// Create a Bare Descriptor. That is descriptor that is
Expand Down Expand Up @@ -145,35 +144,24 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Bare<Pk> {
}
}

impl<Pk> FromTree for Bare<Pk>
where
Pk: MiniscriptKey + FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
impl_from_tree!(
Bare<Pk>,
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
let sub = Miniscript::<Pk, BareCtx>::from_tree(top)?;
BareCtx::top_level_checks(&sub)?;
Bare::new(sub)
}
}

impl<Pk> FromStr for Bare<Pk>
where
Pk: MiniscriptKey + FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
type Err = Error;
);

impl_from_str!(
Bare<Pk>,
type Err = Error;,
fn from_str(s: &str) -> Result<Self, Self::Err> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
Self::from_tree(&top)
}
}
);

impl<Pk: MiniscriptKey> ForEachKey<Pk> for Bare<Pk> {
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
Expand All @@ -192,14 +180,11 @@ where
{
type Output = Bare<Q>;

fn translate_pk<Fpk, Fpkh, E>(&self, mut fpk: Fpk, mut fpkh: Fpkh) -> Result<Self::Output, E>
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
where
Fpk: FnMut(&P) -> Result<Q, E>,
Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>,
Q: MiniscriptKey,
T: Translator<P, Q, E>,
{
Ok(Bare::new(self.ms.translate_pk(&mut fpk, &mut fpkh)?)
.expect("Translation cannot fail inside Bare"))
Ok(Bare::new(self.ms.translate_pk(t)?).expect("Translation cannot fail inside Bare"))
}
}

Expand Down Expand Up @@ -313,13 +298,8 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Pkh<Pk> {
}
}

impl<Pk> FromTree for Pkh<Pk>
where
Pk: MiniscriptKey + FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
impl_from_tree!(
Pkh<Pk>,
fn from_tree(top: &expression::Tree) -> Result<Self, Error> {
if top.name == "pkh" && top.args.len() == 1 {
Ok(Pkh::new(expression::terminal(&top.args[0], |pk| {
Expand All @@ -333,23 +313,17 @@ where
)))
}
}
}

impl<Pk> FromStr for Pkh<Pk>
where
Pk: MiniscriptKey + FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
type Err = Error;
);

impl_from_str!(
Pkh<Pk>,
type Err = Error;,
fn from_str(s: &str) -> Result<Self, Self::Err> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
Self::from_tree(&top)
}
}
);

impl<Pk: MiniscriptKey> ForEachKey<Pk> for Pkh<Pk> {
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
Expand All @@ -368,11 +342,10 @@ where
{
type Output = Pkh<Q>;

fn translate_pk<Fpk, Fpkh, E>(&self, mut fpk: Fpk, _fpkh: Fpkh) -> Result<Self::Output, E>
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
where
Fpk: FnMut(&P) -> Result<Q, E>,
Fpkh: FnMut(&P::Hash) -> Result<Q::Hash, E>,
T: Translator<P, Q, E>,
{
Ok(Pkh::new(fpk(&self.pk)?))
Ok(Pkh::new(t.pk(&self.pk)?))
}
}
8 changes: 7 additions & 1 deletion src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::str::FromStr;
use std::error;

use bitcoin::hashes::hex::FromHex;
use bitcoin::hashes::{hash160, Hash, HashEngine};
use bitcoin::hashes::{hash160, sha256, Hash, HashEngine};
use bitcoin::secp256k1::{Secp256k1, Signing, Verification};
use bitcoin::util::bip32;
use bitcoin::{self, XOnlyPublicKey, XpubIdentifier};
Expand Down Expand Up @@ -737,6 +737,7 @@ impl<K: InnerXKey> DescriptorXKey<K> {
impl MiniscriptKey for DescriptorPublicKey {
// This allows us to be able to derive public keys even for PkH s
type Hash = Self;
type Sha256 = bitcoin::hashes::sha256::Hash;

fn is_uncompressed(&self) -> bool {
match self {
Expand Down Expand Up @@ -802,6 +803,7 @@ impl fmt::Display for DerivedDescriptorKey {
impl MiniscriptKey for DerivedDescriptorKey {
// This allows us to be able to derive public keys even for PkH s
type Hash = Self;
type Sha256 = bitcoin::hashes::sha256::Hash;

fn is_uncompressed(&self) -> bool {
self.key.is_uncompressed()
Expand All @@ -825,6 +827,10 @@ impl ToPublicKey for DerivedDescriptorKey {
fn hash_to_hash160(hash: &Self) -> hash160::Hash {
hash.to_public_key().to_pubkeyhash()
}

fn to_sha256(hash: &sha256::Hash) -> sha256::Hash {
*hash
}
}

#[cfg(test)]
Expand Down
Loading