use miniscript::{
Legacy, Miniscript, MiniscriptKey, ScriptContext, Segwitv0, Threshold,
descriptor::{Descriptor, Sh, ShInner, SortedMultiVec, Tr, Wsh, WshInner},
miniscript::decode::Terminal,
};
type DescriptorTreeThreshold<Pk> = Threshold<DescriptorTree<Pk>, 0>;
type KeylessDescriptorTreeThreshold<Pk> = Threshold<KeylessDescriptorTree<Pk>, 0>;
#[derive(Clone, Debug)]
pub enum DescriptorTree<Pk: MiniscriptKey> {
Keyless(bool),
Key(Pk),
Threshold(DescriptorTreeThreshold<Pk>),
}
#[derive(Clone, Debug)]
pub enum KeylessDescriptorTree<Pk: MiniscriptKey> {
Key(Pk),
Threshold(KeylessDescriptorTreeThreshold<Pk>),
}
pub trait ToDescriptorTree<Pk: MiniscriptKey> {
fn to_tree(&self) -> DescriptorTree<Pk>;
}
impl<Pk: MiniscriptKey> KeylessDescriptorTree<Pk> {
pub fn extract_keys(&self) -> Vec<Pk> {
match self {
KeylessDescriptorTree::Key(pk) => vec![pk.clone()],
KeylessDescriptorTree::Threshold(thresh) => {
thresh.iter().flat_map(|tree| tree.extract_keys()).collect()
}
}
}
}
impl<Pk: MiniscriptKey> DescriptorTree<Pk> {
pub fn extract_keys(&self) -> Vec<Pk> {
match self {
DescriptorTree::Keyless(_) => Vec::new(),
DescriptorTree::Key(pk) => vec![pk.clone()],
DescriptorTree::Threshold(thresh) => {
thresh.iter().flat_map(|tree| tree.extract_keys()).collect()
}
}
}
pub fn prune_keyless(&self) -> Option<KeylessDescriptorTree<Pk>> {
let (_, pruned_tree) = self.prune_keyless_with_satisfiability();
pruned_tree
}
fn prune_keyless_with_satisfiability(&self) -> (bool, Option<KeylessDescriptorTree<Pk>>) {
match self {
DescriptorTree::Keyless(satisfiable) => (*satisfiable, None),
DescriptorTree::Key(pk) => (true, Some(KeylessDescriptorTree::Key(pk.clone()))),
DescriptorTree::Threshold(thresh) => {
let mut assume_satisfied = 0;
let mut keyed_subtrees = Vec::new();
for t in thresh.iter() {
match t.prune_keyless_with_satisfiability() {
(_, Some(subtree)) => {
keyed_subtrees.push(subtree);
}
(true, None) => assume_satisfied += 1,
(false, None) => {}
}
}
let new_k = if thresh.k() > assume_satisfied {
thresh.k() - assume_satisfied
} else {
0
};
match (new_k, keyed_subtrees.len()) {
(0, _) => (true, None),
(1, 1) => (true, Some(keyed_subtrees.first().unwrap().clone())),
(k, n) => {
if k <= n {
(
true,
KeylessDescriptorTreeThreshold::new(new_k, keyed_subtrees)
.ok()
.map(KeylessDescriptorTree::Threshold),
)
} else {
(false, None)
}
}
}
}
}
}
fn from_ms_and<Ctx>(ms0: &Miniscript<Pk, Ctx>, ms1: &Miniscript<Pk, Ctx>) -> Self
where
Ctx: ScriptContext,
{
let tree0 = ms0.to_tree();
let tree1 = ms1.to_tree();
let thresh = DescriptorTreeThreshold::and(tree0, tree1);
DescriptorTree::Threshold(thresh)
}
fn from_ms_or<Ctx>(ms0: &Miniscript<Pk, Ctx>, ms1: &Miniscript<Pk, Ctx>) -> Self
where
Ctx: ScriptContext,
{
let tree0 = ms0.to_tree();
let tree1 = ms1.to_tree();
let thresh = DescriptorTreeThreshold::or(tree0, tree1);
DescriptorTree::Threshold(thresh)
}
fn from_sortedmulti<Ctx>(sortedmulti: &SortedMultiVec<Pk, Ctx>) -> Self
where
Ctx: ScriptContext,
{
let trees = sortedmulti
.pks()
.iter()
.map(|pk| DescriptorTree::Key(pk.clone()))
.collect();
let thresh = DescriptorTreeThreshold::new(sortedmulti.k(), trees).unwrap();
DescriptorTree::Threshold(thresh)
}
}
impl<Pk: MiniscriptKey> ToDescriptorTree<Pk> for Descriptor<Pk> {
fn to_tree(&self) -> DescriptorTree<Pk> {
match self {
Descriptor::Sh(sh) => sh.to_tree(),
Descriptor::Wsh(wsh) => wsh.to_tree(),
Descriptor::Tr(tr) => tr.to_tree(),
Descriptor::Wpkh(wpkh) => DescriptorTree::Key(wpkh.clone().into_inner()),
Descriptor::Pkh(pkh) => DescriptorTree::Key(pkh.clone().into_inner()),
Descriptor::Bare(bare) => bare.as_inner().to_tree(),
}
}
}
impl<Pk: MiniscriptKey> ToDescriptorTree<Pk> for Sh<Pk> {
fn to_tree(&self) -> DescriptorTree<Pk> {
match self.as_inner() {
ShInner::SortedMulti(sortedmulti) => {
DescriptorTree::from_sortedmulti::<Legacy>(sortedmulti)
}
ShInner::Wsh(wsh) => wsh.to_tree(),
ShInner::Wpkh(wpkh) => DescriptorTree::Key(wpkh.clone().into_inner()),
ShInner::Ms(ms) => ms.to_tree(),
}
}
}
impl<Pk: MiniscriptKey> ToDescriptorTree<Pk> for Wsh<Pk> {
fn to_tree(&self) -> DescriptorTree<Pk> {
match self.as_inner() {
WshInner::SortedMulti(sortedmulti) => {
DescriptorTree::from_sortedmulti::<Segwitv0>(sortedmulti)
}
WshInner::Ms(ms) => ms.to_tree(),
}
}
}
impl<Pk: MiniscriptKey> ToDescriptorTree<Pk> for Tr<Pk> {
fn to_tree(&self) -> DescriptorTree<Pk> {
let mut trees = Vec::new();
trees.push(DescriptorTree::Key(self.internal_key().clone()));
for (_, ms) in self.iter_scripts() {
trees.push(ms.to_tree());
}
let thresh = DescriptorTreeThreshold::or_n(trees);
DescriptorTree::Threshold(thresh)
}
}
impl<Pk: MiniscriptKey, Ctx: ScriptContext> ToDescriptorTree<Pk> for Miniscript<Pk, Ctx> {
fn to_tree(&self) -> DescriptorTree<Pk> {
match &self.node {
Terminal::True => DescriptorTree::Keyless(true),
Terminal::False => DescriptorTree::Keyless(false),
Terminal::PkK(pk) => DescriptorTree::Key(pk.clone()),
Terminal::PkH(pk) => DescriptorTree::Key(pk.clone()),
Terminal::RawPkH(_) => DescriptorTree::Keyless(true),
Terminal::After(_) => DescriptorTree::Keyless(true),
Terminal::Older(_) => DescriptorTree::Keyless(true),
Terminal::Sha256(_) => DescriptorTree::Keyless(true),
Terminal::Hash256(_) => DescriptorTree::Keyless(true),
Terminal::Ripemd160(_) => DescriptorTree::Keyless(true),
Terminal::Hash160(_) => DescriptorTree::Keyless(true),
Terminal::Alt(ms) => ms.to_tree(),
Terminal::Swap(ms) => ms.to_tree(),
Terminal::Check(ms) => ms.to_tree(),
Terminal::DupIf(ms) => ms.to_tree(),
Terminal::Verify(ms) => ms.to_tree(),
Terminal::NonZero(ms) => ms.to_tree(),
Terminal::ZeroNotEqual(ms) => ms.to_tree(),
Terminal::AndV(ms0, ms1) => DescriptorTree::from_ms_and(ms0, ms1),
Terminal::AndB(ms0, ms1) => DescriptorTree::from_ms_and(ms0, ms1),
Terminal::AndOr(ms0, ms1, ms2) => {
let and_tree = DescriptorTree::from_ms_and(ms0, ms1);
let or_tree = ms2.to_tree();
let thresh = DescriptorTreeThreshold::or(and_tree, or_tree);
DescriptorTree::Threshold(thresh)
}
Terminal::OrB(ms0, ms1) => DescriptorTree::from_ms_or(ms0, ms1),
Terminal::OrC(ms0, ms1) => DescriptorTree::from_ms_or(ms0, ms1),
Terminal::OrD(ms0, ms1) => DescriptorTree::from_ms_or(ms0, ms1),
Terminal::OrI(ms0, ms1) => DescriptorTree::from_ms_or(ms0, ms1),
Terminal::Thresh(thresh) => {
let mut trees = Vec::new();
for ms in thresh.iter() {
let tree = ms.to_tree();
trees.push(tree);
}
let thresh = DescriptorTreeThreshold::new(thresh.k(), trees).unwrap();
DescriptorTree::Threshold(thresh)
}
Terminal::Multi(thresh) => {
let trees = thresh
.iter()
.map(|pk| DescriptorTree::Key(pk.clone()))
.collect();
let thresh = DescriptorTreeThreshold::new(thresh.k(), trees).unwrap();
DescriptorTree::Threshold(thresh)
}
Terminal::MultiA(thresh) => {
let trees = thresh
.iter()
.map(|pk| DescriptorTree::Key(pk.clone()))
.collect();
let thresh = DescriptorTreeThreshold::new(thresh.k(), trees).unwrap();
DescriptorTree::Threshold(thresh)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use bitcoin::secp256k1;
use miniscript::descriptor::DescriptorPublicKey;
use std::str::FromStr;
fn create_test_key(index: u32) -> DescriptorPublicKey {
let secp = secp256k1::Secp256k1::new();
let secret_value = 1u32 + index;
let mut sk = [0u8; 32];
sk[28..32].copy_from_slice(&secret_value.to_be_bytes());
let pubkey = bitcoin::PublicKey {
inner: secp256k1::PublicKey::from_secret_key(
&secp,
&secp256k1::SecretKey::from_slice(&sk).expect("sk"),
),
compressed: true,
};
DescriptorPublicKey::Single(miniscript::descriptor::SinglePub {
key: miniscript::descriptor::SinglePubKey::FullKey(pubkey),
origin: None,
})
}
#[test]
fn test_extract_keys_single() {
let key = create_test_key(1);
let tree = DescriptorTree::Key(key.clone());
let keys = tree.extract_keys();
assert_eq!(keys.len(), 1);
assert!(keys.contains(&key));
}
#[test]
fn test_extract_keys_threshold() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Key(key2.clone()),
DescriptorTree::Key(key3.clone()),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
assert!(keys.contains(&key1));
assert!(keys.contains(&key2));
assert!(keys.contains(&key3));
}
#[test]
fn test_extract_keys_with_keyless() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
DescriptorTree::Key(key2.clone()),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
assert!(keys.contains(&key1));
assert!(keys.contains(&key2));
}
#[test]
fn test_prune_keyless_single() {
let key = create_test_key(1);
let tree = DescriptorTree::Key(key.clone());
let result = tree.prune_keyless();
assert!(result.is_some());
match result.unwrap() {
KeylessDescriptorTree::Key(k) => assert_eq!(k, key),
_ => panic!("Expected Key tree"),
}
let tree = DescriptorTree::Keyless::<DescriptorPublicKey>(true);
let result = tree.prune_keyless();
assert!(result.is_none());
}
#[test]
fn test_prune_keyless_threshold() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
DescriptorTree::Keyless::<DescriptorPublicKey>(false),
DescriptorTree::Key(key2.clone()),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_some());
match result.unwrap() {
KeylessDescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 1);
assert_eq!(t.n(), 2);
let mut keys = Vec::new();
for subtree in t.iter() {
if let KeylessDescriptorTree::Key(pk) = subtree {
keys.push(pk.clone())
}
}
assert!(keys.contains(&key1));
assert!(keys.contains(&key2));
}
_ => panic!("Expected Threshold tree"),
}
}
#[test]
fn test_prune_keyless_reduce_threshold() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
DescriptorTree::Keyless::<DescriptorPublicKey>(false),
DescriptorTree::Key(key2.clone()),
];
let thresh = DescriptorTreeThreshold::new(3, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_some());
match result.unwrap() {
KeylessDescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 1); assert_eq!(t.n(), 2);
let mut keys = Vec::new();
for subtree in t.iter() {
if let KeylessDescriptorTree::Key(pk) = subtree {
keys.push(pk.clone())
}
}
assert!(keys.contains(&key1));
assert!(keys.contains(&key2));
}
_ => panic!("Expected Threshold tree"),
}
}
#[test]
fn test_prune_keyless_all_trees_keyless() {
let trees = vec![
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
];
let thresh = DescriptorTreeThreshold::new(1, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_none());
}
#[test]
fn test_prune_keyless_k_exceeds_n_due_to_unsatisfiability() {
let key1 = create_test_key(1);
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_some());
let trees = vec![
DescriptorTree::Key(key1.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(false),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_none());
}
#[test]
fn test_prune_keyless_single_key_after_pruning() {
let key = create_test_key(1);
let trees = vec![
DescriptorTree::Key(key.clone()),
DescriptorTree::Keyless::<DescriptorPublicKey>(true),
];
let thresh = DescriptorTreeThreshold::new(2, trees).unwrap();
let tree = DescriptorTree::Threshold(thresh);
let result = tree.prune_keyless();
assert!(result.is_some());
match result.unwrap() {
KeylessDescriptorTree::Key(k) => assert_eq!(k, key),
_ => panic!("Expected a single Key tree"),
}
}
#[test]
fn test_to_tree_wpkh() {
let key = create_test_key(1);
let desc_str = format!("wpkh({})", key);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
match tree {
DescriptorTree::Key(k) => match (k, key) {
(
DescriptorPublicKey::Single(single_k),
DescriptorPublicKey::Single(single_key),
) => match (&single_k.key, &single_key.key) {
(
miniscript::descriptor::SinglePubKey::FullKey(k_pk),
miniscript::descriptor::SinglePubKey::FullKey(key_pk),
) => {
assert_eq!(k_pk.inner.serialize(), key_pk.inner.serialize());
}
_ => panic!("Expected FullKey for both keys"),
},
_ => panic!("Expected Single keys"),
},
_ => panic!("Expected Key tree for wpkh descriptor"),
}
}
#[test]
fn test_to_tree_pkh() {
let key = create_test_key(1);
let desc_str = format!("pkh({})", key);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
match tree {
DescriptorTree::Key(_) => {}
_ => panic!("Expected Key tree for pkh descriptor"),
}
}
#[test]
fn test_to_tree_bare_pk() {
let desc_str = "pk(020000000000000000000000000000000000000000000000000000000000000002)";
let desc = Descriptor::<DescriptorPublicKey>::from_str(desc_str).unwrap();
let tree = desc.to_tree();
match tree {
DescriptorTree::Key(_) => {}
_ => panic!("Expected Key tree for pkh descriptor"),
}
}
#[test]
fn test_to_tree_wsh_multi() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let desc_str = format!("wsh(multi(2,{},{},{}))", key1, key2, key3);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 2);
assert_eq!(t.n(), 3);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let key_serialized3 = serialize_descriptor_pubkey(&key3);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
assert!(extracted_serialized.contains(&key_serialized3));
}
_ => panic!("Expected Threshold tree for wsh(multi) descriptor"),
}
}
#[test]
fn test_to_tree_sh_wsh_multi() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let desc_str = format!("sh(wsh(multi(2,{},{})))", key1, key2);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 2);
assert_eq!(t.n(), 2);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
}
_ => panic!("Expected Threshold tree for sh(wsh(multi)) descriptor"),
}
}
#[test]
fn test_to_tree_tr() {
let key = create_test_key(1);
let desc_str = format!("tr({})", key);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 1);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.n(), 1);
let key_serialized = serialize_descriptor_pubkey(&key);
let extracted_serialized = serialize_descriptor_pubkey(&keys[0]);
assert_eq!(extracted_serialized, key_serialized);
}
_ => panic!("Expected Threshold tree for tr descriptor"),
}
}
#[test]
fn test_to_tree_tr_with_scripts() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let desc_str = format!("tr({},pk({}))", key1, key2);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.n(), 2);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
}
_ => panic!("Expected Threshold tree for tr descriptor with script"),
}
let desc_str = format!("tr({},{{pk({}),pk({})}})", key1, key2, key3);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.n(), 3);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let key_serialized3 = serialize_descriptor_pubkey(&key3);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
assert!(extracted_serialized.contains(&key_serialized3));
}
_ => panic!("Expected Threshold tree for tr descriptor with multiple scripts"),
}
}
#[test]
fn test_to_tree_with_miniscript_and() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let desc_str = format!("wsh(and_v(v:pk({}),pk({})))", key1, key2);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.k(), t.n());
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
}
_ => panic!("Expected Threshold tree for AND miniscript"),
}
}
#[test]
fn test_to_tree_with_miniscript_or() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let desc_str = format!("wsh(or_d(pk({}),pk({})))", key1, key2);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 1); assert_eq!(t.n(), 2);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
}
_ => panic!("Expected Threshold tree for OR miniscript"),
}
}
#[test]
fn test_to_tree_with_miniscript_thresh() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let desc_str = format!("wsh(thresh(2,pk({}),s:pk({}),s:pk({})))", key1, key2, key3);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
match tree {
DescriptorTree::Threshold(t) => {
assert_eq!(t.k(), 2);
assert_eq!(t.n(), 3);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let key_serialized3 = serialize_descriptor_pubkey(&key3);
let extracted_serialized: Vec<_> =
keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
assert!(extracted_serialized.contains(&key_serialized3));
}
_ => panic!("Expected Threshold tree for thresh miniscript"),
}
}
#[test]
fn test_to_tree_with_miniscript_andor() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let desc_str = format!("wsh(andor(pk({}),pk({}),pk({})))", key1, key2, key3);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let key_serialized3 = serialize_descriptor_pubkey(&key3);
let extracted_serialized: Vec<_> = keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
assert!(extracted_serialized.contains(&key_serialized3));
}
#[test]
fn test_to_tree_with_timelock() {
let key = create_test_key(1);
let desc_str = format!("wsh(and_v(v:pk({}),after(100)))", key);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 1);
match tree {
DescriptorTree::Threshold(_) => {
let key_serialized = serialize_descriptor_pubkey(&key);
let extracted_serialized = serialize_descriptor_pubkey(&keys[0]);
assert_eq!(extracted_serialized, key_serialized);
let keyless = tree.prune_keyless();
assert!(keyless.is_some());
match keyless.unwrap() {
KeylessDescriptorTree::Key(k) => {
let k_serialized = serialize_descriptor_pubkey(&k);
assert_eq!(k_serialized, key_serialized);
}
_ => panic!("Expected single key after prune_keyless"),
}
}
_ => panic!("Expected Threshold tree for timelock descriptor"),
}
}
#[test]
fn test_to_tree_with_hashlocks() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let desc_str = format!(
"wsh(or_d(pk({}),and_v(v:pk({}),sha256(7924b373d3b1a8269050c572a0b5a5461d8211d5777744c78ca247bc30569b21))))",
key1, key2
);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 2);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let extracted_serialized: Vec<_> = keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
let keyless = tree.prune_keyless();
assert!(keyless.is_some());
}
#[test]
fn test_complex_descriptor() {
let key1 = create_test_key(1);
let key2 = create_test_key(2);
let key3 = create_test_key(3);
let desc_str = format!(
"wsh(or_d(pk({}),and_v(v:thresh(2,pk({}),s:pk({}),sln:older(1000)),after(100))))",
key1, key2, key3
);
let desc = Descriptor::<DescriptorPublicKey>::from_str(&desc_str).unwrap();
let tree = desc.to_tree();
let keys = tree.extract_keys();
assert_eq!(keys.len(), 3);
let key_serialized1 = serialize_descriptor_pubkey(&key1);
let key_serialized2 = serialize_descriptor_pubkey(&key2);
let key_serialized3 = serialize_descriptor_pubkey(&key3);
let extracted_serialized: Vec<_> = keys.iter().map(serialize_descriptor_pubkey).collect();
assert!(extracted_serialized.contains(&key_serialized1));
assert!(extracted_serialized.contains(&key_serialized2));
assert!(extracted_serialized.contains(&key_serialized3));
}
fn serialize_descriptor_pubkey(key: &DescriptorPublicKey) -> Vec<u8> {
match key {
DescriptorPublicKey::Single(single) => match &single.key {
miniscript::descriptor::SinglePubKey::FullKey(pk) => pk.inner.serialize().to_vec(),
miniscript::descriptor::SinglePubKey::XOnly(xpk) => xpk.serialize().to_vec(),
},
DescriptorPublicKey::XPub(xpub) => xpub.xkey.encode().to_vec(),
DescriptorPublicKey::MultiXPub(multi) => multi.xkey.encode().to_vec(),
}
}
}