Switch to "mainline" rust-miniscript

This commit is contained in:
Alekos Filini
2020-11-16 22:07:38 +01:00
parent 35579cb216
commit 7a42c5e095
12 changed files with 332 additions and 178 deletions

View File

@@ -39,9 +39,10 @@ macro_rules! impl_top_level_pk {
( $descriptor_variant:ident, $ctx:ty, $key:expr ) => {{
#[allow(unused_imports)]
use $crate::keys::{DescriptorKey, ToDescriptorKey};
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
$key.to_descriptor_key()
.and_then(|key: DescriptorKey<$ctx>| key.extract())
.and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
.map(|(pk, key_map, valid_networks)| {
(
$crate::miniscript::Descriptor::<
@@ -314,7 +315,8 @@ macro_rules! fragment {
$crate::impl_leaf_opcode!(False)
});
( pk_k $key:expr ) => ({
$crate::keys::make_pk($key)
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
$crate::keys::make_pk($key, &secp)
});
( pk $key:expr ) => ({
$crate::fragment!(+c pk_k $key)
@@ -391,6 +393,7 @@ macro_rules! fragment {
});
( multi $thresh:expr $(, $key:expr )+ ) => ({
use $crate::keys::ToDescriptorKey;
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
let mut keys = vec![];
$(
@@ -398,7 +401,7 @@ macro_rules! fragment {
)*
keys.into_iter().collect::<Result<Vec<_>, _>>()
.and_then(|keys| $crate::keys::make_multi($thresh, keys))
.and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
});
}
@@ -406,7 +409,8 @@ macro_rules! fragment {
#[cfg(test)]
mod test {
use bitcoin::hashes::hex::ToHex;
use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
use bitcoin::secp256k1::Secp256k1;
use miniscript::descriptor::{DescriptorPublicKey, DescriptorPublicKeyCtx, KeyMap};
use miniscript::{Descriptor, Legacy, Segwitv0};
use std::str::FromStr;
@@ -426,6 +430,9 @@ mod test {
is_fixed: bool,
expected: &[&str],
) {
let secp = Secp256k1::new();
let deriv_ctx = DescriptorPublicKeyCtx::new(&secp, ChildNumber::Normal { index: 0 });
let (desc, _key_map, _networks) = desc.unwrap();
assert_eq!(desc.is_witness(), is_witness);
assert_eq!(desc.is_fixed(), is_fixed);
@@ -436,11 +443,11 @@ mod test {
} else {
desc.derive(ChildNumber::from_normal_idx(index).unwrap())
};
let address = child_desc.address(Regtest);
let address = child_desc.address(Regtest, deriv_ctx);
if address.is_some() {
assert_eq!(address.unwrap().to_string(), *expected.get(i).unwrap());
} else {
let script = child_desc.script_pubkey();
let script = child_desc.script_pubkey(deriv_ctx);
assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap());
}
}
@@ -649,6 +656,8 @@ mod test {
// - verify the key_maps are correctly merged together
#[test]
fn test_key_maps_merged() {
let secp = Secp256k1::new();
let xprv1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
let path1 = bip32::DerivationPath::from_str("m/0").unwrap();
let desc_key1 = (xprv1, path1.clone()).to_descriptor_key().unwrap();
@@ -672,9 +681,9 @@ mod test {
let desc_key3: DescriptorKey<Segwitv0> =
(xprv3, path3.clone()).to_descriptor_key().unwrap();
let (key1, _key_map, _valid_networks) = desc_key1.extract().unwrap();
let (key2, _key_map, _valid_networks) = desc_key2.extract().unwrap();
let (key3, _key_map, _valid_networks) = desc_key3.extract().unwrap();
let (key1, _key_map, _valid_networks) = desc_key1.extract(&secp).unwrap();
let (key2, _key_map, _valid_networks) = desc_key2.extract(&secp).unwrap();
let (key3, _key_map, _valid_networks) = desc_key3.extract(&secp).unwrap();
assert_eq!(key_map.get(&key1).unwrap().to_string(), "tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/0/*");
assert_eq!(key_map.get(&key2).unwrap().to_string(), "tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF/2147483647'/0/*");
assert_eq!(key_map.get(&key3).unwrap().to_string(), "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf/10/20/30/40/*");

View File

@@ -53,6 +53,7 @@ use self::error::Error;
pub use self::policy::Policy;
use crate::keys::{KeyError, ToDescriptorKey, ValidNetworks};
use crate::wallet::signer::SignersContainer;
use crate::wallet::utils::{descriptor_to_pk_ctx, SecpCtx};
/// Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`]
pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
@@ -92,7 +93,7 @@ impl ToWalletDescriptor for &str {
self
};
ExtendedDescriptor::parse_secret(descriptor)?.to_wallet_descriptor(network)
ExtendedDescriptor::parse_descriptor(descriptor)?.to_wallet_descriptor(network)
}
}
@@ -121,15 +122,17 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
use crate::keys::DescriptorKey;
let secp = Secp256k1::new();
let check_key = |pk: &DescriptorPublicKey| {
let (pk, _, networks) = if self.0.is_witness() {
let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
pk.clone().to_descriptor_key()?;
desciptor_key.extract()?
desciptor_key.extract(&secp)?
} else {
let desciptor_key: DescriptorKey<miniscript::Legacy> =
pk.clone().to_descriptor_key()?;
desciptor_key.extract()?
desciptor_key.extract(&secp)?
};
if networks.contains(&network) {
@@ -185,12 +188,16 @@ impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap, ValidNetworks) {
/// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]
pub trait ExtractPolicy {
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error>;
fn extract_policy(
&self,
signers: Arc<SignersContainer>,
secp: &SecpCtx,
) -> Result<Option<Policy>, Error>;
}
pub(crate) trait XKeyUtils {
fn full_path(&self, append: &[ChildNumber]) -> DerivationPath;
fn root_fingerprint(&self) -> Fingerprint;
fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
}
impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
@@ -215,46 +222,55 @@ impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
}
}
fn root_fingerprint(&self) -> Fingerprint {
fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
match self.origin {
Some((fingerprint, _)) => fingerprint,
None => self.xkey.xkey_fingerprint(),
None => self.xkey.xkey_fingerprint(secp),
}
}
}
pub(crate) trait DescriptorMeta: Sized {
fn is_witness(&self) -> bool;
fn get_hd_keypaths(&self, index: u32) -> Result<HDKeyPaths, Error>;
fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error>;
fn is_fixed(&self) -> bool;
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths) -> Option<Self>;
fn derive_from_psbt_input(&self, psbt_input: &psbt::Input, utxo: Option<TxOut>)
-> Option<Self>;
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self>;
fn derive_from_psbt_input(
&self,
psbt_input: &psbt::Input,
utxo: Option<TxOut>,
secp: &SecpCtx,
) -> Option<Self>;
}
pub(crate) trait DescriptorScripts {
fn psbt_redeem_script(&self) -> Option<Script>;
fn psbt_witness_script(&self) -> Option<Script>;
fn psbt_redeem_script(&self, secp: &SecpCtx) -> Option<Script>;
fn psbt_witness_script(&self, secp: &SecpCtx) -> Option<Script>;
}
impl<T> DescriptorScripts for Descriptor<T>
where
T: miniscript::MiniscriptKey + miniscript::ToPublicKey,
{
fn psbt_redeem_script(&self) -> Option<Script> {
impl DescriptorScripts for Descriptor<DescriptorPublicKey> {
fn psbt_redeem_script(&self, secp: &SecpCtx) -> Option<Script> {
let deriv_ctx = descriptor_to_pk_ctx(secp);
match self {
Descriptor::ShWpkh(_) => Some(self.witness_script()),
Descriptor::ShWsh(ref script) => Some(script.encode().to_v0_p2wsh()),
Descriptor::Sh(ref script) => Some(script.encode()),
Descriptor::Bare(ref script) => Some(script.encode()),
Descriptor::ShWpkh(_) => Some(self.witness_script(deriv_ctx)),
Descriptor::ShWsh(ref script) => Some(script.encode(deriv_ctx).to_v0_p2wsh()),
Descriptor::Sh(ref script) => Some(script.encode(deriv_ctx)),
Descriptor::Bare(ref script) => Some(script.encode(deriv_ctx)),
Descriptor::ShSortedMulti(ref keys) => Some(keys.encode(deriv_ctx)),
_ => None,
}
}
fn psbt_witness_script(&self) -> Option<Script> {
fn psbt_witness_script(&self, secp: &SecpCtx) -> Option<Script> {
let deriv_ctx = descriptor_to_pk_ctx(secp);
match self {
Descriptor::Wsh(ref script) => Some(script.encode()),
Descriptor::ShWsh(ref script) => Some(script.encode()),
Descriptor::Wsh(ref script) => Some(script.encode(deriv_ctx)),
Descriptor::ShWsh(ref script) => Some(script.encode(deriv_ctx)),
Descriptor::WshSortedMulti(ref keys) | Descriptor::ShWshSortedMulti(ref keys) => {
Some(keys.encode(deriv_ctx))
}
_ => None,
}
}
@@ -263,22 +279,25 @@ where
impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
fn is_witness(&self) -> bool {
match self {
Descriptor::Bare(_) | Descriptor::Pk(_) | Descriptor::Pkh(_) | Descriptor::Sh(_) => {
false
}
Descriptor::Bare(_)
| Descriptor::Pk(_)
| Descriptor::Pkh(_)
| Descriptor::Sh(_)
| Descriptor::ShSortedMulti(_) => false,
Descriptor::Wpkh(_)
| Descriptor::ShWpkh(_)
| Descriptor::Wsh(_)
| Descriptor::ShWsh(_) => true,
| Descriptor::ShWsh(_)
| Descriptor::ShWshSortedMulti(_)
| Descriptor::WshSortedMulti(_) => true,
}
}
fn get_hd_keypaths(&self, index: u32) -> Result<HDKeyPaths, Error> {
fn translate_key(
key: &DescriptorPublicKey,
index: u32,
paths: &mut HDKeyPaths,
) -> Result<DummyKey, Error> {
fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error> {
let translate_key = |key: &DescriptorPublicKey,
index: u32,
paths: &mut HDKeyPaths|
-> Result<DummyKey, Error> {
match key {
DescriptorPublicKey::SinglePub(_) => {}
DescriptorPublicKey::XPub(xpub) => {
@@ -298,7 +317,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
paths.insert(
derived_pubkey.public_key,
(
xpub.root_fingerprint(),
xpub.root_fingerprint(secp),
xpub.full_path(&[ChildNumber::from_normal_idx(index)?]),
),
);
@@ -306,7 +325,7 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
}
Ok(DummyKey::default())
}
};
let mut answer_pk = BTreeMap::new();
let mut answer_pkh = BTreeMap::new();
@@ -347,12 +366,11 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
!found_wildcard_pk && !found_wildcard_pkh
}
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths) -> Option<Self> {
fn try_key(
key: &DescriptorPublicKey,
index: &HashMap<Fingerprint, DerivationPath>,
found_path: &mut Option<ChildNumber>,
) -> Result<DummyKey, Error> {
fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self> {
let try_key = |key: &DescriptorPublicKey,
index: &HashMap<Fingerprint, DerivationPath>,
found_path: &mut Option<ChildNumber>|
-> Result<DummyKey, Error> {
if found_path.is_some() {
// already found a matching path, we are done
return Ok(DummyKey::default());
@@ -363,13 +381,15 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
// return the "prefix" that matched, so we remove that prefix from the full path
// found in `index` and save it in `derive_path`. We expect this to be a derivation
// path of length 1 if the key `is_wildcard` and an empty path otherwise.
let root_fingerprint = xpub.root_fingerprint();
let root_fingerprint = xpub.root_fingerprint(secp);
let derivation_path: Option<Vec<ChildNumber>> = index
.get_key_value(&root_fingerprint)
.and_then(|(fingerprint, path)| xpub.matches(*fingerprint, path))
.and_then(|(fingerprint, path)| {
xpub.matches(&(*fingerprint, path.clone()), secp)
})
.map(|prefix| {
index
.get(&xpub.root_fingerprint())
.get(&xpub.root_fingerprint(secp))
.unwrap()
.into_iter()
.skip(prefix.into_iter().count())
@@ -422,8 +442,9 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
&self,
psbt_input: &psbt::Input,
utxo: Option<TxOut>,
secp: &SecpCtx,
) -> Option<Self> {
if let Some(derived) = self.derive_from_hd_keypaths(&psbt_input.hd_keypaths) {
if let Some(derived) = self.derive_from_hd_keypaths(&psbt_input.hd_keypaths, secp) {
return Some(derived);
} else if !self.is_fixed() {
// If the descriptor is not fixed we can't brute-force the derivation address, so just
@@ -431,25 +452,38 @@ impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
return None;
}
let deriv_ctx = descriptor_to_pk_ctx(secp);
match self {
Descriptor::Pk(_)
| Descriptor::Pkh(_)
| Descriptor::Wpkh(_)
| Descriptor::ShWpkh(_)
if utxo.is_some()
&& self.script_pubkey() == utxo.as_ref().unwrap().script_pubkey =>
&& self.script_pubkey(deriv_ctx) == utxo.as_ref().unwrap().script_pubkey =>
{
Some(self.clone())
}
Descriptor::Bare(ms) | Descriptor::Sh(ms)
if psbt_input.redeem_script.is_some()
&& &ms.encode() == psbt_input.redeem_script.as_ref().unwrap() =>
&& &ms.encode(deriv_ctx) == psbt_input.redeem_script.as_ref().unwrap() =>
{
Some(self.clone())
}
Descriptor::Wsh(ms) | Descriptor::ShWsh(ms)
if psbt_input.witness_script.is_some()
&& &ms.encode() == psbt_input.witness_script.as_ref().unwrap() =>
&& &ms.encode(deriv_ctx) == psbt_input.witness_script.as_ref().unwrap() =>
{
Some(self.clone())
}
Descriptor::ShSortedMulti(keys)
if psbt_input.redeem_script.is_some()
&& &keys.encode(deriv_ctx) == psbt_input.redeem_script.as_ref().unwrap() =>
{
Some(self.clone())
}
Descriptor::WshSortedMulti(keys) | Descriptor::ShWshSortedMulti(keys)
if psbt_input.witness_script.is_some()
&& &keys.encode(deriv_ctx) == psbt_input.witness_script.as_ref().unwrap() =>
{
Some(self.clone())
}
@@ -489,6 +523,7 @@ mod test {
use bitcoin::consensus::encode::deserialize;
use bitcoin::hashes::hex::FromHex;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::util::{bip32, psbt};
use super::*;
@@ -513,7 +548,7 @@ mod test {
.unwrap();
assert!(descriptor
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0))
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
.is_some());
}
@@ -544,7 +579,7 @@ mod test {
.unwrap();
assert!(descriptor
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0))
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
.is_some());
}
@@ -568,7 +603,7 @@ mod test {
.unwrap();
assert!(descriptor
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0))
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
.is_some());
}
@@ -598,7 +633,7 @@ mod test {
.unwrap();
assert!(descriptor
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0))
.derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
.is_some());
}

View File

@@ -32,13 +32,15 @@
//! ```
//! # use std::sync::Arc;
//! # use bdk::descriptor::*;
//! # use bdk::bitcoin::secp256k1::Secp256k1;
//! let secp = Secp256k1::new();
//! let desc = "wsh(and_v(v:pk(cV3oCth6zxZ1UVsHLnGothsWNsaoxRhC6aeNi5VbSdFpwUkgkEci),or_d(pk(cVMTy7uebJgvFaSBwcgvwk8qn8xSLc97dKow4MBetjrrahZoimm2),older(12960))))";
//!
//! let (extended_desc, key_map) = ExtendedDescriptor::parse_secret(desc)?;
//! let (extended_desc, key_map) = ExtendedDescriptor::parse_descriptor(desc)?;
//! println!("{:?}", extended_desc);
//!
//! let signers = Arc::new(key_map.into());
//! let policy = extended_desc.extract_policy(signers)?;
//! let policy = extended_desc.extract_policy(signers, &secp)?;
//! println!("policy: {}", serde_json::to_string(&policy)?);
//! # Ok::<(), bdk::Error>(())
//! ```
@@ -55,7 +57,7 @@ use bitcoin::hashes::*;
use bitcoin::util::bip32::Fingerprint;
use bitcoin::PublicKey;
use miniscript::descriptor::DescriptorPublicKey;
use miniscript::descriptor::{DescriptorPublicKey, SortedMultiVec};
use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal, ToPublicKey};
#[allow(unused_imports)]
@@ -63,6 +65,7 @@ use log::{debug, error, info, trace};
use crate::descriptor::ExtractPolicy;
use crate::wallet::signer::{SignerId, SignersContainer};
use crate::wallet::utils::{descriptor_to_pk_ctx, SecpCtx};
use super::checksum::get_checksum;
use super::error::Error;
@@ -80,14 +83,14 @@ pub struct PKOrF {
}
impl PKOrF {
fn from_key(k: &DescriptorPublicKey) -> Self {
fn from_key(k: &DescriptorPublicKey, secp: &SecpCtx) -> Self {
match k {
DescriptorPublicKey::SinglePub(pubkey) => PKOrF {
pubkey: Some(pubkey.key),
..Default::default()
},
DescriptorPublicKey::XPub(xpub) => PKOrF {
fingerprint: Some(xpub.root_fingerprint()),
fingerprint: Some(xpub.root_fingerprint(secp)),
..Default::default()
},
}
@@ -241,6 +244,9 @@ pub enum Satisfaction {
m: usize,
/// The items that can be satisfied by the descriptor
items: Vec<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
/// Whether the items are sorted in lexicographic order (used by `sortedmulti`)
sorted: Option<bool>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
/// Extra conditions that also need to be satisfied
conditions: ConditionMap,
@@ -253,6 +259,9 @@ pub enum Satisfaction {
m: usize,
/// The items that can be satisfied by the descriptor
items: Vec<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
/// Whether the items are sorted in lexicographic order (used by `sortedmulti`)
sorted: Option<bool>,
#[serde(
serialize_with = "serialize_folded_cond_map",
skip_serializing_if = "BTreeMap::is_empty"
@@ -324,6 +333,7 @@ impl Satisfaction {
m,
items,
conditions,
sorted,
} = self
{
if items.len() >= *m {
@@ -378,6 +388,7 @@ impl Satisfaction {
m: *m,
items: items.clone(),
conditions: map,
sorted: *sorted,
};
}
}
@@ -510,6 +521,7 @@ impl Policy {
m: threshold,
items: vec![],
conditions: Default::default(),
sorted: None,
};
for (index, item) in items.iter().enumerate() {
contribution.add(&item.contribution, index)?;
@@ -526,21 +538,24 @@ impl Policy {
keys: &[DescriptorPublicKey],
signers: Arc<SignersContainer>,
threshold: usize,
sorted: bool,
secp: &SecpCtx,
) -> Result<Option<Policy>, PolicyError> {
if threshold == 0 {
return Ok(None);
}
let parsed_keys = keys.iter().map(|k| PKOrF::from_key(k)).collect();
let parsed_keys = keys.iter().map(|k| PKOrF::from_key(k, secp)).collect();
let mut contribution = Satisfaction::Partial {
n: keys.len(),
m: threshold,
items: vec![],
conditions: Default::default(),
sorted: Some(sorted),
};
for (index, key) in keys.iter().enumerate() {
if signers.find(signer_id(key)).is_some() {
if signers.find(signer_id(key, secp)).is_some() {
contribution.add(
&Satisfaction::Complete {
condition: Default::default(),
@@ -648,17 +663,17 @@ impl From<SatisfiableItem> for Policy {
}
}
fn signer_id(key: &DescriptorPublicKey) -> SignerId {
fn signer_id(key: &DescriptorPublicKey, secp: &SecpCtx) -> SignerId {
match key {
DescriptorPublicKey::SinglePub(pubkey) => pubkey.key.to_pubkeyhash().into(),
DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint().into(),
DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint(secp).into(),
}
}
fn signature(key: &DescriptorPublicKey, signers: Arc<SignersContainer>) -> Policy {
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key)).into();
fn signature(key: &DescriptorPublicKey, signers: Arc<SignersContainer>, secp: &SecpCtx) -> Policy {
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key, secp)).into();
policy.contribution = if signers.find(signer_id(key)).is_some() {
policy.contribution = if signers.find(signer_id(key, secp)).is_some() {
Satisfaction::Complete {
condition: Default::default(),
}
@@ -672,8 +687,10 @@ fn signature(key: &DescriptorPublicKey, signers: Arc<SignersContainer>) -> Polic
fn signature_key(
key: &<DescriptorPublicKey as MiniscriptKey>::Hash,
signers: Arc<SignersContainer>,
secp: &SecpCtx,
) -> Policy {
let key_hash = key.to_public_key().to_pubkeyhash();
let deriv_ctx = descriptor_to_pk_ctx(secp);
let key_hash = key.to_public_key(deriv_ctx).to_pubkeyhash();
let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key_hash(key_hash)).into();
if signers.find(SignerId::PkHash(key_hash)).is_some() {
@@ -686,12 +703,18 @@ fn signature_key(
}
impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> {
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
fn extract_policy(
&self,
signers: Arc<SignersContainer>,
secp: &SecpCtx,
) -> Result<Option<Policy>, Error> {
Ok(match &self.node {
// Leaves
Terminal::True | Terminal::False => None,
Terminal::PkK(pubkey) => Some(signature(pubkey, Arc::clone(&signers))),
Terminal::PkH(pubkey_hash) => Some(signature_key(pubkey_hash, Arc::clone(&signers))),
Terminal::PkK(pubkey) => Some(signature(pubkey, Arc::clone(&signers), secp)),
Terminal::PkH(pubkey_hash) => {
Some(signature_key(pubkey_hash, Arc::clone(&signers), secp))
}
Terminal::After(value) => {
let mut policy: Policy = SatisfiableItem::AbsoluteTimelock { value: *value }.into();
policy.contribution = Satisfaction::Complete {
@@ -724,7 +747,9 @@ impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>
Terminal::Hash160(hash) => {
Some(SatisfiableItem::HASH160Preimage { hash: *hash }.into())
}
Terminal::Multi(k, pks) => Policy::make_multisig(pks, Arc::clone(&signers), *k)?,
Terminal::Multi(k, pks) => {
Policy::make_multisig(pks, Arc::clone(&signers), *k, false, secp)?
}
// Identities
Terminal::Alt(inner)
| Terminal::Swap(inner)
@@ -732,31 +757,31 @@ impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>
| Terminal::DupIf(inner)
| Terminal::Verify(inner)
| Terminal::NonZero(inner)
| Terminal::ZeroNotEqual(inner) => inner.extract_policy(Arc::clone(&signers))?,
| Terminal::ZeroNotEqual(inner) => inner.extract_policy(Arc::clone(&signers), secp)?,
// Complex policies
Terminal::AndV(a, b) | Terminal::AndB(a, b) => Policy::make_and(
a.extract_policy(Arc::clone(&signers))?,
b.extract_policy(Arc::clone(&signers))?,
a.extract_policy(Arc::clone(&signers), secp)?,
b.extract_policy(Arc::clone(&signers), secp)?,
)?,
Terminal::AndOr(x, y, z) => Policy::make_or(
Policy::make_and(
x.extract_policy(Arc::clone(&signers))?,
y.extract_policy(Arc::clone(&signers))?,
x.extract_policy(Arc::clone(&signers), secp)?,
y.extract_policy(Arc::clone(&signers), secp)?,
)?,
z.extract_policy(Arc::clone(&signers))?,
z.extract_policy(Arc::clone(&signers), secp)?,
)?,
Terminal::OrB(a, b)
| Terminal::OrD(a, b)
| Terminal::OrC(a, b)
| Terminal::OrI(a, b) => Policy::make_or(
a.extract_policy(Arc::clone(&signers))?,
b.extract_policy(Arc::clone(&signers))?,
a.extract_policy(Arc::clone(&signers), secp)?,
b.extract_policy(Arc::clone(&signers), secp)?,
)?,
Terminal::Thresh(k, nodes) => {
let mut threshold = *k;
let mapped: Vec<_> = nodes
.iter()
.map(|n| n.extract_policy(Arc::clone(&signers)))
.map(|n| n.extract_policy(Arc::clone(&signers), secp))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.filter_map(|x| x)
@@ -776,14 +801,42 @@ impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>
}
impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
fn extract_policy(&self, signers: Arc<SignersContainer>) -> Result<Option<Policy>, Error> {
fn extract_policy(
&self,
signers: Arc<SignersContainer>,
secp: &SecpCtx,
) -> Result<Option<Policy>, Error> {
fn make_sortedmulti<Ctx: ScriptContext>(
keys: &SortedMultiVec<DescriptorPublicKey, Ctx>,
signers: Arc<SignersContainer>,
secp: &SecpCtx,
) -> Result<Option<Policy>, Error> {
Ok(Policy::make_multisig(
keys.pks.as_ref(),
signers,
keys.k,
true,
secp,
)?)
}
match self {
Descriptor::Pk(pubkey)
| Descriptor::Pkh(pubkey)
| Descriptor::Wpkh(pubkey)
| Descriptor::ShWpkh(pubkey) => Ok(Some(signature(pubkey, signers))),
Descriptor::Bare(inner) | Descriptor::Sh(inner) => Ok(inner.extract_policy(signers)?),
Descriptor::Wsh(inner) | Descriptor::ShWsh(inner) => Ok(inner.extract_policy(signers)?),
| Descriptor::ShWpkh(pubkey) => Ok(Some(signature(pubkey, signers, secp))),
Descriptor::Bare(inner) | Descriptor::Sh(inner) => {
Ok(inner.extract_policy(signers, secp)?)
}
Descriptor::Wsh(inner) | Descriptor::ShWsh(inner) => {
Ok(inner.extract_policy(signers, secp)?)
}
// `sortedmulti()` is handled separately
Descriptor::ShSortedMulti(keys) => make_sortedmulti(&keys, signers, secp),
Descriptor::ShWshSortedMulti(keys) | Descriptor::WshSortedMulti(keys) => {
make_sortedmulti(&keys, signers, secp)
}
}
}
}
@@ -833,7 +886,7 @@ mod test {
let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = wallet_desc
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -846,7 +899,7 @@ mod test {
let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = wallet_desc
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -926,7 +979,7 @@ mod test {
let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = wallet_desc
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -936,7 +989,7 @@ mod test {
&& &keys[1].fingerprint.unwrap() == &fingerprint1)
);
assert!(
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions} if n == &2
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
&& m == &1
&& items.len() == 2
&& conditions.contains_key(&vec![0])
@@ -954,7 +1007,7 @@ mod test {
let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = wallet_desc
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -965,7 +1018,7 @@ mod test {
);
assert!(
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions} if n == &2
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
&& m == &2
&& items.len() == 2
&& conditions.contains_key(&vec![0,1])
@@ -983,7 +1036,7 @@ mod test {
let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = single_key
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -997,7 +1050,7 @@ mod test {
let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = single_key
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -1019,7 +1072,7 @@ mod test {
let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = single_key
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -1029,7 +1082,7 @@ mod test {
&& &keys[1].fingerprint.unwrap() == &fingerprint1)
);
assert!(
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions } if n == &2
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
&& m == &1
&& items.len() == 2
&& conditions.contains_key(&vec![0])
@@ -1053,7 +1106,7 @@ mod test {
let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
let signers_container = Arc::new(SignersContainer::from(keymap));
let policy = wallet_desc
.extract_policy(signers_container)
.extract_policy(signers_container, &Secp256k1::new())
.unwrap()
.unwrap();
@@ -1062,7 +1115,7 @@ mod test {
);
assert!(
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions } if n == &3
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &3
&& m == &2
&& items.len() == 3
&& conditions.get(&vec![0,1]).unwrap().iter().next().unwrap().csv.is_none()

View File

@@ -432,8 +432,9 @@ mod test {
use crate::keys::{KeyError, ValidNetworks};
use bitcoin::hashes::core::str::FromStr;
use bitcoin::network::constants::Network::Regtest;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::util::bip32::ChildNumber;
use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
use miniscript::descriptor::{DescriptorPublicKey, DescriptorPublicKeyCtx, KeyMap};
use miniscript::Descriptor;
// verify template descriptor generates expected address(es)
@@ -443,6 +444,10 @@ mod test {
is_fixed: bool,
expected: &[&str],
) {
let secp = Secp256k1::new();
let deriv_ctx =
DescriptorPublicKeyCtx::new(&secp, ChildNumber::from_normal_idx(0).unwrap());
let (desc, _key_map, _networks) = desc.unwrap();
assert_eq!(desc.is_witness(), is_witness);
assert_eq!(desc.is_fixed(), is_fixed);
@@ -453,7 +458,7 @@ mod test {
} else {
desc.derive(ChildNumber::from_normal_idx(index).unwrap())
};
let address = child_desc.address(Regtest).unwrap();
let address = child_desc.address(Regtest, deriv_ctx).unwrap();
assert_eq!(address.to_string(), *expected.get(i).unwrap());
}
}