Skip to content

Commit 1ebde2d

Browse files
committed
Merge #606: Remove more recursion from concrete::policy
0452040 Order arms as in enum definition (Tobin C. Harding) d2278d5 Remove recursion from is_safe_nonmalleable (Tobin C. Harding) 90c18f3 Remove recursion from is_valid (Tobin C. Harding) Pull request description: Remove the last of the recursion in functions that process policies. Note there is still recursion in the `from_tree_prob` function that creates the policies. ACKs for top commit: apoelstra: ACK 0452040 sanket1729: utACK 0452040 Tree-SHA512: 0c9ac6481e959af4ed576f1d23e28408dc88d917a4785dc31cb54eff749716505f9394715aa448c595ed7b5d007166754ba74a0bdc94b749e5d3993b38bce547
2 parents f8717e4 + 0452040 commit 1ebde2d

File tree

1 file changed

+79
-87
lines changed

1 file changed

+79
-87
lines changed

src/policy/concrete.rs

Lines changed: 79 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -579,13 +579,13 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
579579
Hash160(ref h) => t.hash160(h).map(Hash160)?,
580580
Older(ref n) => Older(*n),
581581
After(ref n) => After(*n),
582-
Threshold(ref k, ref subs) => Threshold(*k, (0..subs.len()).map(child_n).collect()),
583582
And(ref subs) => And((0..subs.len()).map(child_n).collect()),
584583
Or(ref subs) => Or(subs
585584
.iter()
586585
.enumerate()
587586
.map(|(i, (prob, _))| (*prob, child_n(i)))
588587
.collect()),
588+
Threshold(ref k, ref subs) => Threshold(*k, (0..subs.len()).map(child_n).collect()),
589589
};
590590
translated.push(Arc::new(new_policy));
591591
}
@@ -605,15 +605,15 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
605605

606606
let new_policy = match data.node.as_ref() {
607607
Policy::Key(ref k) if k.clone() == *key => Some(Policy::Unsatisfiable),
608-
Threshold(k, ref subs) => {
609-
Some(Threshold(*k, (0..subs.len()).map(child_n).collect()))
610-
}
611608
And(ref subs) => Some(And((0..subs.len()).map(child_n).collect())),
612609
Or(ref subs) => Some(Or(subs
613610
.iter()
614611
.enumerate()
615612
.map(|(i, (prob, _))| (*prob, child_n(i)))
616613
.collect())),
614+
Threshold(k, ref subs) => {
615+
Some(Threshold(*k, (0..subs.len()).map(child_n).collect()))
616+
}
617617
_ => None,
618618
};
619619
match new_policy {
@@ -724,10 +724,6 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
724724
cltv_with_time: false,
725725
contains_combination: false,
726726
},
727-
Threshold(ref k, subs) => {
728-
let iter = (0..subs.len()).map(info_for_child_n);
729-
TimelockInfo::combine_threshold(*k, iter)
730-
}
731727
And(ref subs) => {
732728
let iter = (0..subs.len()).map(info_for_child_n);
733729
TimelockInfo::combine_threshold(subs.len(), iter)
@@ -736,6 +732,10 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
736732
let iter = (0..subs.len()).map(info_for_child_n);
737733
TimelockInfo::combine_threshold(1, iter)
738734
}
735+
Threshold(ref k, subs) => {
736+
let iter = (0..subs.len()).map(info_for_child_n);
737+
TimelockInfo::combine_threshold(*k, iter)
738+
}
739739
_ => TimelockInfo::default(),
740740
};
741741
infos.push(info);
@@ -749,59 +749,46 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
749749
/// Validity condition also checks whether there is a possible satisfaction
750750
/// combination of timelocks and heightlocks
751751
pub fn is_valid(&self) -> Result<(), PolicyError> {
752+
use Policy::*;
753+
752754
self.check_timelocks()?;
753755
self.check_duplicate_keys()?;
754-
match *self {
755-
Policy::And(ref subs) => {
756-
if subs.len() != 2 {
757-
Err(PolicyError::NonBinaryArgAnd)
758-
} else {
759-
subs.iter()
760-
.map(|sub| sub.is_valid())
761-
.collect::<Result<Vec<()>, PolicyError>>()?;
762-
Ok(())
756+
757+
for policy in self.pre_order_iter() {
758+
match *policy {
759+
After(n) => {
760+
if n == absolute::LockTime::ZERO.into() {
761+
return Err(PolicyError::ZeroTime);
762+
} else if n.to_u32() > 2u32.pow(31) {
763+
return Err(PolicyError::TimeTooFar);
764+
}
763765
}
764-
}
765-
Policy::Or(ref subs) => {
766-
if subs.len() != 2 {
767-
Err(PolicyError::NonBinaryArgOr)
768-
} else {
769-
subs.iter()
770-
.map(|(_prob, sub)| sub.is_valid())
771-
.collect::<Result<Vec<()>, PolicyError>>()?;
772-
Ok(())
766+
Older(n) => {
767+
if n == Sequence::ZERO {
768+
return Err(PolicyError::ZeroTime);
769+
} else if n.to_consensus_u32() > 2u32.pow(31) {
770+
return Err(PolicyError::TimeTooFar);
771+
}
773772
}
774-
}
775-
Policy::Threshold(k, ref subs) => {
776-
if k == 0 || k > subs.len() {
777-
Err(PolicyError::IncorrectThresh)
778-
} else {
779-
subs.iter()
780-
.map(|sub| sub.is_valid())
781-
.collect::<Result<Vec<()>, PolicyError>>()?;
782-
Ok(())
773+
And(ref subs) => {
774+
if subs.len() != 2 {
775+
return Err(PolicyError::NonBinaryArgAnd);
776+
}
783777
}
784-
}
785-
Policy::After(n) => {
786-
if n == absolute::LockTime::ZERO.into() {
787-
Err(PolicyError::ZeroTime)
788-
} else if n.to_u32() > 2u32.pow(31) {
789-
Err(PolicyError::TimeTooFar)
790-
} else {
791-
Ok(())
778+
Or(ref subs) => {
779+
if subs.len() != 2 {
780+
return Err(PolicyError::NonBinaryArgOr);
781+
}
792782
}
793-
}
794-
Policy::Older(n) => {
795-
if n == Sequence::ZERO {
796-
Err(PolicyError::ZeroTime)
797-
} else if n.to_consensus_u32() > 2u32.pow(31) {
798-
Err(PolicyError::TimeTooFar)
799-
} else {
800-
Ok(())
783+
Threshold(k, ref subs) => {
784+
if k == 0 || k > subs.len() {
785+
return Err(PolicyError::IncorrectThresh);
786+
}
801787
}
788+
_ => {}
802789
}
803-
_ => Ok(()),
804790
}
791+
Ok(())
805792
}
806793

807794
/// Checks if any possible compilation of the policy could be compiled
@@ -812,43 +799,48 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
812799
/// Returns a tuple `(safe, non-malleable)` to avoid the fact that
813800
/// non-malleability depends on safety and we would like to cache results.
814801
pub fn is_safe_nonmalleable(&self) -> (bool, bool) {
815-
match *self {
816-
Policy::Unsatisfiable | Policy::Trivial => (true, true),
817-
Policy::Key(_) => (true, true),
818-
Policy::Sha256(_)
819-
| Policy::Hash256(_)
820-
| Policy::Ripemd160(_)
821-
| Policy::Hash160(_)
822-
| Policy::After(_)
823-
| Policy::Older(_) => (false, true),
824-
Policy::Threshold(k, ref subs) => {
825-
let (safe_count, non_mall_count) = subs
826-
.iter()
827-
.map(|sub| sub.is_safe_nonmalleable())
828-
.fold((0, 0), |(safe_count, non_mall_count), (safe, non_mall)| {
829-
(safe_count + safe as usize, non_mall_count + non_mall as usize)
830-
});
831-
(
832-
safe_count >= (subs.len() - k + 1),
833-
non_mall_count == subs.len() && safe_count >= (subs.len() - k),
834-
)
835-
}
836-
Policy::And(ref subs) => {
837-
let (atleast_one_safe, all_non_mall) = subs
838-
.iter()
839-
.map(|sub| sub.is_safe_nonmalleable())
840-
.fold((false, true), |acc, x| (acc.0 || x.0, acc.1 && x.1));
841-
(atleast_one_safe, all_non_mall)
842-
}
802+
use Policy::*;
843803

844-
Policy::Or(ref subs) => {
845-
let (all_safe, atleast_one_safe, all_non_mall) = subs
846-
.iter()
847-
.map(|(_, sub)| sub.is_safe_nonmalleable())
848-
.fold((true, false, true), |acc, x| (acc.0 && x.0, acc.1 || x.0, acc.2 && x.1));
849-
(all_safe, atleast_one_safe && all_non_mall)
850-
}
804+
let mut acc = vec![];
805+
for data in Arc::new(self).post_order_iter() {
806+
let acc_for_child_n = |n| acc[data.child_indices[n]];
807+
808+
let new = match data.node {
809+
Unsatisfiable | Trivial | Key(_) => (true, true),
810+
Sha256(_) | Hash256(_) | Ripemd160(_) | Hash160(_) | After(_) | Older(_) => {
811+
(false, true)
812+
}
813+
And(ref subs) => {
814+
let (atleast_one_safe, all_non_mall) = (0..subs.len())
815+
.map(acc_for_child_n)
816+
.fold((false, true), |acc, x: (bool, bool)| (acc.0 || x.0, acc.1 && x.1));
817+
(atleast_one_safe, all_non_mall)
818+
}
819+
Or(ref subs) => {
820+
let (all_safe, atleast_one_safe, all_non_mall) = (0..subs.len())
821+
.map(acc_for_child_n)
822+
.fold((true, false, true), |acc, x| {
823+
(acc.0 && x.0, acc.1 || x.0, acc.2 && x.1)
824+
});
825+
(all_safe, atleast_one_safe && all_non_mall)
826+
}
827+
Threshold(k, ref subs) => {
828+
let (safe_count, non_mall_count) = (0..subs.len()).map(acc_for_child_n).fold(
829+
(0, 0),
830+
|(safe_count, non_mall_count), (safe, non_mall)| {
831+
(safe_count + safe as usize, non_mall_count + non_mall as usize)
832+
},
833+
);
834+
(
835+
safe_count >= (subs.len() - k + 1),
836+
non_mall_count == subs.len() && safe_count >= (subs.len() - k),
837+
)
838+
}
839+
};
840+
acc.push(new);
851841
}
842+
// Ok to unwrap because we know we processed at least one node.
843+
acc.pop().unwrap()
852844
}
853845
}
854846

0 commit comments

Comments
 (0)