Skip to content

Commit 9a2d4f5

Browse files
committed
count_assets method for total ways to obtain assets
Signed-off-by: Harshil Jani <harshiljani2002@gmail.com>
1 parent e0e9fb2 commit 9a2d4f5

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

src/descriptor/mod.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,51 @@ impl Descriptor<DefiniteDescriptorKey> {
569569
}
570570

571571
impl Descriptor<DescriptorPublicKey> {
572+
/// Count total possible assets for a given descriptor.
573+
pub fn count_assets(&self) -> u64 {
574+
match self {
575+
Descriptor::Bare(k) => k.as_inner().count_assets(),
576+
Descriptor::Pkh(_) => 1,
577+
Descriptor::Wpkh(_) => 1,
578+
Descriptor::Sh(k) => match k.as_inner() {
579+
ShInner::Wsh(k) => match k.as_inner() {
580+
WshInner::SortedMulti(k) => {
581+
let n = k.pks.len() as u64;
582+
let k = k.k as u64;
583+
Self::k_of_n(k, n)
584+
}
585+
WshInner::Ms(k) => k.count_assets(),
586+
},
587+
ShInner::Wpkh(_) => 1,
588+
ShInner::SortedMulti(k) => {
589+
let n = k.clone().pks.len() as u64;
590+
let k = k.clone().k as u64;
591+
Self::k_of_n(k, n)
592+
}
593+
ShInner::Ms(k) => k.count_assets(),
594+
},
595+
Descriptor::Wsh(k) => match k.as_inner() {
596+
WshInner::SortedMulti(k) => {
597+
let n = k.clone().pks.len() as u64;
598+
let k = k.clone().k as u64;
599+
Self::k_of_n(k, n)
600+
}
601+
WshInner::Ms(k) => k.count_assets(),
602+
},
603+
Descriptor::Tr(k) => {
604+
let s = k.taptree().clone().unwrap();
605+
match s {
606+
TapTree::Tree(ref left, ref right) => {
607+
let a = left.count_assets();
608+
let b = right.count_assets();
609+
a + b
610+
}
611+
TapTree::Leaf(k) => k.count_assets(),
612+
}
613+
}
614+
}
615+
}
616+
572617
/// Get all possible assets for a given descriptor
573618
pub fn get_all_assets(&self) -> Result<Vec<Assets>, Error> {
574619
match self {
@@ -659,6 +704,14 @@ impl Descriptor<DescriptorPublicKey> {
659704
println!("{:#?}", new_asset);
660705
Self::combine_assets(k - 1, dpk_v, index + 1, new_asset, all_assets)
661706
}
707+
708+
// ways to select k things out of n
709+
fn k_of_n(k: u64, n: u64) -> u64 {
710+
if k == 0 || k == n {
711+
return 1;
712+
}
713+
Self::k_of_n(k - 1, n - 1) + Self::k_of_n(k - 1, n)
714+
}
662715
}
663716

664717
impl<P, Q> TranslatePk<P, Q> for Descriptor<P>

src/descriptor/tr.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,18 @@ impl TapTree<DescriptorPublicKey> {
161161
TapTree::Leaf(k) => k.get_all_assets(),
162162
}
163163
}
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+
}
164176
}
165177

166178
impl<Pk: MiniscriptKey> fmt::Display for TapTree<Pk> {

src/miniscript/astelem.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,93 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
597597
}
598598

599599
impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
600+
/// Count total possible assets
601+
pub fn count_assets(&self) -> u64 {
602+
match self {
603+
Terminal::True => 0,
604+
Terminal::False => 0,
605+
Terminal::PkK(_) => 1,
606+
Terminal::PkH(_) => 1,
607+
Terminal::RawPkH(_) => 1,
608+
// What happens to timelocks ? for both the assets and the count.
609+
Terminal::After(_) => 0,
610+
Terminal::Older(_) => 0,
611+
Terminal::Sha256(_) => 1,
612+
Terminal::Hash256(_) => 1,
613+
Terminal::Ripemd160(_) => 1,
614+
Terminal::Hash160(_) => 1,
615+
Terminal::Alt(k) => k.count_assets(),
616+
Terminal::Swap(k) => k.count_assets(),
617+
Terminal::Check(k) => k.count_assets(),
618+
Terminal::DupIf(k) => k.count_assets(),
619+
Terminal::Verify(k) => k.count_assets(),
620+
Terminal::NonZero(k) => k.count_assets(),
621+
Terminal::ZeroNotEqual(k) => k.count_assets(),
622+
Terminal::AndV(left, right) => {
623+
let left_count = left.count_assets();
624+
let right_count = right.count_assets();
625+
left_count * right_count
626+
}
627+
Terminal::AndB(left, right) => {
628+
let left_count = left.count_assets();
629+
let right_count = right.count_assets();
630+
left_count * right_count
631+
}
632+
Terminal::AndOr(a, b, c) => {
633+
let a = a.count_assets();
634+
let b = b.count_assets();
635+
let c = c.count_assets();
636+
(a * b) + c
637+
}
638+
Terminal::OrB(left, right) => {
639+
let left_count = left.count_assets();
640+
let right_count = right.count_assets();
641+
left_count + right_count
642+
}
643+
Terminal::OrD(left, right) => {
644+
let left_count = left.count_assets();
645+
let right_count = right.count_assets();
646+
left_count + right_count
647+
}
648+
Terminal::OrC(left, right) => {
649+
let left_count = left.count_assets();
650+
let right_count = right.count_assets();
651+
left_count + right_count
652+
}
653+
Terminal::OrI(left, right) => {
654+
let left_count = left.count_assets();
655+
let right_count = right.count_assets();
656+
left_count + right_count
657+
}
658+
Terminal::Thresh(k, ms_v) => {
659+
// k = 2, n = ms_v.len()
660+
// ms_v = [ms(A),ms(B),ms(C)];
661+
// Assume count array as [5,7,8] and k=2
662+
// get_combinations_product gives [5*7,5*8,7*8] = [35,40,56]
663+
let mut count_array = Vec::new();
664+
for ms in ms_v {
665+
count_array.push(ms.count_assets());
666+
}
667+
let products = Self::get_combinations_product(&count_array, *k as u64);
668+
let mut total_count: u64 = 0;
669+
for product in products {
670+
total_count += product;
671+
}
672+
total_count
673+
}
674+
Terminal::Multi(k, dpk) => {
675+
let k: u64 = *k as u64;
676+
let n: u64 = dpk.len() as u64;
677+
Self::k_of_n(k, n)
678+
}
679+
Terminal::MultiA(k, dpk) => {
680+
let k: u64 = *k as u64;
681+
let n: u64 = dpk.len() as u64;
682+
Self::k_of_n(k, n)
683+
}
684+
}
685+
}
686+
600687
/// Retrieve the assets associated with the type of miniscript element.
601688
pub fn get_all_assets(&self) -> Vec<Assets> {
602689
match self {
@@ -824,4 +911,38 @@ impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
824911
current_combination.truncate(current_combination.len() - 1);
825912
}
826913
}
914+
915+
// Do product of K combinations
916+
fn get_combinations_product(values: &[u64], k: u64) -> Vec<u64> {
917+
let mut products = Vec::new();
918+
let n = values.len();
919+
920+
if k == 0 {
921+
return vec![1]; // Empty combination has a product of 1
922+
}
923+
924+
// Using bitwise operations to generate combinations
925+
let max_combinations = 1u32 << n;
926+
for combination_bits in 1..max_combinations {
927+
if combination_bits.count_ones() as usize == k as usize {
928+
let mut product = 1;
929+
for i in 0..n {
930+
if combination_bits & (1u32 << i) != 0 {
931+
product *= values[i];
932+
}
933+
}
934+
products.push(product);
935+
}
936+
}
937+
938+
products
939+
}
940+
941+
// ways to select k things out of n
942+
fn k_of_n(k: u64, n: u64) -> u64 {
943+
if k == 0 || k == n {
944+
return 1;
945+
}
946+
Self::k_of_n(k - 1, n - 1) + Self::k_of_n(k, n - 1)
947+
}
827948
}

src/miniscript/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ impl<Ctx: ScriptContext> Miniscript<DescriptorPublicKey, Ctx> {
410410
pub fn get_all_assets(&self) -> Vec<Assets> {
411411
self.node.get_all_assets()
412412
}
413+
414+
/// Get the total number of assets possible
415+
pub fn count_assets(&self) -> u64 {
416+
self.node.count_assets()
417+
}
413418
}
414419

415420
impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for Miniscript<Pk, Ctx> {

0 commit comments

Comments
 (0)