Skip to content

Commit

Permalink
Workaround compiler goof in Policy::translate_pk
Browse files Browse the repository at this point in the history
These previously untested methods result in a compiler error if you ever
tried to call them. This happens because if you put &mut in front of the
type when you recursively pass it to another call you are actually
creating a &mut &mut since the argument may already be a &mut. This ends
up in infinite &muts prefix. The compiler only figures this out when you call
the method (not at compile time of the library).

I fixed this by having an inner function take a &mut FnMut as the argument
and so breaking the chain of &mut. The public functions remains the same.
  • Loading branch information
LLFourn committed Feb 16, 2021
1 parent 42367cf commit ef1d69c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
33 changes: 30 additions & 3 deletions src/policy/concrete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,34 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Policy<Pk> {
impl<Pk: MiniscriptKey> Policy<Pk> {
/// Convert a policy using one kind of public key to another
/// type of public key
///
/// # Example
///
/// ```
/// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy};
/// use std::str::FromStr;
/// let alice_key = "0270cf3c71f65a3d93d285d9149fddeeb638f87a2d4d8cf16c525f71c417439777";
/// let bob_key = "02f43b15c50a436f5335dbea8a64dd3b4e63e34c3b50c42598acb5f4f336b5d2fb";
/// let placeholder_policy = Policy::<String>::from_str("and(pk(alice_key),pk(bob_key))").unwrap();
///
/// let real_policy = placeholder_policy.translate_pk(|placeholder: &String| match placeholder.as_str() {
/// "alice_key" => PublicKey::from_str(alice_key),
/// "bob_key" => PublicKey::from_str(bob_key),
/// _ => panic!("unknown key!")
/// }).unwrap();
///
/// let expected_policy = Policy::from_str(&format!("and(pk({}),pk({}))", alice_key, bob_key)).unwrap();
/// assert_eq!(real_policy, expected_policy);
/// ```
pub fn translate_pk<Fpk, Q, E>(&self, mut translatefpk: Fpk) -> Result<Policy<Q>, E>
where
Fpk: FnMut(&Pk) -> Result<Q, E>,
Q: MiniscriptKey,
{
self._translate_pk(&mut translatefpk)
}

fn _translate_pk<Fpk, Q, E>(&self, translatefpk: &mut Fpk) -> Result<Policy<Q>, E>
where
Fpk: FnMut(&Pk) -> Result<Q, E>,
Q: MiniscriptKey,
Expand All @@ -184,18 +211,18 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
Policy::Threshold(k, ref subs) => {
let new_subs: Result<Vec<Policy<Q>>, _> = subs
.iter()
.map(|sub| sub.translate_pk(&mut translatefpk))
.map(|sub| sub._translate_pk(translatefpk))
.collect();
new_subs.map(|ok| Policy::Threshold(k, ok))
}
Policy::And(ref subs) => Ok(Policy::And(
subs.iter()
.map(|sub| sub.translate_pk(&mut translatefpk))
.map(|sub| sub._translate_pk(translatefpk))
.collect::<Result<Vec<Policy<Q>>, E>>()?,
)),
Policy::Or(ref subs) => Ok(Policy::Or(
subs.iter()
.map(|&(ref prob, ref sub)| Ok((*prob, sub.translate_pk(&mut translatefpk)?)))
.map(|&(ref prob, ref sub)| Ok((*prob, sub._translate_pk(translatefpk)?)))
.collect::<Result<Vec<(usize, Policy<Q>)>, E>>()?,
)),
}
Expand Down
29 changes: 28 additions & 1 deletion src/policy/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,34 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for Policy<Pk> {
impl<Pk: MiniscriptKey> Policy<Pk> {
/// Convert a policy using one kind of public key to another
/// type of public key
///
/// # Example
///
/// ```
/// use miniscript::{bitcoin::{hashes::hash160, PublicKey}, policy::semantic::Policy};
/// use std::str::FromStr;
/// let alice_pkh = "236ada020df3208d2517f4b0db03e16f92cd8cf1";
/// let bob_pkh = "3e89b972416ae33870b4634d03b8cdc773200cac";
/// let placeholder_policy = Policy::<String>::from_str("and(pkh(alice_pkh),pkh(bob_pkh))").unwrap();
///
/// let real_policy = placeholder_policy.translate_pkh(|placeholder| match placeholder.as_str() {
/// "alice_pkh" => hash160::Hash::from_str(alice_pkh),
/// "bob_pkh" => hash160::Hash::from_str(bob_pkh),
/// _ => panic!("unknown key hash!")
/// }).unwrap();
///
/// let expected_policy = Policy::<PublicKey>::from_str(&format!("and(pkh({}),pkh({}))", alice_pkh, bob_pkh)).unwrap();
/// assert_eq!(real_policy, expected_policy);
/// ```
pub fn translate_pkh<Fpkh, Q, E>(&self, mut translatefpkh: Fpkh) -> Result<Policy<Q>, E>
where
Fpkh: FnMut(&Pk::Hash) -> Result<Q::Hash, E>,
Q: MiniscriptKey,
{
self._translate_pkh(&mut translatefpkh)
}

fn _translate_pkh<Fpkh, Q, E>(&self, translatefpkh: &mut Fpkh) -> Result<Policy<Q>, E>
where
Fpkh: FnMut(&Pk::Hash) -> Result<Q::Hash, E>,
Q: MiniscriptKey,
Expand All @@ -98,7 +125,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
Policy::Threshold(k, ref subs) => {
let new_subs: Result<Vec<Policy<Q>>, _> = subs
.iter()
.map(|sub| sub.translate_pkh(&mut translatefpkh))
.map(|sub| sub._translate_pkh(translatefpkh))
.collect();
new_subs.map(|ok| Policy::Threshold(k, ok))
}
Expand Down

0 comments on commit ef1d69c

Please sign in to comment.