Skip to content

Commit 351b192

Browse files
committed
Track miniscript tree depth explicitly
1 parent 7ebdd2f commit 351b192

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

src/miniscript/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bitcoin::taproot::{LeafVersion, TapLeafHash};
2222
use self::analyzable::ExtParams;
2323
pub use self::context::{BareCtx, Legacy, Segwitv0, Tap};
2424
use crate::iter::TreeLike;
25-
use crate::prelude::*;
25+
use crate::{prelude::*, MAX_RECURSION_DEPTH};
2626
use crate::{script_num_size, TranslateErr};
2727

2828
pub mod analyzable;
@@ -75,6 +75,13 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
7575
node: t,
7676
phantom: PhantomData,
7777
};
78+
// TODO: This recursion depth is based on segwitv0.
79+
// We can relax this in tapscript, but this should be good for almost
80+
// all practical cases and we can revisit this if needed.
81+
// casting to u32 is safe because tree_height will never go more than u32::MAX
82+
if (res.ext.tree_height as u32) > MAX_RECURSION_DEPTH {
83+
return Err(Error::MaxRecursiveDepthExceeded);
84+
}
7885
Ctx::check_global_consensus_validity(&res)?;
7986
Ok(res)
8087
}

src/miniscript/types/extra_props.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ pub struct ExtData {
131131
/// This does **not** include initial witness elements. This element only captures
132132
/// the additional elements that are pushed during execution.
133133
pub exec_stack_elem_count_dissat: Option<usize>,
134+
/// The miniscript tree depth/height of this node.
135+
/// Used for checking the max depth of the miniscript tree to prevent stack overflow.
136+
pub tree_height: usize,
134137
}
135138

136139
impl Property for ExtData {
@@ -157,6 +160,7 @@ impl Property for ExtData {
157160
timelock_info: TimelockInfo::default(),
158161
exec_stack_elem_count_sat: Some(1),
159162
exec_stack_elem_count_dissat: None,
163+
tree_height : 0,
160164
}
161165
}
162166

@@ -172,6 +176,7 @@ impl Property for ExtData {
172176
timelock_info: TimelockInfo::default(),
173177
exec_stack_elem_count_sat: None,
174178
exec_stack_elem_count_dissat: Some(1),
179+
tree_height : 0,
175180
}
176181
}
177182

@@ -193,6 +198,7 @@ impl Property for ExtData {
193198
timelock_info: TimelockInfo::default(),
194199
exec_stack_elem_count_sat: Some(1), // pushes the pk
195200
exec_stack_elem_count_dissat: Some(1),
201+
tree_height: 0,
196202
}
197203
}
198204

@@ -214,6 +220,7 @@ impl Property for ExtData {
214220
timelock_info: TimelockInfo::default(),
215221
exec_stack_elem_count_sat: Some(2), // dup and hash push
216222
exec_stack_elem_count_dissat: Some(2),
223+
tree_height: 0,
217224
}
218225
}
219226

@@ -237,6 +244,7 @@ impl Property for ExtData {
237244
timelock_info: TimelockInfo::default(),
238245
exec_stack_elem_count_sat: Some(n), // n pks
239246
exec_stack_elem_count_dissat: Some(n),
247+
tree_height: 0,
240248
}
241249
}
242250

@@ -259,6 +267,7 @@ impl Property for ExtData {
259267
timelock_info: TimelockInfo::default(),
260268
exec_stack_elem_count_sat: Some(2), // the two nums before num equal verify
261269
exec_stack_elem_count_dissat: Some(2),
270+
tree_height: 0,
262271
}
263272
}
264273

@@ -279,6 +288,7 @@ impl Property for ExtData {
279288
timelock_info: TimelockInfo::default(),
280289
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
281290
exec_stack_elem_count_dissat: Some(2),
291+
tree_height: 0,
282292
}
283293
}
284294

@@ -294,6 +304,7 @@ impl Property for ExtData {
294304
timelock_info: TimelockInfo::default(),
295305
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
296306
exec_stack_elem_count_dissat: Some(2),
307+
tree_height: 0,
297308
}
298309
}
299310

@@ -309,6 +320,7 @@ impl Property for ExtData {
309320
timelock_info: TimelockInfo::default(),
310321
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
311322
exec_stack_elem_count_dissat: Some(2),
323+
tree_height: 0,
312324
}
313325
}
314326

@@ -324,6 +336,7 @@ impl Property for ExtData {
324336
timelock_info: TimelockInfo::default(),
325337
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
326338
exec_stack_elem_count_dissat: Some(2),
339+
tree_height: 0,
327340
}
328341
}
329342

@@ -347,6 +360,7 @@ impl Property for ExtData {
347360
},
348361
exec_stack_elem_count_sat: Some(1), // <t>
349362
exec_stack_elem_count_dissat: None,
363+
tree_height: 0,
350364
}
351365
}
352366

@@ -368,6 +382,7 @@ impl Property for ExtData {
368382
},
369383
exec_stack_elem_count_sat: Some(1), // <t>
370384
exec_stack_elem_count_dissat: None,
385+
tree_height: 0,
371386
}
372387
}
373388

@@ -383,6 +398,7 @@ impl Property for ExtData {
383398
timelock_info: self.timelock_info,
384399
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
385400
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
401+
tree_height : self.tree_height + 1,
386402
})
387403
}
388404

@@ -398,6 +414,7 @@ impl Property for ExtData {
398414
timelock_info: self.timelock_info,
399415
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
400416
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
417+
tree_height : self.tree_height + 1,
401418
})
402419
}
403420

@@ -413,6 +430,7 @@ impl Property for ExtData {
413430
timelock_info: self.timelock_info,
414431
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
415432
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
433+
tree_height : self.tree_height + 1,
416434
})
417435
}
418436

@@ -431,6 +449,7 @@ impl Property for ExtData {
431449
// Even all V types push something onto the stack and then remove them
432450
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
433451
exec_stack_elem_count_dissat: Some(1),
452+
tree_height : self.tree_height + 1,
434453
})
435454
}
436455

@@ -447,6 +466,7 @@ impl Property for ExtData {
447466
timelock_info: self.timelock_info,
448467
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
449468
exec_stack_elem_count_dissat: None,
469+
tree_height : self.tree_height + 1,
450470
})
451471
}
452472

@@ -462,6 +482,7 @@ impl Property for ExtData {
462482
timelock_info: self.timelock_info,
463483
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
464484
exec_stack_elem_count_dissat: Some(1),
485+
tree_height : self.tree_height + 1,
465486
})
466487
}
467488

@@ -478,6 +499,7 @@ impl Property for ExtData {
478499
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
479500
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
480501
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
502+
tree_height : self.tree_height + 1,
481503
})
482504
}
483505

@@ -518,6 +540,7 @@ impl Property for ExtData {
518540
l.exec_stack_elem_count_dissat,
519541
r.exec_stack_elem_count_dissat.map(|x| x + 1),
520542
),
543+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
521544
})
522545
}
523546

@@ -541,6 +564,7 @@ impl Property for ExtData {
541564
r.exec_stack_elem_count_sat,
542565
),
543566
exec_stack_elem_count_dissat: None,
567+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
544568
})
545569
}
546570

@@ -580,6 +604,7 @@ impl Property for ExtData {
580604
l.exec_stack_elem_count_dissat,
581605
r.exec_stack_elem_count_dissat.map(|x| x + 1),
582606
),
607+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
583608
})
584609
}
585610

@@ -617,6 +642,7 @@ impl Property for ExtData {
617642
l.exec_stack_elem_count_dissat,
618643
r.exec_stack_elem_count_dissat.map(|x| x + 1),
619644
),
645+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
620646
};
621647
Ok(res)
622648
}
@@ -648,6 +674,7 @@ impl Property for ExtData {
648674
opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat),
649675
),
650676
exec_stack_elem_count_dissat: None,
677+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
651678
})
652679
}
653680

@@ -694,6 +721,7 @@ impl Property for ExtData {
694721
l.exec_stack_elem_count_dissat,
695722
r.exec_stack_elem_count_dissat,
696723
),
724+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
697725
})
698726
}
699727

@@ -736,6 +764,7 @@ impl Property for ExtData {
736764
a.exec_stack_elem_count_dissat,
737765
c.exec_stack_elem_count_dissat,
738766
),
767+
tree_height : cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)) + 1,
739768
})
740769
}
741770

@@ -755,6 +784,7 @@ impl Property for ExtData {
755784
// the max element count is same as max sat element count when satisfying one element + 1
756785
let mut exec_stack_elem_count_sat_vec = Vec::with_capacity(n);
757786
let mut exec_stack_elem_count_dissat = Some(0);
787+
let mut max_child_height = 0;
758788

759789
for i in 0..n {
760790
let sub = sub_ck(i)?;
@@ -784,6 +814,7 @@ impl Property for ExtData {
784814
.push((sub.exec_stack_elem_count_sat, sub.exec_stack_elem_count_dissat));
785815
exec_stack_elem_count_dissat =
786816
opt_max(exec_stack_elem_count_dissat, sub.exec_stack_elem_count_dissat);
817+
max_child_height = cmp::max(max_child_height, sub.tree_height);
787818
}
788819

789820
stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
@@ -854,6 +885,7 @@ impl Property for ExtData {
854885
timelock_info: TimelockInfo::combine_threshold(k, timelocks),
855886
exec_stack_elem_count_sat,
856887
exec_stack_elem_count_dissat,
888+
tree_height : max_child_height + 1,
857889
})
858890
}
859891

0 commit comments

Comments
 (0)