Skip to content

Commit d2278d5

Browse files
committed
Remove recursion from is_safe_nonmalleable
As we have done for other `Policy` functions remove the recursive calls in `is_safe_nonmalleable` and use the `post_order_iter` to process each node accumulating the required results in a vector during iteration.
1 parent 90c18f3 commit d2278d5

File tree

1 file changed

+40
-35
lines changed

1 file changed

+40
-35
lines changed

src/policy/concrete.rs

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -799,43 +799,48 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
799799
/// Returns a tuple `(safe, non-malleable)` to avoid the fact that
800800
/// non-malleability depends on safety and we would like to cache results.
801801
pub fn is_safe_nonmalleable(&self) -> (bool, bool) {
802-
match *self {
803-
Policy::Unsatisfiable | Policy::Trivial => (true, true),
804-
Policy::Key(_) => (true, true),
805-
Policy::Sha256(_)
806-
| Policy::Hash256(_)
807-
| Policy::Ripemd160(_)
808-
| Policy::Hash160(_)
809-
| Policy::After(_)
810-
| Policy::Older(_) => (false, true),
811-
Policy::Threshold(k, ref subs) => {
812-
let (safe_count, non_mall_count) = subs
813-
.iter()
814-
.map(|sub| sub.is_safe_nonmalleable())
815-
.fold((0, 0), |(safe_count, non_mall_count), (safe, non_mall)| {
816-
(safe_count + safe as usize, non_mall_count + non_mall as usize)
817-
});
818-
(
819-
safe_count >= (subs.len() - k + 1),
820-
non_mall_count == subs.len() && safe_count >= (subs.len() - k),
821-
)
822-
}
823-
Policy::And(ref subs) => {
824-
let (atleast_one_safe, all_non_mall) = subs
825-
.iter()
826-
.map(|sub| sub.is_safe_nonmalleable())
827-
.fold((false, true), |acc, x| (acc.0 || x.0, acc.1 && x.1));
828-
(atleast_one_safe, all_non_mall)
829-
}
802+
use Policy::*;
830803

831-
Policy::Or(ref subs) => {
832-
let (all_safe, atleast_one_safe, all_non_mall) = subs
833-
.iter()
834-
.map(|(_, sub)| sub.is_safe_nonmalleable())
835-
.fold((true, false, true), |acc, x| (acc.0 && x.0, acc.1 || x.0, acc.2 && x.1));
836-
(all_safe, atleast_one_safe && all_non_mall)
837-
}
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+
Threshold(k, ref subs) => {
814+
let (safe_count, non_mall_count) = (0..subs.len()).map(acc_for_child_n).fold(
815+
(0, 0),
816+
|(safe_count, non_mall_count), (safe, non_mall)| {
817+
(safe_count + safe as usize, non_mall_count + non_mall as usize)
818+
},
819+
);
820+
(
821+
safe_count >= (subs.len() - k + 1),
822+
non_mall_count == subs.len() && safe_count >= (subs.len() - k),
823+
)
824+
}
825+
And(ref subs) => {
826+
let (atleast_one_safe, all_non_mall) = (0..subs.len())
827+
.map(acc_for_child_n)
828+
.fold((false, true), |acc, x: (bool, bool)| (acc.0 || x.0, acc.1 && x.1));
829+
(atleast_one_safe, all_non_mall)
830+
}
831+
Or(ref subs) => {
832+
let (all_safe, atleast_one_safe, all_non_mall) = (0..subs.len())
833+
.map(acc_for_child_n)
834+
.fold((true, false, true), |acc, x| {
835+
(acc.0 && x.0, acc.1 || x.0, acc.2 && x.1)
836+
});
837+
(all_safe, atleast_one_safe && all_non_mall)
838+
}
839+
};
840+
acc.push(new);
838841
}
842+
// Ok to unwrap because we know we processed at least one node.
843+
acc.pop().unwrap()
839844
}
840845
}
841846

0 commit comments

Comments
 (0)