Skip to content

Commit 20b961a

Browse files
committed
Track miniscript tree depth explicitly
1 parent ab279b2 commit 20b961a

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ mod tests {
898898
}
899899
}
900900

901+
#[allow(unused_imports)] // this is an internal prelude module; not all imports are used with every feature combination
901902
mod prelude {
902903
// Mutex implementation from LDK
903904
// https://github.com/lightningdevkit/rust-lightning/blob/9bdce47f0e0516e37c89c09f1975dfc06b5870b1/lightning-invoice/src/sync.rs

src/miniscript/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use bitcoin::taproot::{LeafVersion, TapLeafHash};
2121

2222
use self::analyzable::ExtParams;
2323
pub use self::context::{BareCtx, Legacy, Segwitv0, Tap};
24-
use crate::prelude::*;
24+
use crate::{prelude::*, MAX_RECURSION_DEPTH};
2525
use crate::TranslateErr;
2626

2727
pub mod analyzable;
@@ -116,6 +116,13 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
116116
node: t,
117117
phantom: PhantomData,
118118
};
119+
// TODO: This recursion depth is based on segwitv0.
120+
// We can relax this in tapscript, but this should be good for almost
121+
// all practical cases and we can revisit this if needed.
122+
// casting to u32 is safe because tree_height will never go more than u32::MAX
123+
if (res.ext.tree_height as u32) > MAX_RECURSION_DEPTH {
124+
return Err(Error::MaxRecursiveDepthExceeded);
125+
}
119126
Ctx::check_global_consensus_validity(&res)?;
120127
Ok(res)
121128
}

src/miniscript/types/extra_props.rs

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

144147
impl Property for ExtData {
@@ -165,6 +168,7 @@ impl Property for ExtData {
165168
timelock_info: TimelockInfo::default(),
166169
exec_stack_elem_count_sat: Some(1),
167170
exec_stack_elem_count_dissat: None,
171+
tree_height : 0,
168172
}
169173
}
170174

@@ -180,6 +184,7 @@ impl Property for ExtData {
180184
timelock_info: TimelockInfo::default(),
181185
exec_stack_elem_count_sat: None,
182186
exec_stack_elem_count_dissat: Some(1),
187+
tree_height : 0,
183188
}
184189
}
185190

@@ -201,6 +206,7 @@ impl Property for ExtData {
201206
timelock_info: TimelockInfo::default(),
202207
exec_stack_elem_count_sat: Some(1), // pushes the pk
203208
exec_stack_elem_count_dissat: Some(1),
209+
tree_height: 0,
204210
}
205211
}
206212

@@ -222,6 +228,7 @@ impl Property for ExtData {
222228
timelock_info: TimelockInfo::default(),
223229
exec_stack_elem_count_sat: Some(2), // dup and hash push
224230
exec_stack_elem_count_dissat: Some(2),
231+
tree_height: 0,
225232
}
226233
}
227234

@@ -245,6 +252,7 @@ impl Property for ExtData {
245252
timelock_info: TimelockInfo::default(),
246253
exec_stack_elem_count_sat: Some(n), // n pks
247254
exec_stack_elem_count_dissat: Some(n),
255+
tree_height: 0,
248256
}
249257
}
250258

@@ -267,6 +275,7 @@ impl Property for ExtData {
267275
timelock_info: TimelockInfo::default(),
268276
exec_stack_elem_count_sat: Some(2), // the two nums before num equal verify
269277
exec_stack_elem_count_dissat: Some(2),
278+
tree_height: 0,
270279
}
271280
}
272281

@@ -287,6 +296,7 @@ impl Property for ExtData {
287296
timelock_info: TimelockInfo::default(),
288297
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
289298
exec_stack_elem_count_dissat: Some(2),
299+
tree_height: 0,
290300
}
291301
}
292302

@@ -302,6 +312,7 @@ impl Property for ExtData {
302312
timelock_info: TimelockInfo::default(),
303313
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
304314
exec_stack_elem_count_dissat: Some(2),
315+
tree_height: 0,
305316
}
306317
}
307318

@@ -317,6 +328,7 @@ impl Property for ExtData {
317328
timelock_info: TimelockInfo::default(),
318329
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
319330
exec_stack_elem_count_dissat: Some(2),
331+
tree_height: 0,
320332
}
321333
}
322334

@@ -332,6 +344,7 @@ impl Property for ExtData {
332344
timelock_info: TimelockInfo::default(),
333345
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
334346
exec_stack_elem_count_dissat: Some(2),
347+
tree_height: 0,
335348
}
336349
}
337350

@@ -357,6 +370,7 @@ impl Property for ExtData {
357370
},
358371
exec_stack_elem_count_sat: Some(1), // <t>
359372
exec_stack_elem_count_dissat: None,
373+
tree_height: 0,
360374
}
361375
}
362376

@@ -378,6 +392,7 @@ impl Property for ExtData {
378392
},
379393
exec_stack_elem_count_sat: Some(1), // <t>
380394
exec_stack_elem_count_dissat: None,
395+
tree_height: 0,
381396
}
382397
}
383398

@@ -393,6 +408,7 @@ impl Property for ExtData {
393408
timelock_info: self.timelock_info,
394409
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
395410
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
411+
tree_height : self.tree_height + 1,
396412
})
397413
}
398414

@@ -408,6 +424,7 @@ impl Property for ExtData {
408424
timelock_info: self.timelock_info,
409425
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
410426
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
427+
tree_height : self.tree_height + 1,
411428
})
412429
}
413430

@@ -423,6 +440,7 @@ impl Property for ExtData {
423440
timelock_info: self.timelock_info,
424441
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
425442
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
443+
tree_height : self.tree_height + 1,
426444
})
427445
}
428446

@@ -441,6 +459,7 @@ impl Property for ExtData {
441459
// Even all V types push something onto the stack and then remove them
442460
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
443461
exec_stack_elem_count_dissat: Some(1),
462+
tree_height : self.tree_height + 1,
444463
})
445464
}
446465

@@ -457,6 +476,7 @@ impl Property for ExtData {
457476
timelock_info: self.timelock_info,
458477
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
459478
exec_stack_elem_count_dissat: None,
479+
tree_height : self.tree_height + 1,
460480
})
461481
}
462482

@@ -472,6 +492,7 @@ impl Property for ExtData {
472492
timelock_info: self.timelock_info,
473493
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
474494
exec_stack_elem_count_dissat: Some(1),
495+
tree_height : self.tree_height + 1,
475496
})
476497
}
477498

@@ -488,6 +509,7 @@ impl Property for ExtData {
488509
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
489510
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
490511
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
512+
tree_height : self.tree_height + 1,
491513
})
492514
}
493515

@@ -528,6 +550,7 @@ impl Property for ExtData {
528550
l.exec_stack_elem_count_dissat,
529551
r.exec_stack_elem_count_dissat.map(|x| x + 1),
530552
),
553+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
531554
})
532555
}
533556

@@ -555,6 +578,7 @@ impl Property for ExtData {
555578
r.exec_stack_elem_count_sat,
556579
),
557580
exec_stack_elem_count_dissat: None,
581+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
558582
})
559583
}
560584

@@ -603,6 +627,7 @@ impl Property for ExtData {
603627
l.exec_stack_elem_count_dissat,
604628
r.exec_stack_elem_count_dissat.map(|x| x + 1),
605629
),
630+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
606631
})
607632
}
608633

@@ -640,6 +665,7 @@ impl Property for ExtData {
640665
l.exec_stack_elem_count_dissat,
641666
r.exec_stack_elem_count_dissat.map(|x| x + 1),
642667
),
668+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
643669
};
644670
Ok(res)
645671
}
@@ -671,6 +697,7 @@ impl Property for ExtData {
671697
opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat),
672698
),
673699
exec_stack_elem_count_dissat: None,
700+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
674701
})
675702
}
676703

@@ -717,6 +744,7 @@ impl Property for ExtData {
717744
l.exec_stack_elem_count_dissat,
718745
r.exec_stack_elem_count_dissat,
719746
),
747+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
720748
})
721749
}
722750

@@ -762,6 +790,7 @@ impl Property for ExtData {
762790
a.exec_stack_elem_count_dissat,
763791
c.exec_stack_elem_count_dissat,
764792
),
793+
tree_height : cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)) + 1,
765794
})
766795
}
767796

@@ -781,6 +810,7 @@ impl Property for ExtData {
781810
// the max element count is same as max sat element count when satisfying one element + 1
782811
let mut exec_stack_elem_count_sat_vec = Vec::with_capacity(n);
783812
let mut exec_stack_elem_count_dissat = Some(0);
813+
let mut max_child_height = 0;
784814

785815
for i in 0..n {
786816
let sub = sub_ck(i)?;
@@ -814,6 +844,7 @@ impl Property for ExtData {
814844
exec_stack_elem_count_dissat,
815845
sub.exec_stack_elem_count_dissat,
816846
);
847+
max_child_height = cmp::max(max_child_height, sub.tree_height) + 1;
817848
}
818849

819850
stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
@@ -885,6 +916,7 @@ impl Property for ExtData {
885916
timelock_info: TimelockInfo::combine_threshold(k, timelocks),
886917
exec_stack_elem_count_sat,
887918
exec_stack_elem_count_dissat,
919+
tree_height : max_child_height + 1,
888920
})
889921
}
890922

0 commit comments

Comments
 (0)