Skip to content

Commit 3626712

Browse files
committed
Track miniscript tree depth explicitly
1 parent dc502f4 commit 3626712

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;
@@ -91,6 +91,13 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
9191
node: t,
9292
phantom: PhantomData,
9393
};
94+
// TODO: This recursion depth is based on segwitv0.
95+
// We can relax this in tapscript, but this should be good for almost
96+
// all practical cases and we can revisit this if needed.
97+
// casting to u32 is safe because tree_height will never go more than u32::MAX
98+
if (res.ext.tree_height as u32) > MAX_RECURSION_DEPTH {
99+
return Err(Error::MaxRecursiveDepthExceeded);
100+
}
94101
Ctx::check_global_consensus_validity(&res)?;
95102
Ok(res)
96103
}

src/miniscript/types/extra_props.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ pub struct ExtData {
140140
/// This does **not** include initial witness elements. This element only captures
141141
/// the additional elements that are pushed during execution.
142142
pub exec_stack_elem_count_dissat: Option<usize>,
143+
/// The miniscript tree depth/height of this node.
144+
/// Used for checking the max depth of the miniscript tree to prevent stack overflow.
145+
pub tree_height: usize,
143146
}
144147

145148
impl ExtData {
@@ -155,6 +158,7 @@ impl ExtData {
155158
timelock_info: TimelockInfo::new(),
156159
exec_stack_elem_count_sat: None,
157160
exec_stack_elem_count_dissat: Some(1),
161+
tree_height: 0,
158162
};
159163

160164
/// Extra data for the `1` combinator
@@ -169,6 +173,7 @@ impl ExtData {
169173
timelock_info: TimelockInfo::new(),
170174
exec_stack_elem_count_sat: Some(1),
171175
exec_stack_elem_count_dissat: None,
176+
tree_height: 0,
172177
};
173178
}
174179

@@ -204,6 +209,7 @@ impl ExtData {
204209
timelock_info: TimelockInfo::default(),
205210
exec_stack_elem_count_sat: Some(1), // pushes the pk
206211
exec_stack_elem_count_dissat: Some(1),
212+
tree_height: 0,
207213
}
208214
}
209215

@@ -226,6 +232,7 @@ impl ExtData {
226232
timelock_info: TimelockInfo::default(),
227233
exec_stack_elem_count_sat: Some(2), // dup and hash push
228234
exec_stack_elem_count_dissat: Some(2),
235+
tree_height: 0,
229236
}
230237
}
231238

@@ -250,6 +257,7 @@ impl ExtData {
250257
timelock_info: TimelockInfo::new(),
251258
exec_stack_elem_count_sat: Some(n), // n pks
252259
exec_stack_elem_count_dissat: Some(n),
260+
tree_height: 0,
253261
}
254262
}
255263

@@ -273,6 +281,7 @@ impl ExtData {
273281
timelock_info: TimelockInfo::new(),
274282
exec_stack_elem_count_sat: Some(2), // the two nums before num equal verify
275283
exec_stack_elem_count_dissat: Some(2),
284+
tree_height: 0,
276285
}
277286
}
278287

@@ -289,6 +298,7 @@ impl ExtData {
289298
timelock_info: TimelockInfo::new(),
290299
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
291300
exec_stack_elem_count_dissat: Some(2),
301+
tree_height: 0,
292302
}
293303
}
294304

@@ -305,6 +315,7 @@ impl ExtData {
305315
timelock_info: TimelockInfo::new(),
306316
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
307317
exec_stack_elem_count_dissat: Some(2),
318+
tree_height: 0,
308319
}
309320
}
310321

@@ -321,6 +332,7 @@ impl ExtData {
321332
timelock_info: TimelockInfo::new(),
322333
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
323334
exec_stack_elem_count_dissat: Some(2),
335+
tree_height: 0,
324336
}
325337
}
326338

@@ -337,6 +349,7 @@ impl ExtData {
337349
timelock_info: TimelockInfo::new(),
338350
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
339351
exec_stack_elem_count_dissat: Some(2),
352+
tree_height: 0,
340353
}
341354
}
342355

@@ -359,6 +372,7 @@ impl ExtData {
359372
},
360373
exec_stack_elem_count_sat: Some(1), // <t>
361374
exec_stack_elem_count_dissat: None,
375+
tree_height: 0,
362376
}
363377
}
364378

@@ -381,6 +395,7 @@ impl ExtData {
381395
},
382396
exec_stack_elem_count_sat: Some(1), // <t>
383397
exec_stack_elem_count_dissat: None,
398+
tree_height: 0,
384399
}
385400
}
386401

@@ -397,6 +412,7 @@ impl ExtData {
397412
timelock_info: self.timelock_info,
398413
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
399414
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
415+
tree_height: self.tree_height + 1,
400416
}
401417
}
402418

@@ -413,6 +429,7 @@ impl ExtData {
413429
timelock_info: self.timelock_info,
414430
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
415431
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
432+
tree_height: self.tree_height + 1,
416433
}
417434
}
418435

@@ -429,6 +446,7 @@ impl ExtData {
429446
timelock_info: self.timelock_info,
430447
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
431448
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
449+
tree_height: self.tree_height + 1,
432450
}
433451
}
434452

@@ -448,6 +466,7 @@ impl ExtData {
448466
// Even all V types push something onto the stack and then remove them
449467
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
450468
exec_stack_elem_count_dissat: Some(1),
469+
tree_height: self.tree_height + 1,
451470
}
452471
}
453472

@@ -465,6 +484,7 @@ impl ExtData {
465484
timelock_info: self.timelock_info,
466485
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
467486
exec_stack_elem_count_dissat: None,
487+
tree_height: self.tree_height + 1,
468488
}
469489
}
470490

@@ -481,6 +501,7 @@ impl ExtData {
481501
timelock_info: self.timelock_info,
482502
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
483503
exec_stack_elem_count_dissat: Some(1),
504+
tree_height: self.tree_height + 1,
484505
}
485506
}
486507

@@ -498,6 +519,7 @@ impl ExtData {
498519
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
499520
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
500521
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
522+
tree_height: self.tree_height + 1,
501523
}
502524
}
503525

@@ -545,6 +567,7 @@ impl ExtData {
545567
l.exec_stack_elem_count_dissat,
546568
r.exec_stack_elem_count_dissat.map(|x| x + 1),
547569
),
570+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
548571
}
549572
}
550573

@@ -569,6 +592,7 @@ impl ExtData {
569592
r.exec_stack_elem_count_sat,
570593
),
571594
exec_stack_elem_count_dissat: None,
595+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
572596
}
573597
}
574598

@@ -609,6 +633,7 @@ impl ExtData {
609633
l.exec_stack_elem_count_dissat,
610634
r.exec_stack_elem_count_dissat.map(|x| x + 1),
611635
),
636+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
612637
}
613638
}
614639

@@ -647,6 +672,7 @@ impl ExtData {
647672
l.exec_stack_elem_count_dissat,
648673
r.exec_stack_elem_count_dissat.map(|x| x + 1),
649674
),
675+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
650676
}
651677
}
652678

@@ -678,6 +704,7 @@ impl ExtData {
678704
opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat),
679705
),
680706
exec_stack_elem_count_dissat: None,
707+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
681708
}
682709
}
683710

@@ -725,6 +752,7 @@ impl ExtData {
725752
l.exec_stack_elem_count_dissat,
726753
r.exec_stack_elem_count_dissat,
727754
),
755+
tree_height: 1 + cmp::max(l.tree_height, r.tree_height),
728756
}
729757
}
730758

@@ -768,6 +796,7 @@ impl ExtData {
768796
a.exec_stack_elem_count_dissat,
769797
c.exec_stack_elem_count_dissat,
770798
),
799+
tree_height: 1 + cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)),
771800
}
772801
}
773802

@@ -788,6 +817,7 @@ impl ExtData {
788817
// the max element count is same as max sat element count when satisfying one element + 1
789818
let mut exec_stack_elem_count_sat_vec = Vec::with_capacity(n);
790819
let mut exec_stack_elem_count_dissat = Some(0);
820+
let mut max_child_height = 0;
791821

792822
for i in 0..n {
793823
let sub = sub_ck(i);
@@ -817,6 +847,7 @@ impl ExtData {
817847
.push((sub.exec_stack_elem_count_sat, sub.exec_stack_elem_count_dissat));
818848
exec_stack_elem_count_dissat =
819849
opt_max(exec_stack_elem_count_dissat, sub.exec_stack_elem_count_dissat);
850+
max_child_height = cmp::max(max_child_height, sub.tree_height);
820851
}
821852

822853
stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
@@ -887,6 +918,7 @@ impl ExtData {
887918
timelock_info: TimelockInfo::combine_threshold(k, timelocks),
888919
exec_stack_elem_count_sat,
889920
exec_stack_elem_count_dissat,
921+
tree_height: max_child_height + 1,
890922
}
891923
}
892924

0 commit comments

Comments
 (0)