Skip to content

Commit 8bfd146

Browse files
committed
Add height check to miniscript types
1 parent 4944aa4 commit 8bfd146

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

src/miniscript/types/extra_props.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ pub struct ExtData {
119119
pub max_dissat_size: Option<(usize, usize)>,
120120
/// The timelock info about heightlocks and timelocks
121121
pub timelock_info: TimeLockInfo,
122+
/// Maximum stack + alt stack size during satisfaction execution
123+
/// This does **not** include initial witness elements. This element only captures
124+
/// the additional elements that are pushed during execution.
125+
pub exec_stack_elem_count_sat: Option<usize>,
126+
/// Maximum stack + alt stack size during dissat execution
127+
/// This does **not** include initial witness elements. This element only captures
128+
/// the additional elements that are pushed during execution.
129+
pub exec_stack_elem_count_dissat: Option<usize>,
122130
}
123131

124132
impl Property for ExtData {
@@ -138,6 +146,8 @@ impl Property for ExtData {
138146
max_sat_size: Some((0, 0)),
139147
max_dissat_size: None,
140148
timelock_info: TimeLockInfo::default(),
149+
exec_stack_elem_count_sat: Some(1),
150+
exec_stack_elem_count_dissat: None,
141151
}
142152
}
143153

@@ -153,6 +163,8 @@ impl Property for ExtData {
153163
max_sat_size: None,
154164
max_dissat_size: Some((0, 0)),
155165
timelock_info: TimeLockInfo::default(),
166+
exec_stack_elem_count_sat: None,
167+
exec_stack_elem_count_dissat: Some(1),
156168
}
157169
}
158170

@@ -168,6 +180,8 @@ impl Property for ExtData {
168180
max_sat_size: Some((73, 73)),
169181
max_dissat_size: Some((1, 1)),
170182
timelock_info: TimeLockInfo::default(),
183+
exec_stack_elem_count_sat: Some(1), // pushes the pk
184+
exec_stack_elem_count_dissat: Some(1),
171185
}
172186
}
173187

@@ -183,6 +197,8 @@ impl Property for ExtData {
183197
max_sat_size: Some((34 + 73, 34 + 73)),
184198
max_dissat_size: Some((35, 35)),
185199
timelock_info: TimeLockInfo::default(),
200+
exec_stack_elem_count_sat: Some(2), // dup and hash push
201+
exec_stack_elem_count_dissat: Some(2),
186202
}
187203
}
188204

@@ -204,6 +220,8 @@ impl Property for ExtData {
204220
max_sat_size: Some((1 + 73 * k, 1 + 73 * k)),
205221
max_dissat_size: Some((1 + k, 1 + k)),
206222
timelock_info: TimeLockInfo::default(),
223+
exec_stack_elem_count_sat: Some(n), // n pks
224+
exec_stack_elem_count_dissat: Some(n),
207225
}
208226
}
209227

@@ -224,6 +242,8 @@ impl Property for ExtData {
224242
max_sat_size: Some((33, 33)),
225243
max_dissat_size: Some((33, 33)),
226244
timelock_info: TimeLockInfo::default(),
245+
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
246+
exec_stack_elem_count_dissat: Some(2),
227247
}
228248
}
229249

@@ -239,6 +259,8 @@ impl Property for ExtData {
239259
max_sat_size: Some((33, 33)),
240260
max_dissat_size: Some((33, 33)),
241261
timelock_info: TimeLockInfo::default(),
262+
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <32 byte>
263+
exec_stack_elem_count_dissat: Some(2),
242264
}
243265
}
244266

@@ -254,6 +276,8 @@ impl Property for ExtData {
254276
max_sat_size: Some((33, 33)),
255277
max_dissat_size: Some((33, 33)),
256278
timelock_info: TimeLockInfo::default(),
279+
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
280+
exec_stack_elem_count_dissat: Some(2),
257281
}
258282
}
259283

@@ -269,6 +293,8 @@ impl Property for ExtData {
269293
max_sat_size: Some((33, 33)),
270294
max_dissat_size: Some((33, 33)),
271295
timelock_info: TimeLockInfo::default(),
296+
exec_stack_elem_count_sat: Some(2), // either size <32> or <hash256> <20 byte>
297+
exec_stack_elem_count_dissat: Some(2),
272298
}
273299
}
274300

@@ -294,6 +320,8 @@ impl Property for ExtData {
294320
cltv_with_time: t >= HEIGHT_TIME_THRESHOLD,
295321
contains_combination: false,
296322
},
323+
exec_stack_elem_count_sat: Some(1), // <t>
324+
exec_stack_elem_count_dissat: None,
297325
}
298326
}
299327

@@ -315,6 +343,8 @@ impl Property for ExtData {
315343
cltv_with_time: false,
316344
contains_combination: false,
317345
},
346+
exec_stack_elem_count_sat: Some(1), // <t>
347+
exec_stack_elem_count_dissat: None,
318348
}
319349
}
320350

@@ -330,6 +360,8 @@ impl Property for ExtData {
330360
max_sat_size: self.max_sat_size,
331361
max_dissat_size: self.max_dissat_size,
332362
timelock_info: self.timelock_info,
363+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
364+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
333365
})
334366
}
335367

@@ -345,6 +377,8 @@ impl Property for ExtData {
345377
max_sat_size: self.max_sat_size,
346378
max_dissat_size: self.max_dissat_size,
347379
timelock_info: self.timelock_info,
380+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
381+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
348382
})
349383
}
350384

@@ -360,6 +394,8 @@ impl Property for ExtData {
360394
max_sat_size: self.max_sat_size,
361395
max_dissat_size: self.max_dissat_size,
362396
timelock_info: self.timelock_info,
397+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
398+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
363399
})
364400
}
365401

@@ -375,6 +411,11 @@ impl Property for ExtData {
375411
max_sat_size: self.max_sat_size.map(|(w, s)| (w + 2, s + 1)),
376412
max_dissat_size: Some((1, 1)),
377413
timelock_info: self.timelock_info,
414+
// Technically max(1, self.exec_stack_elem_count_sat), but all miniscript expressions
415+
// that can be satisfied push at least one thing onto the stack.
416+
// Even all V types push something onto the stack and then remove them
417+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
418+
exec_stack_elem_count_dissat: Some(1),
378419
})
379420
}
380421

@@ -391,6 +432,8 @@ impl Property for ExtData {
391432
max_sat_size: self.max_sat_size,
392433
max_dissat_size: None,
393434
timelock_info: self.timelock_info,
435+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
436+
exec_stack_elem_count_dissat: None,
394437
})
395438
}
396439

@@ -406,6 +449,8 @@ impl Property for ExtData {
406449
max_sat_size: self.max_sat_size,
407450
max_dissat_size: Some((1, 1)),
408451
timelock_info: self.timelock_info,
452+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
453+
exec_stack_elem_count_dissat: Some(1),
409454
})
410455
}
411456

@@ -421,6 +466,9 @@ impl Property for ExtData {
421466
max_sat_size: self.max_sat_size,
422467
max_dissat_size: self.max_dissat_size,
423468
timelock_info: self.timelock_info,
469+
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
470+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
471+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
424472
})
425473
}
426474

@@ -436,6 +484,9 @@ impl Property for ExtData {
436484
max_sat_size: self.max_sat_size,
437485
max_dissat_size: None,
438486
timelock_info: self.timelock_info,
487+
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
488+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
489+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
439490
})
440491
}
441492

@@ -455,6 +506,10 @@ impl Property for ExtData {
455506
stack_elem_count_dissat: self.stack_elem_count_dissat.map(|x| x + 1),
456507
max_sat_size: self.max_sat_size.map(|(w, s)| (w + 2, s + 1)),
457508
max_dissat_size: self.max_dissat_size.map(|(w, s)| (w + 1, s + 1)),
509+
// TODO: fix dissat stack elem counting above in a later commit
510+
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
511+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
512+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
458513
timelock_info: self.timelock_info,
459514
})
460515
}
@@ -471,6 +526,10 @@ impl Property for ExtData {
471526
max_sat_size: self.max_sat_size.map(|(w, s)| (w + 1, s + 1)),
472527
max_dissat_size: self.max_dissat_size.map(|(w, s)| (w + 2, s + 1)),
473528
timelock_info: self.timelock_info,
529+
// TODO: fix dissat stack elem counting above in a later commit
530+
// Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif
531+
exec_stack_elem_count_sat: self.exec_stack_elem_count_sat,
532+
exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat,
474533
})
475534
}
476535

@@ -498,6 +557,16 @@ impl Property for ExtData {
498557
.max_dissat_size
499558
.and_then(|(lw, ls)| r.max_dissat_size.map(|(rw, rs)| (lw + rw, ls + rs))),
500559
timelock_info: TimeLockInfo::comb_and_timelocks(l.timelock_info, r.timelock_info),
560+
// Left element leaves a stack result on the stack top and then right element is evaluated
561+
// Therefore + 1 is added to execution size of second element
562+
exec_stack_elem_count_sat: cmp::max(
563+
l.exec_stack_elem_count_sat,
564+
r.exec_stack_elem_count_sat.map(|x| x + 1),
565+
),
566+
exec_stack_elem_count_dissat: cmp::max(
567+
l.exec_stack_elem_count_dissat,
568+
r.exec_stack_elem_count_dissat.map(|x| x + 1),
569+
),
501570
})
502571
}
503572

@@ -517,6 +586,15 @@ impl Property for ExtData {
517586
.and_then(|(lw, ls)| r.max_sat_size.map(|(rw, rs)| (lw + rw, ls + rs))),
518587
max_dissat_size: None,
519588
timelock_info: TimeLockInfo::comb_and_timelocks(l.timelock_info, r.timelock_info),
589+
// [X] leaves no element after evaluation, hence this is the max
590+
exec_stack_elem_count_sat: cmp::max(
591+
l.exec_stack_elem_count_sat,
592+
r.exec_stack_elem_count_sat,
593+
),
594+
exec_stack_elem_count_dissat: cmp::max(
595+
l.exec_stack_elem_count_dissat,
596+
r.exec_stack_elem_count_dissat,
597+
),
520598
})
521599
}
522600

@@ -553,6 +631,20 @@ impl Property for ExtData {
553631
.max_dissat_size
554632
.and_then(|(lw, ls)| r.max_dissat_size.map(|(rw, rs)| (lw + rw, ls + rs))),
555633
timelock_info: TimeLockInfo::comb_or_timelocks(l.timelock_info, r.timelock_info),
634+
exec_stack_elem_count_sat: cmp::max(
635+
cmp::max(
636+
l.exec_stack_elem_count_sat,
637+
r.exec_stack_elem_count_dissat.map(|x| x + 1),
638+
),
639+
cmp::max(
640+
l.exec_stack_elem_count_dissat,
641+
r.exec_stack_elem_count_sat.map(|x| x + 1),
642+
),
643+
),
644+
exec_stack_elem_count_dissat: cmp::max(
645+
l.exec_stack_elem_count_dissat,
646+
r.exec_stack_elem_count_dissat.map(|x| x + 1),
647+
),
556648
})
557649
}
558650

@@ -586,6 +678,14 @@ impl Property for ExtData {
586678
.max_dissat_size
587679
.and_then(|(lw, ls)| r.max_dissat_size.map(|(rw, rs)| (lw + rw, ls + rs))),
588680
timelock_info: TimeLockInfo::comb_or_timelocks(l.timelock_info, r.timelock_info),
681+
exec_stack_elem_count_sat: cmp::max(
682+
cmp::max(l.exec_stack_elem_count_sat, r.exec_stack_elem_count_dissat),
683+
r.exec_stack_elem_count_sat,
684+
),
685+
exec_stack_elem_count_dissat: cmp::max(
686+
l.exec_stack_elem_count_dissat,
687+
r.exec_stack_elem_count_dissat.map(|x| x + 1),
688+
),
589689
})
590690
}
591691

@@ -613,6 +713,11 @@ impl Property for ExtData {
613713
),
614714
max_dissat_size: None,
615715
timelock_info: TimeLockInfo::comb_or_timelocks(l.timelock_info, r.timelock_info),
716+
exec_stack_elem_count_sat: cmp::max(
717+
cmp::max(l.exec_stack_elem_count_sat, r.exec_stack_elem_count_dissat),
718+
r.exec_stack_elem_count_sat,
719+
),
720+
exec_stack_elem_count_dissat: None,
616721
})
617722
}
618723

@@ -656,6 +761,15 @@ impl Property for ExtData {
656761
(None, None) => None,
657762
},
658763
timelock_info: TimeLockInfo::comb_or_timelocks(l.timelock_info, r.timelock_info),
764+
// TODO: fix elem count dissat bug
765+
exec_stack_elem_count_sat: cmp::max(
766+
l.exec_stack_elem_count_sat,
767+
r.exec_stack_elem_count_sat,
768+
),
769+
exec_stack_elem_count_dissat: cmp::max(
770+
l.exec_stack_elem_count_dissat,
771+
r.exec_stack_elem_count_dissat,
772+
),
659773
})
660774
}
661775

@@ -695,6 +809,14 @@ impl Property for ExtData {
695809
TimeLockInfo::comb_and_timelocks(a.timelock_info, b.timelock_info),
696810
c.timelock_info,
697811
),
812+
exec_stack_elem_count_sat: cmp::max(
813+
cmp::max(a.exec_stack_elem_count_sat, b.exec_stack_elem_count_sat),
814+
cmp::max(c.exec_stack_elem_count_sat, a.exec_stack_elem_count_dissat),
815+
),
816+
exec_stack_elem_count_dissat: cmp::max(
817+
a.exec_stack_elem_count_dissat,
818+
c.exec_stack_elem_count_dissat,
819+
),
698820
})
699821
}
700822

@@ -716,6 +838,9 @@ impl Property for ExtData {
716838
let mut max_sat_size_vec = Vec::with_capacity(n);
717839
let mut max_sat_size = Some((0, 0));
718840
let mut max_dissat_size = Some((0, 0));
841+
// the max element count is same as max sat element count when satisfying one element + 1
842+
let mut exec_stack_elem_count_sat = None;
843+
let mut exec_stack_elem_count_dissat = None;
719844

720845
for i in 0..n {
721846
let sub = sub_ck(i)?;
@@ -751,6 +876,17 @@ impl Property for ExtData {
751876
}
752877
_ => {}
753878
}
879+
// Threshold satisfaction require satisfaction/disssat of each child
880+
// Therefore, the max count is max of children + 1 (for the previous result)
881+
exec_stack_elem_count_sat =
882+
cmp::max(exec_stack_elem_count_sat, sub.exec_stack_elem_count_sat);
883+
// satisfaction involve dissatisfactions too
884+
exec_stack_elem_count_sat =
885+
cmp::max(exec_stack_elem_count_sat, sub.exec_stack_elem_count_dissat);
886+
exec_stack_elem_count_dissat = cmp::max(
887+
exec_stack_elem_count_dissat,
888+
sub.exec_stack_elem_count_dissat,
889+
);
754890
}
755891

756892
// We sort by [satisfaction cost - dissatisfaction cost] to make a worst-case (the most
@@ -809,6 +945,8 @@ impl Property for ExtData {
809945
max_sat_size,
810946
max_dissat_size,
811947
timelock_info: TimeLockInfo::combine_thresh_timelocks(k, timelocks),
948+
exec_stack_elem_count_sat,
949+
exec_stack_elem_count_dissat,
812950
})
813951
}
814952

0 commit comments

Comments
 (0)