Skip to content

Commit f8a0d9e

Browse files
committed
Track miniscript tree depth explicitly
1 parent f1c1272 commit f8a0d9e

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,6 @@ mod macros;
118118
#[macro_use]
119119
mod pub_macros;
120120

121-
pub use pub_macros::*;
122-
123121
pub mod descriptor;
124122
pub mod expression;
125123
pub mod interpreter;
@@ -954,6 +952,7 @@ mod tests {
954952
}
955953
}
956954

955+
#[allow(unused_imports)] // this is an internal prelude module; not all imports are used with every feature combination
957956
mod prelude {
958957
// Mutex implementation from LDK
959958
// https://github.com/lightningdevkit/rust-lightning/blob/9bdce47f0e0516e37c89c09f1975dfc06b5870b1/lightning-invoice/src/sync.rs
@@ -1017,10 +1016,9 @@ mod prelude {
10171016
};
10181017
#[cfg(any(feature = "std", test))]
10191018
pub use std::{
1020-
borrow::{Borrow, Cow, ToOwned},
1019+
borrow::{Borrow, ToOwned},
10211020
boxed::Box,
10221021
collections::{vec_deque::VecDeque, BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet},
1023-
rc, slice,
10241022
string::{String, ToString},
10251023
sync,
10261024
sync::Mutex,

src/miniscript/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use bitcoin::util::taproot::{LeafVersion, TapLeafHash};
3232

3333
use self::analyzable::ExtParams;
3434
pub use self::context::{BareCtx, Legacy, Segwitv0, Tap};
35-
use crate::prelude::*;
35+
use crate::{prelude::*, MAX_RECURSION_DEPTH};
3636

3737
pub mod analyzable;
3838
pub mod astelem;
@@ -121,12 +121,21 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
121121
/// `AstElem` fragment. Dependent on display and clone because of Error
122122
/// Display code of type_check.
123123
pub fn from_ast(t: Terminal<Pk, Ctx>) -> Result<Miniscript<Pk, Ctx>, Error> {
124-
Ok(Miniscript {
124+
let res = Miniscript {
125125
ty: Type::type_check(&t, |_| None)?,
126126
ext: ExtData::type_check(&t, |_| None)?,
127127
node: t,
128128
phantom: PhantomData,
129-
})
129+
};
130+
// TODO: This recursion depth is based on segwitv0.
131+
// We can relax this in tapscript, but this should be good for almost
132+
// all practical cases and we can revisit this if needed.
133+
// casting to u32 is safe because tree_height will never go more than u32::MAX
134+
if (res.ext.tree_height as u32) > MAX_RECURSION_DEPTH {
135+
Err(Error::MaxRecursiveDepthExceeded)
136+
} else {
137+
Ok(res)
138+
}
130139
}
131140
}
132141

src/miniscript/types/extra_props.rs

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

142145
impl Property for ExtData {
@@ -163,6 +166,7 @@ impl Property for ExtData {
163166
timelock_info: TimelockInfo::default(),
164167
exec_stack_elem_count_sat: Some(1),
165168
exec_stack_elem_count_dissat: None,
169+
tree_height : 0,
166170
}
167171
}
168172

@@ -178,6 +182,7 @@ impl Property for ExtData {
178182
timelock_info: TimelockInfo::default(),
179183
exec_stack_elem_count_sat: None,
180184
exec_stack_elem_count_dissat: Some(1),
185+
tree_height : 0,
181186
}
182187
}
183188

@@ -199,6 +204,7 @@ impl Property for ExtData {
199204
timelock_info: TimelockInfo::default(),
200205
exec_stack_elem_count_sat: Some(1), // pushes the pk
201206
exec_stack_elem_count_dissat: Some(1),
207+
tree_height: 0,
202208
}
203209
}
204210

@@ -220,6 +226,7 @@ impl Property for ExtData {
220226
timelock_info: TimelockInfo::default(),
221227
exec_stack_elem_count_sat: Some(2), // dup and hash push
222228
exec_stack_elem_count_dissat: Some(2),
229+
tree_height: 0,
223230
}
224231
}
225232

@@ -243,6 +250,7 @@ impl Property for ExtData {
243250
timelock_info: TimelockInfo::default(),
244251
exec_stack_elem_count_sat: Some(n), // n pks
245252
exec_stack_elem_count_dissat: Some(n),
253+
tree_height: 0,
246254
}
247255
}
248256

@@ -265,6 +273,7 @@ impl Property for ExtData {
265273
timelock_info: TimelockInfo::default(),
266274
exec_stack_elem_count_sat: Some(2), // the two nums before num equal verify
267275
exec_stack_elem_count_dissat: Some(2),
276+
tree_height: 0,
268277
}
269278
}
270279

@@ -285,6 +294,7 @@ impl Property for ExtData {
285294
timelock_info: TimelockInfo::default(),
286295
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
287296
exec_stack_elem_count_dissat: Some(2),
297+
tree_height: 0,
288298
}
289299
}
290300

@@ -300,6 +310,7 @@ impl Property for ExtData {
300310
timelock_info: TimelockInfo::default(),
301311
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
302312
exec_stack_elem_count_dissat: Some(2),
313+
tree_height: 0,
303314
}
304315
}
305316

@@ -315,6 +326,7 @@ impl Property for ExtData {
315326
timelock_info: TimelockInfo::default(),
316327
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
317328
exec_stack_elem_count_dissat: Some(2),
329+
tree_height: 0,
318330
}
319331
}
320332

@@ -330,6 +342,7 @@ impl Property for ExtData {
330342
timelock_info: TimelockInfo::default(),
331343
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
332344
exec_stack_elem_count_dissat: Some(2),
345+
tree_height: 0,
333346
}
334347
}
335348

@@ -355,6 +368,7 @@ impl Property for ExtData {
355368
},
356369
exec_stack_elem_count_sat: Some(1), // <t>
357370
exec_stack_elem_count_dissat: None,
371+
tree_height: 0,
358372
}
359373
}
360374

@@ -376,6 +390,7 @@ impl Property for ExtData {
376390
},
377391
exec_stack_elem_count_sat: Some(1), // <t>
378392
exec_stack_elem_count_dissat: None,
393+
tree_height: 0,
379394
}
380395
}
381396

@@ -391,6 +406,7 @@ impl Property for ExtData {
391406
timelock_info: self.timelock_info,
392407
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
393408
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
409+
tree_height : self.tree_height + 1,
394410
})
395411
}
396412

@@ -406,6 +422,7 @@ impl Property for ExtData {
406422
timelock_info: self.timelock_info,
407423
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
408424
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
425+
tree_height : self.tree_height + 1,
409426
})
410427
}
411428

@@ -421,6 +438,7 @@ impl Property for ExtData {
421438
timelock_info: self.timelock_info,
422439
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
423440
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
441+
tree_height : self.tree_height + 1,
424442
})
425443
}
426444

@@ -439,6 +457,7 @@ impl Property for ExtData {
439457
// Even all V types push something onto the stack and then remove them
440458
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
441459
exec_stack_elem_count_dissat: Some(1),
460+
tree_height : self.tree_height + 1,
442461
})
443462
}
444463

@@ -455,6 +474,7 @@ impl Property for ExtData {
455474
timelock_info: self.timelock_info,
456475
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
457476
exec_stack_elem_count_dissat: None,
477+
tree_height : self.tree_height + 1,
458478
})
459479
}
460480

@@ -470,6 +490,7 @@ impl Property for ExtData {
470490
timelock_info: self.timelock_info,
471491
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
472492
exec_stack_elem_count_dissat: Some(1),
493+
tree_height : self.tree_height + 1,
473494
})
474495
}
475496

@@ -486,6 +507,7 @@ impl Property for ExtData {
486507
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
487508
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
488509
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
510+
tree_height : self.tree_height + 1,
489511
})
490512
}
491513

@@ -526,6 +548,7 @@ impl Property for ExtData {
526548
l.exec_stack_elem_count_dissat,
527549
r.exec_stack_elem_count_dissat.map(|x| x + 1),
528550
),
551+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
529552
})
530553
}
531554

@@ -553,6 +576,7 @@ impl Property for ExtData {
553576
r.exec_stack_elem_count_sat,
554577
),
555578
exec_stack_elem_count_dissat: None,
579+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
556580
})
557581
}
558582

@@ -601,6 +625,7 @@ impl Property for ExtData {
601625
l.exec_stack_elem_count_dissat,
602626
r.exec_stack_elem_count_dissat.map(|x| x + 1),
603627
),
628+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
604629
})
605630
}
606631

@@ -638,6 +663,7 @@ impl Property for ExtData {
638663
l.exec_stack_elem_count_dissat,
639664
r.exec_stack_elem_count_dissat.map(|x| x + 1),
640665
),
666+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
641667
};
642668
Ok(res)
643669
}
@@ -669,6 +695,7 @@ impl Property for ExtData {
669695
opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat),
670696
),
671697
exec_stack_elem_count_dissat: None,
698+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
672699
})
673700
}
674701

@@ -716,6 +743,7 @@ impl Property for ExtData {
716743
l.exec_stack_elem_count_dissat,
717744
r.exec_stack_elem_count_dissat,
718745
),
746+
tree_height : cmp::max(l.tree_height, r.tree_height) + 1,
719747
})
720748
}
721749

@@ -761,6 +789,7 @@ impl Property for ExtData {
761789
a.exec_stack_elem_count_dissat,
762790
c.exec_stack_elem_count_dissat,
763791
),
792+
tree_height : cmp::max(a.tree_height, cmp::max(b.tree_height, c.tree_height)) + 1,
764793
})
765794
}
766795

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

784814
for i in 0..n {
785815
let sub = sub_ck(i)?;
@@ -813,6 +843,7 @@ impl Property for ExtData {
813843
exec_stack_elem_count_dissat,
814844
sub.exec_stack_elem_count_dissat,
815845
);
846+
max_child_height = cmp::max(max_child_height, sub.tree_height) + 1;
816847
}
817848

818849
stack_elem_count_sat_vec.sort_by(sat_minus_option_dissat);
@@ -884,6 +915,7 @@ impl Property for ExtData {
884915
timelock_info: TimelockInfo::combine_threshold(k, timelocks),
885916
exec_stack_elem_count_sat,
886917
exec_stack_elem_count_dissat,
918+
tree_height : max_child_height + 1,
887919
})
888920
}
889921

tests/test_cpp.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,13 @@ pub fn test_from_cpp_ms(cl: &Client, testdata: &TestData) {
239239
}
240240

241241
#[test]
242+
#[ignore = "bitcoind crate breaking change"]
242243
fn test_setup() {
243244
setup::setup();
244245
}
245246

246247
#[test]
248+
#[ignore = "bitcoind crate breaking change"]
247249
fn tests_from_cpp() {
248250
let cl = &setup::setup().client;
249251
let testdata = TestData::new_fixed_data(50);

tests/test_desc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ fn test_descs(cl: &Client, testdata: &TestData) {
424424
}
425425

426426
#[test]
427+
#[ignore = "bitcoind crate made a breaking change"]
427428
fn test_satisfy() {
428429
let testdata = TestData::new_fixed_data(50);
429430
let cl = &setup::setup().client;

0 commit comments

Comments
 (0)