Skip to content

Commit bf4ff5c

Browse files
committed
all_assets method for descriptors
Signed-off-by: Harshil Jani <[email protected]>
1 parent 7649827 commit bf4ff5c

File tree

6 files changed

+385
-37
lines changed

6 files changed

+385
-37
lines changed

src/descriptor/mod.rs

+191-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ use sync::Arc;
2323
use self::checksum::verify_checksum;
2424
use crate::miniscript::decode::Terminal;
2525
use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0};
26-
use crate::plan::{AssetProvider, Plan};
26+
use crate::plan::{AssetProvider, Assets, Plan};
2727
use crate::prelude::*;
28+
use crate::util::get_asset_combination;
2829
use crate::{
2930
expression, hash256, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey,
3031
TranslateErr, TranslatePk, Translator,
@@ -568,6 +569,124 @@ impl Descriptor<DefiniteDescriptorKey> {
568569
}
569570
}
570571

572+
impl Descriptor<DescriptorPublicKey> {
573+
/// Count total possible assets for a given descriptor.
574+
pub fn count_assets(&self) -> u64 {
575+
match self {
576+
Descriptor::Bare(k) => k.as_inner().count_assets(),
577+
Descriptor::Pkh(_) => 1,
578+
Descriptor::Wpkh(_) => 1,
579+
Descriptor::Sh(k) => match k.as_inner() {
580+
ShInner::Wsh(k) => match k.as_inner() {
581+
WshInner::SortedMulti(k) => {
582+
let n = k.pks.len() as u64;
583+
let k = k.k as u64;
584+
Self::k_of_n(k, n)
585+
}
586+
WshInner::Ms(k) => k.count_assets(),
587+
},
588+
ShInner::Wpkh(_) => 1,
589+
ShInner::SortedMulti(k) => {
590+
let n = k.clone().pks.len() as u64;
591+
let k = k.clone().k as u64;
592+
Self::k_of_n(k, n)
593+
}
594+
ShInner::Ms(k) => k.count_assets(),
595+
},
596+
Descriptor::Wsh(k) => match k.as_inner() {
597+
WshInner::SortedMulti(k) => {
598+
let n = k.clone().pks.len() as u64;
599+
let k = k.clone().k as u64;
600+
Self::k_of_n(k, n)
601+
}
602+
WshInner::Ms(k) => k.count_assets(),
603+
},
604+
Descriptor::Tr(k) => {
605+
let s = k.taptree().clone().unwrap();
606+
match s {
607+
TapTree::Tree(ref left, ref right) => {
608+
let a = left.count_assets();
609+
let b = right.count_assets();
610+
a + b
611+
}
612+
TapTree::Leaf(k) => k.count_assets(),
613+
}
614+
}
615+
}
616+
}
617+
618+
/// Get all possible assets for a given descriptor
619+
pub fn all_assets(&self) -> Result<Vec<Assets>, Error> {
620+
match self {
621+
Descriptor::Bare(k) => Ok(k.as_inner().all_assets()),
622+
Descriptor::Pkh(k) => {
623+
let mut asset = Assets::new();
624+
asset = asset.add(k.as_inner().clone());
625+
Ok(vec![asset])
626+
}
627+
Descriptor::Wpkh(k) => {
628+
let mut asset = Assets::new();
629+
asset = asset.add(k.as_inner().clone());
630+
Ok(vec![asset])
631+
}
632+
Descriptor::Sh(k) => match k.as_inner() {
633+
ShInner::Wsh(k) => match k.as_inner() {
634+
WshInner::SortedMulti(k) => {
635+
let dpk_v = k.clone().pks;
636+
let k = k.clone().k;
637+
Ok(get_asset_combination(k, &dpk_v))
638+
}
639+
WshInner::Ms(k) => Ok(k.all_assets()),
640+
},
641+
ShInner::Wpkh(k) => {
642+
let mut asset = Assets::new();
643+
asset = asset.add(k.as_inner().clone());
644+
Ok(vec![asset])
645+
}
646+
ShInner::SortedMulti(k) => {
647+
let dpk_v = k.clone().pks;
648+
let k = k.clone().k;
649+
Ok(get_asset_combination(k, &dpk_v))
650+
}
651+
ShInner::Ms(k) => Ok(k.all_assets()),
652+
},
653+
Descriptor::Wsh(k) => match k.as_inner() {
654+
WshInner::SortedMulti(k) => {
655+
let dpk_v = k.clone().pks;
656+
let k = k.clone().k;
657+
Ok(get_asset_combination(k, &dpk_v))
658+
}
659+
WshInner::Ms(k) => {
660+
println!("{}", k);
661+
let a = k.all_assets();
662+
println!("{:#?}", a);
663+
Ok(a)
664+
}
665+
},
666+
Descriptor::Tr(k) => {
667+
let s = k.taptree().clone().unwrap();
668+
match s {
669+
TapTree::Tree(ref left, ref right) => {
670+
let mut a = left.all_assets();
671+
let b = right.all_assets();
672+
a.extend(b);
673+
Ok(a)
674+
}
675+
TapTree::Leaf(k) => Ok(k.all_assets()),
676+
}
677+
}
678+
}
679+
}
680+
681+
// ways to select k things out of n
682+
fn k_of_n(k: u64, n: u64) -> u64 {
683+
if k == 0 || k == n {
684+
return 1;
685+
}
686+
Self::k_of_n(k - 1, n - 1) + Self::k_of_n(k - 1, n)
687+
}
688+
}
689+
571690
impl<P, Q> TranslatePk<P, Q> for Descriptor<P>
572691
where
573692
P: MiniscriptKey,
@@ -2094,4 +2213,75 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
20942213
Desc::from_str(&format!("tr({},pk({}))", x_only_key, uncomp_key)).unwrap_err();
20952214
Desc::from_str(&format!("tr({},pk({}))", x_only_key, x_only_key)).unwrap();
20962215
}
2216+
2217+
#[test]
2218+
fn test_all_assets_bare() {
2219+
let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
2220+
"pk(0237b1c59ab055a8d3de40eaeb215c7b1922664b5ac049d849fb3346f81431e77f)",
2221+
)
2222+
.unwrap();
2223+
2224+
// Getting the assets from the all_assets method
2225+
let assets = descriptor.all_assets().unwrap();
2226+
2227+
let mut expected_asset = Assets::new();
2228+
expected_asset = expected_asset.add(
2229+
DescriptorPublicKey::from_str(
2230+
"0237b1c59ab055a8d3de40eaeb215c7b1922664b5ac049d849fb3346f81431e77f",
2231+
)
2232+
.unwrap(),
2233+
);
2234+
assert_eq!(assets, vec![expected_asset]);
2235+
}
2236+
2237+
#[test]
2238+
fn test_all_assets_sh_sortedmulti() {
2239+
let keys = vec![
2240+
"0360eabc52e04f70c89e944f379895cdff28fed60849afe7736815c091765afb3c",
2241+
"03a80a24196e66ccf6bca6e6f96633bb629ec702acd76b074de10922b0cf41cc81",
2242+
];
2243+
2244+
let descriptor = Descriptor::<DescriptorPublicKey>::from_str(&format!(
2245+
"sh(sortedmulti(1,{},{}))",
2246+
keys[0], keys[1]
2247+
))
2248+
.unwrap();
2249+
2250+
let assets = descriptor.all_assets().unwrap();
2251+
2252+
let mut expected_assets: Vec<Assets> = Vec::new();
2253+
2254+
let mut asset1 = Assets::new();
2255+
asset1 = asset1.add(DescriptorPublicKey::from_str(keys[0]).unwrap());
2256+
expected_assets.push(asset1);
2257+
2258+
let mut asset2 = Assets::new();
2259+
asset2 = asset2.add(DescriptorPublicKey::from_str(keys[1]).unwrap());
2260+
expected_assets.push(asset2);
2261+
2262+
for expected_asset in &expected_assets {
2263+
assert!(assets.contains(expected_asset));
2264+
}
2265+
}
2266+
2267+
#[test]
2268+
fn test_all_assets_taproot() {
2269+
let x_only_key = bitcoin::key::XOnlyPublicKey::from_str(
2270+
"015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
2271+
)
2272+
.unwrap();
2273+
let descriptor =
2274+
Descriptor::from_str(&format!("tr({},pk({}))", x_only_key, x_only_key)).unwrap();
2275+
let assets = descriptor.all_assets().unwrap();
2276+
let mut expected_assets: Vec<Assets> = Vec::new();
2277+
let mut asset_1 = Assets::new();
2278+
asset_1 = asset_1.add(
2279+
DescriptorPublicKey::from_str(
2280+
"015e4cb53458bf813db8c79968e76e10d13ed6426a23fa71c2f41ba021c2a7ab",
2281+
)
2282+
.unwrap(),
2283+
);
2284+
expected_assets.push(asset_1);
2285+
assert_eq!(assets, expected_assets);
2286+
}
20972287
}

src/descriptor/tr.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ use crate::descriptor::DefiniteDescriptorKey;
1616
use crate::expression::{self, FromTree};
1717
use crate::miniscript::satisfy::{Placeholder, Satisfaction, SchnorrSigType, Witness};
1818
use crate::miniscript::Miniscript;
19-
use crate::plan::AssetProvider;
19+
use crate::plan::{AssetProvider, Assets};
2020
use crate::policy::semantic::Policy;
2121
use crate::policy::Liftable;
2222
use crate::prelude::*;
2323
use crate::util::{varint_len, witness_size};
2424
use crate::{
25-
errstr, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap, ToPublicKey,
26-
TranslateErr, TranslatePk, Translator,
25+
errstr, DescriptorPublicKey, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap,
26+
ToPublicKey, TranslateErr, TranslatePk, Translator,
2727
};
2828

2929
/// A Taproot Tree representation.
@@ -148,6 +148,33 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
148148
}
149149
}
150150

151+
impl TapTree<DescriptorPublicKey> {
152+
/// Get all possible assets for Taptree
153+
pub fn all_assets(&self) -> Vec<Assets> {
154+
match self {
155+
TapTree::Tree(left, right) => {
156+
let mut a = left.all_assets();
157+
let b = right.all_assets();
158+
a.extend(b);
159+
a
160+
}
161+
TapTree::Leaf(k) => k.all_assets(),
162+
}
163+
}
164+
165+
/// Get total possible assets for TapTree
166+
pub fn count_assets(&self) -> u64 {
167+
match self {
168+
TapTree::Tree(left, right) => {
169+
let a = left.count_assets();
170+
let b = right.count_assets();
171+
a + b
172+
}
173+
TapTree::Leaf(k) => k.count_assets(),
174+
}
175+
}
176+
}
177+
151178
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {
152179
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153180
match self {

src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,8 @@ pub enum Error {
560560
/// At least two BIP389 key expressions in the descriptor contain tuples of
561561
/// derivation indexes of different lengths.
562562
MultipathDescLenMismatch,
563+
/// Cannot get assets for this large descriptor. Exceeds 1000 assets.
564+
MaxAssetThresholdExceeded,
563565
}
564566

565567
// https://github.com/sipa/miniscript/pull/5 for discussion on this number
@@ -636,6 +638,7 @@ impl fmt::Display for Error {
636638
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
637639
Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
638640
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
641+
Error::MaxAssetThresholdExceeded => write!(f,"Cannot plan descriptors having more than 1000 possible spend paths."),
639642
}
640643
}
641644
}
@@ -678,6 +681,7 @@ impl error::Error for Error {
678681
| TrNoScriptCode
679682
| TrNoExplicitScript
680683
| MultipathDescLenMismatch => None,
684+
MaxAssetThresholdExceeded => None,
681685
Script(e) => Some(e),
682686
AddrError(e) => Some(e),
683687
BadPubkey(e) => Some(e),

0 commit comments

Comments
 (0)