Skip to content

Commit 30bcc4a

Browse files
committed
Adding all_assets method for miniscript
Using `all_assets` method you can get all possible asset for a given node of Miniscript AST. Eg : multi(2,A,B,C). Then all possible assets are AB,AC and BC. Signed-off-by: Harshil Jani <[email protected]>
1 parent 3c6ae26 commit 30bcc4a

File tree

3 files changed

+355
-4
lines changed

3 files changed

+355
-4
lines changed

src/miniscript/astelem.rs

Lines changed: 210 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ use sync::Arc;
1717
use crate::miniscript::context::SigType;
1818
use crate::miniscript::types::{self, Property};
1919
use crate::miniscript::ScriptContext;
20+
use crate::plan::Assets;
2021
use crate::prelude::*;
2122
use crate::util::MsKeyBuilder;
2223
use crate::{
23-
errstr, expression, AbsLockTime, Error, Miniscript, MiniscriptKey, Terminal, ToPublicKey,
24+
errstr, expression, AbsLockTime, DescriptorPublicKey, Error, Miniscript, MiniscriptKey,
25+
Terminal, ToPublicKey,
2426
};
2527

2628
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
@@ -593,3 +595,210 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
593595
}
594596
}
595597
}
598+
599+
impl<Ctx: ScriptContext> Terminal<DescriptorPublicKey, Ctx> {
600+
/// Retrieve the assets associated with the type of miniscript element.
601+
pub fn all_assets(&self) -> Vec<Assets> {
602+
match self {
603+
Terminal::True => vec![Assets::new()],
604+
Terminal::False => Vec::new(),
605+
Terminal::PkK(k) => {
606+
let mut asset = Assets::new();
607+
asset = asset.add(k.clone());
608+
vec![asset]
609+
}
610+
Terminal::PkH(k) => {
611+
let mut asset = Assets::new();
612+
asset = asset.add(k.clone());
613+
vec![asset]
614+
}
615+
Terminal::RawPkH(k) => {
616+
let mut asset = Assets::new();
617+
asset = asset.add(k.clone());
618+
vec![asset]
619+
}
620+
Terminal::After(k) => {
621+
let mut asset = Assets::new();
622+
asset.absolute_timelock = Some(k.clone().into());
623+
vec![asset]
624+
}
625+
Terminal::Older(k) => {
626+
let mut asset = Assets::new();
627+
asset.relative_timelock = Some(k.clone());
628+
vec![asset]
629+
}
630+
Terminal::Sha256(k) => {
631+
let mut asset = Assets::new();
632+
asset = asset.add(k.clone());
633+
vec![asset]
634+
}
635+
Terminal::Hash256(k) => {
636+
let mut asset = Assets::new();
637+
asset = asset.add(k.clone());
638+
vec![asset]
639+
}
640+
Terminal::Ripemd160(k) => {
641+
let mut asset = Assets::new();
642+
asset = asset.add(k.clone());
643+
vec![asset]
644+
}
645+
Terminal::Hash160(k) => {
646+
let mut asset = Assets::new();
647+
asset = asset.add(k.clone());
648+
vec![asset]
649+
}
650+
Terminal::Alt(k) => k.all_assets(),
651+
Terminal::Swap(k) => k.all_assets(),
652+
Terminal::Check(k) => k.all_assets(),
653+
Terminal::DupIf(k) => k.all_assets(),
654+
Terminal::Verify(k) => k.all_assets(),
655+
Terminal::NonZero(k) => k.all_assets(),
656+
Terminal::ZeroNotEqual(k) => k.all_assets(),
657+
Terminal::AndB(left, right) | Terminal::AndV(left, right) => {
658+
let a = left.all_assets();
659+
let b = right.all_assets();
660+
let result: Vec<Assets> = a
661+
.into_iter()
662+
.flat_map(|x| {
663+
b.clone().into_iter().map(move |y| {
664+
let mut new_asset = Assets::new();
665+
new_asset = new_asset.add(x.clone());
666+
new_asset = new_asset.add(y.clone());
667+
new_asset
668+
})
669+
})
670+
.collect();
671+
result
672+
}
673+
Terminal::AndOr(a, b, c) => {
674+
let a = a.all_assets();
675+
let b = b.all_assets();
676+
let mut c = c.all_assets();
677+
let and: Vec<Assets> = a
678+
.into_iter()
679+
.flat_map(|x| {
680+
b.clone().into_iter().map(move |y| {
681+
let mut new_asset = Assets::new();
682+
new_asset = new_asset.add(x.clone());
683+
new_asset = new_asset.add(y.clone());
684+
new_asset
685+
})
686+
})
687+
.collect();
688+
c.extend(and);
689+
c
690+
}
691+
Terminal::OrB(left, right)
692+
| Terminal::OrC(left, right)
693+
| Terminal::OrD(left, right)
694+
| Terminal::OrI(left, right) => {
695+
let mut a = left.all_assets();
696+
let b = right.all_assets();
697+
a.extend(b);
698+
a
699+
}
700+
Terminal::Thresh(k, ms) => {
701+
// In order to understand working of below code consider k of n as 2 of 3 thresh policy
702+
// Eg : thresh(2,ms(A),ms(B),ms(C)) Here ms(A),ms(B) and ms(C) are miniscript policies
703+
// k = 2
704+
// ms = [ms(A),ms(B),ms(C)];
705+
// We would consider the possible combinations of k policies into the ms_v
706+
// here k=2 so all possible combinations of 2.
707+
// ms_v = [[ms(A),ms(B)],[ms(A),ms(C)],[ms(B),ms(C)]]
708+
// Between each set of combination we would need to do an OR
709+
// (i.e ms_v[0] OR ms_v[1] OR ms_v[3])
710+
// Now inside of each policy combination we need to have AND
711+
// Eg : ms_v[0] = [ms(A),ms(B)] so here -> ms(A) AND ms(B)
712+
713+
let ms_v = Self::get_ms_combination_thresh(*k, ms);
714+
let mut result = Vec::new();
715+
for ms in ms_v {
716+
// AND between each miniscript policy
717+
let mut and: Vec<Assets> = Vec::new();
718+
if let Some(first_assets) = ms.first() {
719+
and = first_assets.all_assets().clone();
720+
}
721+
for i in ms.iter().skip(1) {
722+
let i_assets = i.all_assets();
723+
and = and
724+
.iter()
725+
.flat_map(|x| {
726+
i_assets.iter().map(move |y| {
727+
let mut new_asset = x.clone();
728+
new_asset = new_asset.add(y.clone());
729+
new_asset
730+
})
731+
})
732+
.collect();
733+
}
734+
// OR of possible combinations of k miniscript policies.
735+
result.extend(and.clone());
736+
}
737+
result
738+
}
739+
Terminal::Multi(k, dpk_v) | Terminal::MultiA(k, dpk_v) => {
740+
Self::get_asset_combination(*k, dpk_v)
741+
}
742+
}
743+
}
744+
745+
// Helper to get all possible pairs of K of N assets
746+
fn get_asset_combination(k: usize, dpk_v: &Vec<DescriptorPublicKey>) -> Vec<Assets> {
747+
let mut all_assets: Vec<Assets> = Vec::new();
748+
let current_assets = Assets::new();
749+
Self::combine_assets(k, dpk_v, 0, current_assets, &mut all_assets);
750+
all_assets
751+
}
752+
753+
// Combine K of N assets
754+
fn combine_assets(
755+
k: usize,
756+
dpk_v: &[DescriptorPublicKey],
757+
index: usize,
758+
current_assets: Assets,
759+
all_assets: &mut Vec<Assets>,
760+
) {
761+
if k == 0 {
762+
all_assets.push(current_assets);
763+
return;
764+
}
765+
if index >= dpk_v.len() {
766+
return;
767+
}
768+
Self::combine_assets(k, dpk_v, index + 1, current_assets.clone(), all_assets);
769+
let mut new_asset = current_assets;
770+
new_asset = new_asset.add(dpk_v[index].clone());
771+
println!("{:#?}", new_asset);
772+
Self::combine_assets(k - 1, dpk_v, index + 1, new_asset, all_assets)
773+
}
774+
775+
// Helper to get all combinations of K policies of N for thresh
776+
fn get_ms_combination_thresh(
777+
k: usize,
778+
ms: &Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
779+
) -> Vec<Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>> {
780+
let mut result = Vec::new();
781+
let mut current_combination = Vec::new();
782+
Self::combine_ms(0, &mut current_combination, &mut result, ms, k);
783+
result
784+
}
785+
786+
// combine K policies of N for thresh
787+
fn combine_ms(
788+
start: usize,
789+
current_combination: &mut Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
790+
result: &mut Vec<Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>>,
791+
ms: &Vec<Arc<Miniscript<DescriptorPublicKey, Ctx>>>,
792+
k: usize,
793+
) {
794+
if current_combination.len() == k {
795+
result.push(current_combination.clone());
796+
return;
797+
}
798+
for i in start..ms.len() {
799+
current_combination.push(ms[i].clone());
800+
Self::combine_ms(i + 1, current_combination, result, ms, k);
801+
current_combination.truncate(current_combination.len() - 1);
802+
}
803+
}
804+
}

0 commit comments

Comments
 (0)