4
4
use super :: { Error , ErrorKind , Property , ScriptContext } ;
5
5
use script_num_size;
6
6
use std:: cmp;
7
+ use std:: iter:: once;
7
8
use MiniscriptKey ;
8
9
use Terminal ;
9
10
10
11
pub const MAX_OPS_PER_SCRIPT : usize = 201 ;
12
+ // https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39
13
+ pub const HEIGHT_TIME_THRESHOLD : u32 = 500_000_000 ;
14
+
15
+ /// Helper struct Whether any satisfaction of this fragment contains any timelocks
16
+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Debug , Hash ) ]
17
+ pub struct TimeLockInfo {
18
+ // csv with heights
19
+ pub csv_with_height : bool ,
20
+ /// csv with times
21
+ pub csv_with_time : bool ,
22
+ /// cltv with heights
23
+ pub cltv_with_height : bool ,
24
+ /// cltv with times
25
+ pub cltv_with_time : bool ,
26
+ /// combination of any heightlocks and timelocks
27
+ pub contains_combination : bool ,
28
+ }
29
+
30
+ impl Default for TimeLockInfo {
31
+ fn default ( ) -> Self {
32
+ Self {
33
+ csv_with_height : false ,
34
+ csv_with_time : false ,
35
+ cltv_with_height : false ,
36
+ cltv_with_time : false ,
37
+ contains_combination : false ,
38
+ }
39
+ }
40
+ }
41
+
42
+ impl TimeLockInfo {
43
+ /// Whether the current contains any possible unspendable
44
+ /// path
45
+ pub fn contains_unspendable_path ( self ) -> bool {
46
+ self . contains_combination
47
+ }
48
+
49
+ // handy function for combining `and` timelocks
50
+ // This can be operator overloaded in future
51
+ pub ( crate ) fn comb_and_timelocks ( a : Self , b : Self ) -> Self {
52
+ Self :: combine_thresh_timelocks ( 2 , once ( a) . chain ( once ( b) ) )
53
+ }
54
+
55
+ // handy function for combining `or` timelocks
56
+ // This can be operator overloaded in future
57
+ pub ( crate ) fn comb_or_timelocks ( a : Self , b : Self ) -> Self {
58
+ Self :: combine_thresh_timelocks ( 1 , once ( a) . chain ( once ( b) ) )
59
+ }
60
+
61
+ pub ( crate ) fn combine_thresh_timelocks < I > ( k : usize , sub_timelocks : I ) -> TimeLockInfo
62
+ where
63
+ I : IntoIterator < Item = TimeLockInfo > ,
64
+ {
65
+ // timelocks calculation
66
+ // Propagate all fields of `TimelockInfo` from each of the node's children to the node
67
+ // itself (by taking the logical-or of all of them). In case `k == 1` (this is a disjunction)
68
+ // this is all we need to do: the node may behave like any of its children, for purposes
69
+ // of timelock accounting.
70
+ //
71
+ // If `k > 1` we have the additional consideration that if any two children have conflicting
72
+ // timelock requirements, this represents an inaccessible spending branch.
73
+ sub_timelocks. into_iter ( ) . fold (
74
+ TimeLockInfo :: default ( ) ,
75
+ |mut timelock_info, sub_timelock| {
76
+ // If more than one branch may be taken, and some other branch has a requirement
77
+ // that conflicts with this one, set `contains_combination`
78
+ if k >= 2 {
79
+ timelock_info. contains_combination |= ( timelock_info. csv_with_height
80
+ && sub_timelock. csv_with_time )
81
+ || ( timelock_info. csv_with_time && sub_timelock. csv_with_height )
82
+ || ( timelock_info. cltv_with_time && sub_timelock. cltv_with_height )
83
+ || ( timelock_info. cltv_with_height && sub_timelock. cltv_with_time ) ;
84
+ }
85
+ timelock_info. csv_with_height |= sub_timelock. csv_with_height ;
86
+ timelock_info. csv_with_time |= sub_timelock. csv_with_time ;
87
+ timelock_info. cltv_with_height |= sub_timelock. cltv_with_height ;
88
+ timelock_info. cltv_with_time |= sub_timelock. cltv_with_time ;
89
+ timelock_info. contains_combination |= sub_timelock. contains_combination ;
90
+ timelock_info
91
+ } ,
92
+ )
93
+ }
94
+ }
11
95
12
96
/// Structure representing the extra type properties of a fragment which are
13
97
/// relevant to legacy(pre-segwit) safety and fee estimation. If a fragment is
@@ -25,6 +109,8 @@ pub struct ExtData {
25
109
pub ops_count_sat : Option < usize > ,
26
110
/// The worst case ops-count for dissatisfying this Miniscript fragment.
27
111
pub ops_count_nsat : Option < usize > ,
112
+ /// The timelock info about heightlocks and timelocks
113
+ pub timelock_info : TimeLockInfo ,
28
114
}
29
115
30
116
impl Property for ExtData {
@@ -39,6 +125,7 @@ impl Property for ExtData {
39
125
ops_count_static : 0 ,
40
126
ops_count_sat : Some ( 0 ) ,
41
127
ops_count_nsat : None ,
128
+ timelock_info : TimeLockInfo :: default ( ) ,
42
129
}
43
130
}
44
131
@@ -49,6 +136,7 @@ impl Property for ExtData {
49
136
ops_count_static : 0 ,
50
137
ops_count_sat : None ,
51
138
ops_count_nsat : Some ( 0 ) ,
139
+ timelock_info : TimeLockInfo :: default ( ) ,
52
140
}
53
141
}
54
142
@@ -59,6 +147,7 @@ impl Property for ExtData {
59
147
ops_count_static : 0 ,
60
148
ops_count_sat : Some ( 0 ) ,
61
149
ops_count_nsat : Some ( 0 ) ,
150
+ timelock_info : TimeLockInfo :: default ( ) ,
62
151
}
63
152
}
64
153
@@ -69,6 +158,7 @@ impl Property for ExtData {
69
158
ops_count_static : 3 ,
70
159
ops_count_sat : Some ( 3 ) ,
71
160
ops_count_nsat : Some ( 3 ) ,
161
+ timelock_info : TimeLockInfo :: default ( ) ,
72
162
}
73
163
}
74
164
@@ -85,6 +175,7 @@ impl Property for ExtData {
85
175
ops_count_static : 1 ,
86
176
ops_count_sat : Some ( n + 1 ) ,
87
177
ops_count_nsat : Some ( n + 1 ) ,
178
+ timelock_info : TimeLockInfo :: default ( ) ,
88
179
}
89
180
}
90
181
@@ -100,6 +191,7 @@ impl Property for ExtData {
100
191
ops_count_static : 4 ,
101
192
ops_count_sat : Some ( 4 ) ,
102
193
ops_count_nsat : None ,
194
+ timelock_info : TimeLockInfo :: default ( ) ,
103
195
}
104
196
}
105
197
@@ -110,6 +202,7 @@ impl Property for ExtData {
110
202
ops_count_static : 4 ,
111
203
ops_count_sat : Some ( 4 ) ,
112
204
ops_count_nsat : None ,
205
+ timelock_info : TimeLockInfo :: default ( ) ,
113
206
}
114
207
}
115
208
@@ -120,6 +213,7 @@ impl Property for ExtData {
120
213
ops_count_static : 4 ,
121
214
ops_count_sat : Some ( 4 ) ,
122
215
ops_count_nsat : None ,
216
+ timelock_info : TimeLockInfo :: default ( ) ,
123
217
}
124
218
}
125
219
@@ -130,25 +224,56 @@ impl Property for ExtData {
130
224
ops_count_static : 4 ,
131
225
ops_count_sat : Some ( 4 ) ,
132
226
ops_count_nsat : None ,
227
+ timelock_info : TimeLockInfo :: default ( ) ,
228
+ }
229
+ }
230
+
231
+ fn from_time ( _t : u32 ) -> Self {
232
+ unreachable ! ( )
233
+ }
234
+
235
+ fn from_after ( t : u32 ) -> Self {
236
+ ExtData {
237
+ pk_cost : script_num_size ( t as usize ) + 1 ,
238
+ has_free_verify : false ,
239
+ ops_count_static : 1 ,
240
+ ops_count_sat : Some ( 1 ) ,
241
+ ops_count_nsat : None ,
242
+ timelock_info : TimeLockInfo {
243
+ csv_with_height : false ,
244
+ csv_with_time : false ,
245
+ cltv_with_height : t < HEIGHT_TIME_THRESHOLD ,
246
+ cltv_with_time : t >= HEIGHT_TIME_THRESHOLD ,
247
+ contains_combination : false ,
248
+ } ,
133
249
}
134
250
}
135
251
136
- fn from_time ( t : u32 ) -> Self {
252
+ fn from_older ( t : u32 ) -> Self {
137
253
ExtData {
138
254
pk_cost : script_num_size ( t as usize ) + 1 ,
139
255
has_free_verify : false ,
140
256
ops_count_static : 1 ,
141
257
ops_count_sat : Some ( 1 ) ,
142
258
ops_count_nsat : None ,
259
+ timelock_info : TimeLockInfo {
260
+ csv_with_height : t < HEIGHT_TIME_THRESHOLD ,
261
+ csv_with_time : t >= HEIGHT_TIME_THRESHOLD ,
262
+ cltv_with_height : false ,
263
+ cltv_with_time : false ,
264
+ contains_combination : false ,
265
+ } ,
143
266
}
144
267
}
268
+
145
269
fn cast_alt ( self ) -> Result < Self , ErrorKind > {
146
270
Ok ( ExtData {
147
271
pk_cost : self . pk_cost + 2 ,
148
272
has_free_verify : false ,
149
273
ops_count_static : self . ops_count_static + 2 ,
150
274
ops_count_sat : self . ops_count_sat . map ( |x| x + 2 ) ,
151
275
ops_count_nsat : self . ops_count_nsat . map ( |x| x + 2 ) ,
276
+ timelock_info : self . timelock_info ,
152
277
} )
153
278
}
154
279
@@ -159,6 +284,7 @@ impl Property for ExtData {
159
284
ops_count_static : self . ops_count_static + 1 ,
160
285
ops_count_sat : self . ops_count_sat . map ( |x| x + 1 ) ,
161
286
ops_count_nsat : self . ops_count_nsat . map ( |x| x + 1 ) ,
287
+ timelock_info : self . timelock_info ,
162
288
} )
163
289
}
164
290
@@ -169,6 +295,7 @@ impl Property for ExtData {
169
295
ops_count_static : self . ops_count_static + 1 ,
170
296
ops_count_sat : self . ops_count_sat . map ( |x| x + 1 ) ,
171
297
ops_count_nsat : self . ops_count_nsat . map ( |x| x + 1 ) ,
298
+ timelock_info : self . timelock_info ,
172
299
} )
173
300
}
174
301
@@ -179,6 +306,7 @@ impl Property for ExtData {
179
306
ops_count_static : self . ops_count_static + 3 ,
180
307
ops_count_sat : self . ops_count_sat . map ( |x| x + 3 ) ,
181
308
ops_count_nsat : Some ( self . ops_count_static + 3 ) ,
309
+ timelock_info : self . timelock_info ,
182
310
} )
183
311
}
184
312
@@ -190,6 +318,7 @@ impl Property for ExtData {
190
318
ops_count_static : self . ops_count_static + verify_cost,
191
319
ops_count_sat : self . ops_count_sat . map ( |x| x + verify_cost) ,
192
320
ops_count_nsat : None ,
321
+ timelock_info : self . timelock_info ,
193
322
} )
194
323
}
195
324
@@ -200,6 +329,7 @@ impl Property for ExtData {
200
329
ops_count_static : self . ops_count_static + 4 ,
201
330
ops_count_sat : self . ops_count_sat . map ( |x| x + 4 ) ,
202
331
ops_count_nsat : Some ( self . ops_count_static + 4 ) ,
332
+ timelock_info : self . timelock_info ,
203
333
} )
204
334
}
205
335
@@ -210,6 +340,7 @@ impl Property for ExtData {
210
340
ops_count_static : self . ops_count_static + 1 ,
211
341
ops_count_sat : self . ops_count_sat . map ( |x| x + 1 ) ,
212
342
ops_count_nsat : self . ops_count_nsat . map ( |x| x + 1 ) ,
343
+ timelock_info : self . timelock_info ,
213
344
} )
214
345
}
215
346
@@ -220,6 +351,7 @@ impl Property for ExtData {
220
351
ops_count_static : self . ops_count_static ,
221
352
ops_count_sat : self . ops_count_sat ,
222
353
ops_count_nsat : None ,
354
+ timelock_info : self . timelock_info ,
223
355
} )
224
356
}
225
357
@@ -235,6 +367,7 @@ impl Property for ExtData {
235
367
ops_count_static : self . ops_count_static + 3 ,
236
368
ops_count_sat : self . ops_count_sat . map ( |x| x + 3 ) ,
237
369
ops_count_nsat : Some ( self . ops_count_static + 3 ) ,
370
+ timelock_info : self . timelock_info ,
238
371
} )
239
372
}
240
373
@@ -245,6 +378,7 @@ impl Property for ExtData {
245
378
ops_count_static : self . ops_count_static + 3 ,
246
379
ops_count_sat : self . ops_count_sat . map ( |x| x + 3 ) ,
247
380
ops_count_nsat : Some ( self . ops_count_static + 3 ) ,
381
+ timelock_info : self . timelock_info ,
248
382
} )
249
383
}
250
384
@@ -259,6 +393,7 @@ impl Property for ExtData {
259
393
ops_count_nsat : l
260
394
. ops_count_nsat
261
395
. and_then ( |x| r. ops_count_nsat . map ( |y| x + y + 1 ) ) ,
396
+ timelock_info : TimeLockInfo :: comb_and_timelocks ( l. timelock_info , r. timelock_info ) ,
262
397
} )
263
398
}
264
399
@@ -269,6 +404,7 @@ impl Property for ExtData {
269
404
ops_count_static : l. ops_count_static + r. ops_count_static ,
270
405
ops_count_sat : l. ops_count_sat . and_then ( |x| r. ops_count_sat . map ( |y| x + y) ) ,
271
406
ops_count_nsat : None ,
407
+ timelock_info : TimeLockInfo :: comb_and_timelocks ( l. timelock_info , r. timelock_info ) ,
272
408
} )
273
409
}
274
410
@@ -286,6 +422,7 @@ impl Property for ExtData {
286
422
ops_count_nsat : l
287
423
. ops_count_nsat
288
424
. and_then ( |x| r. ops_count_nsat . map ( |y| x + y + 1 ) ) ,
425
+ timelock_info : TimeLockInfo :: comb_or_timelocks ( l. timelock_info , r. timelock_info ) ,
289
426
} )
290
427
}
291
428
@@ -302,6 +439,7 @@ impl Property for ExtData {
302
439
ops_count_nsat : l
303
440
. ops_count_nsat
304
441
. and_then ( |x| r. ops_count_nsat . map ( |y| x + y + 3 ) ) ,
442
+ timelock_info : TimeLockInfo :: comb_or_timelocks ( l. timelock_info , r. timelock_info ) ,
305
443
} )
306
444
}
307
445
@@ -316,6 +454,7 @@ impl Property for ExtData {
316
454
. and_then ( |x| l. ops_count_nsat . map ( |y| y + x + 2 ) ) ,
317
455
) ,
318
456
ops_count_nsat : None ,
457
+ timelock_info : TimeLockInfo :: comb_or_timelocks ( l. timelock_info , r. timelock_info ) ,
319
458
} )
320
459
}
321
460
@@ -333,6 +472,7 @@ impl Property for ExtData {
333
472
( _, Some ( x) ) | ( Some ( x) , _) => Some ( x + 3 ) ,
334
473
( None , None ) => None ,
335
474
} ,
475
+ timelock_info : TimeLockInfo :: comb_or_timelocks ( l. timelock_info , r. timelock_info ) ,
336
476
} )
337
477
}
338
478
@@ -350,6 +490,10 @@ impl Property for ExtData {
350
490
ops_count_nsat : c
351
491
. ops_count_nsat
352
492
. and_then ( |z| a. ops_count_nsat . map ( |x| x + b. ops_count_static + z + 3 ) ) ,
493
+ timelock_info : TimeLockInfo :: comb_or_timelocks (
494
+ TimeLockInfo :: comb_and_timelocks ( a. timelock_info , b. timelock_info ) ,
495
+ c. timelock_info ,
496
+ ) ,
353
497
} )
354
498
}
355
499
@@ -364,10 +508,13 @@ impl Property for ExtData {
364
508
let mut ops_count_nsat = Some ( 0 ) ;
365
509
let mut ops_count_sat = Some ( 0 ) ;
366
510
let mut sat_count = 0 ;
511
+ let mut timelocks = vec ! [ ] ;
367
512
for i in 0 ..n {
368
513
let sub = sub_ck ( i) ?;
514
+
369
515
pk_cost += sub. pk_cost ;
370
516
ops_count_static += sub. ops_count_static ;
517
+ timelocks. push ( sub. timelock_info ) ;
371
518
match ( sub. ops_count_sat , sub. ops_count_nsat ) {
372
519
( Some ( x) , Some ( y) ) => {
373
520
ops_count_sat_vec. push ( Some ( x as i32 - y as i32 ) ) ;
@@ -402,6 +549,7 @@ impl Property for ExtData {
402
549
ops_count_sat : ops_count_sat
403
550
. map ( |x : usize | ( x + ( n - 1 ) + 1 + ( sum + ops_count_nsat_sum as i32 ) as usize ) ) , //adds and equal
404
551
ops_count_nsat : ops_count_nsat. map ( |x| x + ( n - 1 ) + 1 ) , //adds and equal
552
+ timelock_info : TimeLockInfo :: combine_thresh_timelocks ( k, timelocks) ,
405
553
} )
406
554
}
407
555
0 commit comments