Skip to content

Commit 3868fea

Browse files
committed
Remove recursion from is_valid
Currently the `is_valid` function recursively calls itself, we can use the `pre_order_iter` to loop over the policy nodes instead and remove the recursion. Note that this whole `is_valid` function is pretty inefficient because we have already iterated the nodes twice already (in `check_timelocks` and `check_duplicate_keys`).
1 parent 9effa2d commit 3868fea

File tree

1 file changed

+31
-44
lines changed

1 file changed

+31
-44
lines changed

src/policy/concrete.rs

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
And(ref subs) => {
760+
if subs.len() != 2 {
761+
return Err(PolicyError::NonBinaryArgAnd);
762+
}
763763
}
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(())
764+
Or(ref subs) => {
765+
if subs.len() != 2 {
766+
return Err(PolicyError::NonBinaryArgOr);
767+
}
773768
}
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(())
769+
Threshold(k, ref subs) => {
770+
if k == 0 || k > subs.len() {
771+
return Err(PolicyError::IncorrectThresh);
772+
}
783773
}
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(())
774+
After(n) => {
775+
if n == absolute::LockTime::ZERO.into() {
776+
return Err(PolicyError::ZeroTime);
777+
} else if n.to_u32() > 2u32.pow(31) {
778+
return Err(PolicyError::TimeTooFar);
779+
}
792780
}
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(())
781+
Older(n) => {
782+
if n == Sequence::ZERO {
783+
return Err(PolicyError::ZeroTime);
784+
} else if n.to_consensus_u32() > 2u32.pow(31) {
785+
return Err(PolicyError::TimeTooFar);
786+
}
801787
}
788+
_ => {}
802789
}
803-
_ => Ok(()),
804790
}
791+
Ok(())
805792
}
806793

807794
/// Checks if any possible compilation of the policy could be compiled

0 commit comments

Comments
 (0)