• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Neptune-Crypto / neptune-core / 14703155990

28 Apr 2025 07:55AM UTC coverage: 79.634% (-0.09%) from 79.726%
14703155990

push

github

dan-da
test: fix shared_tokio_runtime macro

addresses review comments:
https://github.com/Neptune-Crypto/neptune-core/pull/569#discussion_r2062924684
https://github.com/Neptune-Crypto/neptune-core/pull/569#discussion_r2062938756

1. adds back a #[traced_test] that got removed in efe4da2f.

2. adds missing visibility specifier to async test fn inside macro.

The missing specifier didn't cause any error or warning during
compilation or linting, but it is clearly more correct to have it in
place.

1 of 2 new or added lines in 2 files covered. (50.0%)

46 existing lines in 3 files now uncovered.

37143 of 46642 relevant lines covered (79.63%)

232101.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.33
/src/models/blockchain/type_scripts/time_lock.rs
1
use std::collections::HashMap;
2
use std::sync::OnceLock;
3

4
use get_size2::GetSize;
5
use itertools::Itertools;
6
use num_traits::Zero;
7
use serde::Deserialize;
8
use serde::Serialize;
9
use tasm_lib::memory::encode_to_memory;
10
use tasm_lib::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
11
use tasm_lib::prelude::Digest;
12
use tasm_lib::prelude::Library;
13
use tasm_lib::structure::verify_nd_si_integrity::VerifyNdSiIntegrity;
14
use tasm_lib::triton_vm::prelude::*;
15
use tasm_lib::twenty_first::math::b_field_element::BFieldElement;
16
use tasm_lib::twenty_first::math::bfield_codec::BFieldCodec;
17

18
use super::TypeScript;
19
use super::TypeScriptWitness;
20
use crate::models::blockchain::transaction::primitive_witness::PrimitiveWitness;
21
use crate::models::blockchain::transaction::primitive_witness::SaltedUtxos;
22
use crate::models::blockchain::transaction::transaction_kernel::TransactionKernel;
23
use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelField;
24
use crate::models::blockchain::transaction::utxo::Coin;
25
use crate::models::blockchain::transaction::utxo::Utxo;
26
use crate::models::blockchain::type_scripts::TypeScriptAndWitness;
27
use crate::models::proof_abstractions::mast_hash::MastHash;
28
use crate::models::proof_abstractions::tasm::program::ConsensusProgram;
29
use crate::models::proof_abstractions::timestamp::Timestamp;
30
use crate::models::proof_abstractions::SecretWitness;
31

32
#[derive(Debug, Copy, Clone, Deserialize, Serialize, BFieldCodec, GetSize, PartialEq, Eq)]
×
33
pub struct TimeLock;
34

35
impl TimeLock {
36
    /// Create a `TimeLock` type-script-and-state-pair that releases the coins at the
37
    /// given release date, which corresponds to the number of milliseconds that passed
38
    /// since the unix epoch started (00:00 am UTC on Jan 1 1970).
39
    pub fn until(date: Timestamp) -> Coin {
306,993✔
40
        Coin {
306,993✔
41
            type_script_hash: TimeLock.hash(),
306,993✔
42
            state: vec![date.0],
306,993✔
43
        }
306,993✔
44
    }
306,993✔
45

46
    /// Get the release date from a `Utxo`, if any. If there aren't any, return
47
    /// the null release date.
48
    pub fn extract_release_date(utxo: &Utxo) -> Timestamp {
1,762✔
49
        utxo.coins()
1,762✔
50
            .iter()
1,762✔
51
            .find_map(Coin::release_date)
1,762✔
52
            .unwrap_or_else(Timestamp::zero)
1,762✔
53
    }
1,762✔
54
}
55

56
impl ConsensusProgram for TimeLock {
57
    fn library_and_code(&self) -> (Library, Vec<LabelledInstruction>) {
3,991✔
58
        let (library, audit_preloaded_data, audit_subroutine) = {
3,991✔
59
            let mut library = Library::new();
3,991✔
60
            let audit_preloaded_data = library.import(Box::new(VerifyNdSiIntegrity::<
3,991✔
61
                TimeLockWitnessMemory,
3,991✔
62
            >::default()));
3,991✔
63
            let audit_subroutine = library.all_imports();
3,991✔
64
            (library, audit_preloaded_data, audit_subroutine)
3,991✔
65
        };
3,991✔
66

3,991✔
67
        // Generated by tasm-lang compiler
3,991✔
68
        // `tasm-lang typescript-timelock.rs type-script-time-lock.tasm`
3,991✔
69
        // 2024-09-09
3,991✔
70
        let code = triton_asm! {
3,991✔
71
        call main
3,991✔
72
        halt
3,991✔
73
        {&audit_subroutine}
3,991✔
74

3,991✔
75
        main:
3,991✔
76
        call tasmlib_verifier_own_program_digest
3,991✔
77
        dup 4
3,991✔
78
        dup 4
3,991✔
79
        dup 4
3,991✔
80
        dup 4
3,991✔
81
        dup 4
3,991✔
82
        push -6
3,991✔
83
        write_mem 5
3,991✔
84
        pop 1
3,991✔
85
        hint self_digest = stack[0..5]
3,991✔
86
        call tasmlib_io_read_stdin___digest
3,991✔
87
        dup 4
3,991✔
88
        dup 4
3,991✔
89
        dup 4
3,991✔
90
        dup 4
3,991✔
91
        dup 4
3,991✔
92
        push -11
3,991✔
93
        write_mem 5
3,991✔
94
        pop 1
3,991✔
95
        hint tx_kernel_digest = stack[0..5]
3,991✔
96
        call tasmlib_io_read_stdin___digest
3,991✔
97
        dup 4
3,991✔
98
        dup 4
3,991✔
99
        dup 4
3,991✔
100
        dup 4
3,991✔
101
        dup 4
3,991✔
102
        push -16
3,991✔
103
        write_mem 5
3,991✔
104
        pop 1
3,991✔
105
        hint input_utxos_digest = stack[0..5]
3,991✔
106
        call tasmlib_io_read_stdin___digest
3,991✔
107
        hint _output_utxos_digest = stack[0..5]
3,991✔
108
        push 5
3,991✔
109
        hint leaf_index = stack[0]
3,991✔
110
        call tasmlib_io_read_secin___bfe
3,991✔
111
        dup 0
3,991✔
112
        push -17
3,991✔
113
        write_mem 1
3,991✔
114
        pop 1
3,991✔
115
        hint timestamp = stack[0]
3,991✔
116
        push -17
3,991✔
117
        read_mem 1
3,991✔
118
        pop 1
3,991✔
119
        call encode_BField
3,991✔
120
        call tasm_langs_hash_varlen
3,991✔
121
        hint leaf = stack[0..5]
3,991✔
122
        push 3
3,991✔
123
        hint tree_height = stack[0]
3,991✔
124
        push -7
3,991✔
125
        read_mem 5
3,991✔
126
        pop 1
3,991✔
127
        dup 5
3,991✔
128
        dup 13
3,991✔
129
        dup 12
3,991✔
130
        dup 12
3,991✔
131
        dup 12
3,991✔
132
        dup 12
3,991✔
133
        dup 12
3,991✔
134
        call tasmlib_hashing_merkle_verify
3,991✔
135
        call tasmlib_io_read_secin___bfe
3,991✔
136
        hint input_utxos_pointer = stack[0]
3,991✔
137

3,991✔
138
        /* Audit preloaded data */
3,991✔
139
        // ... *input_utxos_pointer
3,991✔
140
        dup 0
3,991✔
141
        call {audit_preloaded_data}
3,991✔
142
        // ... *input_utxos_pointer witness_size
3,991✔
143

3,991✔
144
        pop 1
3,991✔
145
        // ... *input_utxos_pointer
3,991✔
146

3,991✔
147
        call tasmlib_io_read_secin___bfe
3,991✔
148
        split
3,991✔
149
        hint _output_utxos_pointer = stack[0..2]
3,991✔
150
        dup 2
3,991✔
151
        hint input_salted_utxos = stack[0]
3,991✔
152
        dup 0
3,991✔
153
        call tasm_langs_hash_varlen_boxed_value___SaltedUtxos
3,991✔
154
        hint input_salted_utxos_digest = stack[0..5]
3,991✔
155
        dup 4
3,991✔
156
        dup 4
3,991✔
157
        dup 4
3,991✔
158
        dup 4
3,991✔
159
        dup 4
3,991✔
160
        push -12
3,991✔
161
        read_mem 5
3,991✔
162
        pop 1
3,991✔
163
        call tasmlib_hashing_eq_digest
3,991✔
164
        assert
3,991✔
165
        dup 5
3,991✔
166
        addi 4
3,991✔
167
        hint input_utxos = stack[0]
3,991✔
168
        push 0
3,991✔
169
        hint i = stack[0]
3,991✔
170
        call _binop_Lt__LboolR_bool_32_while_loop
3,991✔
171
        pop 5
3,991✔
172
        pop 5
3,991✔
173
        pop 5
3,991✔
174
        pop 5
3,991✔
175
        pop 5
3,991✔
176
        pop 5
3,991✔
177
        pop 5
3,991✔
178
        pop 4
3,991✔
179
        return
3,991✔
180
        _binop_Eq__LboolR_bool_49_then:
3,991✔
181
        pop 1
3,991✔
182
        dup 0
3,991✔
183
        addi 1
3,991✔
184
        hint state = stack[0]
3,991✔
185
        dup 0
3,991✔
186
        read_mem 1
3,991✔
187
        pop 1
3,991✔
188
        push 1
3,991✔
189
        eq
3,991✔
190
        assert
3,991✔
191
        dup 0
3,991✔
192
        push 0
3,991✔
193
        push 1
3,991✔
194
        mul
3,991✔
195
        push 1
3,991✔
196
        add
3,991✔
197
        push 00000000001073741824
3,991✔
198
        dup 1
3,991✔
199
        lt
3,991✔
200
        assert
3,991✔
201
        add
3,991✔
202
        read_mem 1
3,991✔
203
        pop 1
3,991✔
204
        hint release_date = stack[0]
3,991✔
205
        dup 0
3,991✔
206
        split
3,991✔
207
        push -17
3,991✔
208
        read_mem 1
3,991✔
209
        pop 1
3,991✔
210
        split
3,991✔
211
        swap 3
3,991✔
212
        swap 1
3,991✔
213
        swap 3
3,991✔
214
        swap 2
3,991✔
215
        call tasmlib_arithmetic_u64_lt
3,991✔
216
        assert
3,991✔
217
        pop 1
3,991✔
218
        pop 1
3,991✔
219
        push 0
3,991✔
220
        return
3,991✔
221
        _binop_Eq__LboolR_bool_49_else:
3,991✔
222
        return
3,991✔
223
        _binop_Lt__LboolR_bool_42_while_loop:
3,991✔
224
        dup 0
3,991✔
225
        dup 2
3,991✔
226
        read_mem 1
3,991✔
227
        pop 1
3,991✔
228
        swap 1
3,991✔
229
        lt
3,991✔
230
        push 0
3,991✔
231
        eq
3,991✔
232
        skiz
3,991✔
233
        return
3,991✔
234
        dup 1
3,991✔
235
        push 1
3,991✔
236
        add
3,991✔
237
        dup 1
3,991✔
238
        call tasm_langs_dynamic_list_element_finder
3,991✔
239
        pop 1
3,991✔
240
        addi 1
3,991✔
241
        hint coin = stack[0]
3,991✔
242
        dup 0
3,991✔
243
        read_mem 1
3,991✔
244
        push 00000000001073741824
3,991✔
245
        dup 2
3,991✔
246
        lt
3,991✔
247
        assert
3,991✔
248
        addi 2
3,991✔
249
        add
3,991✔
250
        push 4
3,991✔
251
        add
3,991✔
252
        read_mem 5
3,991✔
253
        pop 1
3,991✔
254
        push -2
3,991✔
255
        read_mem 5
3,991✔
256
        pop 1
3,991✔
257
        call tasmlib_hashing_eq_digest
3,991✔
258
        push 1
3,991✔
259
        swap 1
3,991✔
260
        skiz
3,991✔
261
        call _binop_Eq__LboolR_bool_49_then
3,991✔
262
        skiz
3,991✔
263
        call _binop_Eq__LboolR_bool_49_else
3,991✔
264
        dup 1
3,991✔
265
        push 1
3,991✔
266
        call tasmlib_arithmetic_u32_safeadd
3,991✔
267
        swap 2
3,991✔
268
        pop 1
3,991✔
269
        pop 1
3,991✔
270
        recurse
3,991✔
271
        _binop_Lt__LboolR_bool_32_while_loop:
3,991✔
272
        dup 0
3,991✔
273
        dup 2
3,991✔
274
        read_mem 1
3,991✔
275
        pop 1
3,991✔
276
        swap 1
3,991✔
277
        lt
3,991✔
278
        push 0
3,991✔
279
        eq
3,991✔
280
        skiz
3,991✔
281
        return
3,991✔
282
        dup 1
3,991✔
283
        push 1
3,991✔
284
        add
3,991✔
285
        dup 1
3,991✔
286
        call tasm_langs_dynamic_list_element_finder
3,991✔
287
        pop 1
3,991✔
288
        addi 1
3,991✔
289
        addi 1
3,991✔
290
        hint coins = stack[0]
3,991✔
291
        push 0
3,991✔
292
        hint j = stack[0]
3,991✔
293
        call _binop_Lt__LboolR_bool_42_while_loop
3,991✔
294
        dup 2
3,991✔
295
        push 1
3,991✔
296
        call tasmlib_arithmetic_u32_safeadd
3,991✔
297
        swap 3
3,991✔
298
        pop 1
3,991✔
299
        pop 1
3,991✔
300
        pop 1
3,991✔
301
        recurse
3,991✔
302
        encode_BField:
3,991✔
303
        call tasmlib_memory_dyn_malloc
3,991✔
304
        push 1
3,991✔
305
        swap 1
3,991✔
306
        write_mem 1
3,991✔
307
        write_mem 1
3,991✔
308
        push -2
3,991✔
309
        add
3,991✔
310
        return
3,991✔
311
        tasm_langs_dynamic_list_element_finder:
3,991✔
312
        dup 0
3,991✔
313
        push 0
3,991✔
314
        eq
3,991✔
315
        skiz
3,991✔
316
        return
3,991✔
317
        swap 1
3,991✔
318
        read_mem 1
3,991✔
319
        push 00000000001073741824
3,991✔
320
        dup 2
3,991✔
321
        lt
3,991✔
322
        assert
3,991✔
323
        addi 2
3,991✔
324
        add
3,991✔
325
        swap 1
3,991✔
326
        addi -1
3,991✔
327
        recurse
3,991✔
328
        tasm_langs_hash_varlen:
3,991✔
329
        read_mem 1
3,991✔
330
        push 2
3,991✔
331
        add
3,991✔
332
        swap 1
3,991✔
333
        call tasmlib_hashing_algebraic_hasher_hash_varlen
3,991✔
334
        return
3,991✔
335
        tasm_langs_hash_varlen_boxed_value___SaltedUtxos:
3,991✔
336
        dup 0
3,991✔
337
        push 0
3,991✔
338
        addi 3
3,991✔
339
        swap 1
3,991✔
340
        addi 3
3,991✔
341
        swap 1
3,991✔
342
        dup 1
3,991✔
343
        read_mem 1
3,991✔
344
        pop 1
3,991✔
345
        push 00000000001073741824
3,991✔
346
        dup 1
3,991✔
347
        lt
3,991✔
348
        assert
3,991✔
349
        addi 1
3,991✔
350
        dup 2
3,991✔
351
        dup 1
3,991✔
352
        add
3,991✔
353
        swap 3
3,991✔
354
        pop 1
3,991✔
355
        add
3,991✔
356
        swap 1
3,991✔
357
        pop 1
3,991✔
358
        call tasmlib_hashing_algebraic_hasher_hash_varlen
3,991✔
359
        return
3,991✔
360
        tasmlib_arithmetic_u32_safeadd:
3,991✔
361
        hint input_lhs: u32 = stack[0]
3,991✔
362
        hint input_rhs: u32 = stack[1]
3,991✔
363
        add
3,991✔
364
        dup 0
3,991✔
365
        split
3,991✔
366
        pop 1
3,991✔
367
        push 0
3,991✔
368
        eq
3,991✔
369
        assert
3,991✔
370
        return
3,991✔
371
        tasmlib_arithmetic_u64_lt:
3,991✔
372
        hint lhs: u64 = stack[0..2]
3,991✔
373
        hint rhs: u64 = stack[2..4]
3,991✔
374
        swap 3
3,991✔
375
        swap 2
3,991✔
376
        dup 2
3,991✔
377
        dup 2
3,991✔
378
        lt
3,991✔
379
        swap 4
3,991✔
380
        lt
3,991✔
381
        swap 2
3,991✔
382
        eq
3,991✔
383
        mul
3,991✔
384
        add
3,991✔
385
        return
3,991✔
386
        tasmlib_hashing_absorb_multiple:
3,991✔
387
        hint len: u32 = stack[0]
3,991✔
388
        hint _sequence: void_pointer = stack[1]
3,991✔
389
        dup 0
3,991✔
390
        push 10
3,991✔
391
        swap 1
3,991✔
392
        div_mod
3,991✔
393
        swap 1
3,991✔
394
        pop 1
3,991✔
395
        swap 1
3,991✔
396
        dup 1
3,991✔
397
        push -1
3,991✔
398
        mul
3,991✔
399
        dup 3
3,991✔
400
        add
3,991✔
401
        add
3,991✔
402
        swap 1
3,991✔
403
        swap 2
3,991✔
404
        push 0
3,991✔
405
        push 0
3,991✔
406
        push 0
3,991✔
407
        push 0
3,991✔
408
        swap 4
3,991✔
409
        call tasmlib_hashing_absorb_multiple_hash_all_full_chunks
3,991✔
410
        pop 5
3,991✔
411
        push -1
3,991✔
412
        add
3,991✔
413
        push 9
3,991✔
414
        dup 2
3,991✔
415
        push -1
3,991✔
416
        mul
3,991✔
417
        add
3,991✔
418
        call tasmlib_hashing_absorb_multiple_pad_varnum_zeros
3,991✔
419
        pop 1
3,991✔
420
        push 1
3,991✔
421
        swap 2
3,991✔
422
        dup 1
3,991✔
423
        add
3,991✔
424
        call tasmlib_hashing_absorb_multiple_read_remainder
3,991✔
425
        pop 2
3,991✔
426
        sponge_absorb
3,991✔
427
        return
3,991✔
428
        tasmlib_hashing_absorb_multiple_hash_all_full_chunks:
3,991✔
429
        dup 5
3,991✔
430
        dup 1
3,991✔
431
        eq
3,991✔
432
        skiz
3,991✔
433
        return
3,991✔
434
        sponge_absorb_mem
3,991✔
435
        recurse
3,991✔
436
        tasmlib_hashing_absorb_multiple_pad_varnum_zeros:
3,991✔
437
        dup 0
3,991✔
438
        push 0
3,991✔
439
        eq
3,991✔
440
        skiz
3,991✔
441
        return
3,991✔
442
        push 0
3,991✔
443
        swap 3
3,991✔
444
        swap 2
3,991✔
445
        swap 1
3,991✔
446
        push -1
3,991✔
447
        add
3,991✔
448
        recurse
3,991✔
449
        tasmlib_hashing_absorb_multiple_read_remainder:
3,991✔
450
        dup 1
3,991✔
451
        dup 1
3,991✔
452
        eq
3,991✔
453
        skiz
3,991✔
454
        return
3,991✔
455
        read_mem 1
3,991✔
456
        swap 1
3,991✔
457
        swap 2
3,991✔
458
        swap 1
3,991✔
459
        recurse
3,991✔
460
        tasmlib_hashing_algebraic_hasher_hash_varlen:
3,991✔
461
        hint length: u32 = stack[0]
3,991✔
462
        hint _addr: void_pointer = stack[1]
3,991✔
463
        sponge_init
3,991✔
464
        call tasmlib_hashing_absorb_multiple
3,991✔
465
        sponge_squeeze
3,991✔
466
        swap 5
3,991✔
467
        pop 1
3,991✔
468
        swap 5
3,991✔
469
        pop 1
3,991✔
470
        swap 5
3,991✔
471
        pop 1
3,991✔
472
        swap 5
3,991✔
473
        pop 1
3,991✔
474
        swap 5
3,991✔
475
        pop 1
3,991✔
476
        return
3,991✔
477
        tasmlib_hashing_eq_digest:
3,991✔
478
        hint input_a4: digest = stack[0..5]
3,991✔
479
        hint input_b4: digest = stack[5..10]
3,991✔
480
        swap 6
3,991✔
481
        eq
3,991✔
482
        swap 6
3,991✔
483
        eq
3,991✔
484
        swap 6
3,991✔
485
        eq
3,991✔
486
        swap 6
3,991✔
487
        eq
3,991✔
488
        swap 2
3,991✔
489
        eq
3,991✔
490
        mul
3,991✔
491
        mul
3,991✔
492
        mul
3,991✔
493
        mul
3,991✔
494
        return
3,991✔
495
        tasmlib_hashing_merkle_verify:
3,991✔
496
        hint leaf: digest = stack[0..5]
3,991✔
497
        hint leaf_index: u32 = stack[5]
3,991✔
498
        hint tree_height: u32 = stack[6]
3,991✔
499
        hint root: digest = stack[7..12]
3,991✔
500
        dup 6
3,991✔
501
        push 2
3,991✔
502
        pow
3,991✔
503
        dup 0
3,991✔
504
        dup 7
3,991✔
505
        lt
3,991✔
506
        assert
3,991✔
507
        dup 6
3,991✔
508
        add
3,991✔
509
        swap 6
3,991✔
510
        pop 1
3,991✔
511
        dup 6
3,991✔
512
        skiz
3,991✔
513
        call tasmlib_hashing_merkle_verify_tree_height_is_not_zero
3,991✔
514
        swap 2
3,991✔
515
        swap 4
3,991✔
516
        swap 6
3,991✔
517
        pop 1
3,991✔
518
        swap 2
3,991✔
519
        swap 4
3,991✔
520
        pop 1
3,991✔
521
        assert_vector
3,991✔
522
        pop 5
3,991✔
523
        return
3,991✔
524
        tasmlib_hashing_merkle_verify_tree_height_is_not_zero:
3,991✔
525
        push 1
3,991✔
526
        swap 7
3,991✔
527
        pop 1
3,991✔
528
        call tasmlib_hashing_merkle_verify_traverse_tree
3,991✔
529
        return
3,991✔
530
        tasmlib_hashing_merkle_verify_traverse_tree:
3,991✔
531
        merkle_step
3,991✔
532
        recurse_or_return
3,991✔
533
        tasmlib_io_read_secin___bfe:
3,991✔
534
        divine 1
3,991✔
535
        return
3,991✔
536
        tasmlib_io_read_stdin___digest:
3,991✔
537
        read_io 5
3,991✔
538
        return
3,991✔
539
        tasmlib_memory_dyn_malloc:
3,991✔
540
        push -1
3,991✔
541
        read_mem 1
3,991✔
542
        pop 1
3,991✔
543
        dup 0
3,991✔
544
        push 0
3,991✔
545
        eq
3,991✔
546
        skiz
3,991✔
547
        call tasmlib_memory_dyn_malloc_initialize
3,991✔
548
        push 00000000002147483647
3,991✔
549
        dup 1
3,991✔
550
        lt
3,991✔
551
        assert
3,991✔
552
        dup 0
3,991✔
553
        push 1
3,991✔
554
        add
3,991✔
555
        push -1
3,991✔
556
        write_mem 1
3,991✔
557
        pop 1
3,991✔
558
        push 00000000004294967296
3,991✔
559
        mul
3,991✔
560
        return
3,991✔
561
        tasmlib_memory_dyn_malloc_initialize:
3,991✔
562
        pop 1
3,991✔
563
        push 1
3,991✔
564
        return
3,991✔
565
        tasmlib_verifier_own_program_digest:
3,991✔
566
        dup 15
3,991✔
567
        dup 15
3,991✔
568
        dup 15
3,991✔
569
        dup 15
3,991✔
570
        dup 15
3,991✔
571
        return
3,991✔
572
        };
3,991✔
573

3,991✔
574
        (library, code)
3,991✔
575
    }
3,991✔
576

577
    fn hash(&self) -> Digest {
337,366✔
578
        static HASH: OnceLock<Digest> = OnceLock::new();
579

580
        *HASH.get_or_init(|| self.program().hash())
337,366✔
581
    }
337,366✔
582
}
583

584
impl TypeScript for TimeLock {
585
    type State = Timestamp;
586
}
587

588
#[derive(Debug, Clone, Deserialize, Serialize, BFieldCodec, GetSize, PartialEq, Eq)]
×
589
pub struct TimeLockWitness {
590
    /// One timestamp for every input UTXO. Inputs that do not have a time lock are
591
    /// assigned timestamp 0, which is automatically satisfied.
592
    release_dates: Vec<Timestamp>,
593
    input_utxos: SaltedUtxos,
594
    transaction_kernel: TransactionKernel,
595
}
596

597
type TimeLockWitnessMemory = SaltedUtxos;
598

599
impl SecretWitness for TimeLockWitness {
600
    fn nondeterminism(&self) -> NonDeterminism {
3,760✔
601
        let mut memory: HashMap<BFieldElement, BFieldElement> = HashMap::new();
3,760✔
602
        let input_salted_utxos_address = FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
3,760✔
603
        let output_salted_utxos_address = encode_to_memory::<TimeLockWitnessMemory>(
3,760✔
604
            &mut memory,
3,760✔
605
            input_salted_utxos_address,
3,760✔
606
            &self.input_utxos,
3,760✔
607
        );
3,760✔
608
        let individual_tokens = vec![
3,760✔
609
            self.transaction_kernel.timestamp.0,
3,760✔
610
            input_salted_utxos_address,
3,760✔
611
            output_salted_utxos_address,
3,760✔
612
        ];
3,760✔
613
        let mast_path = self
3,760✔
614
            .transaction_kernel
3,760✔
615
            .mast_path(TransactionKernelField::Timestamp)
3,760✔
616
            .clone();
3,760✔
617
        NonDeterminism::new(individual_tokens)
3,760✔
618
            .with_digests(mast_path)
3,760✔
619
            .with_ram(memory)
3,760✔
620
    }
3,760✔
621

622
    fn standard_input(&self) -> PublicInput {
162✔
623
        self.type_script_standard_input()
162✔
624
    }
162✔
625

626
    fn program(&self) -> Program {
×
627
        TimeLock.program()
×
628
    }
×
629
}
630

631
impl TypeScriptWitness for TimeLockWitness {
632
    fn transaction_kernel(&self) -> TransactionKernel {
162✔
633
        self.transaction_kernel.clone()
162✔
634
    }
162✔
635

636
    fn salted_input_utxos(&self) -> SaltedUtxos {
162✔
637
        self.input_utxos.clone()
162✔
638
    }
162✔
639

640
    fn salted_output_utxos(&self) -> SaltedUtxos {
162✔
641
        SaltedUtxos::empty()
162✔
642
    }
162✔
643

644
    fn type_script_and_witness(&self) -> TypeScriptAndWitness {
3,598✔
645
        TypeScriptAndWitness::new_with_nondeterminism(TimeLock.program(), self.nondeterminism())
3,598✔
646
    }
3,598✔
647

648
    fn new(
3,598✔
649
        transaction_kernel: TransactionKernel,
3,598✔
650
        salted_input_utxos: SaltedUtxos,
3,598✔
651
        _salted_output_utxos: SaltedUtxos,
3,598✔
652
    ) -> Self {
3,598✔
653
        let release_dates = salted_input_utxos
3,598✔
654
            .utxos
3,598✔
655
            .iter()
3,598✔
656
            .map(TimeLock::extract_release_date)
3,598✔
657
            .collect_vec();
3,598✔
658

3,598✔
659
        Self {
3,598✔
660
            release_dates,
3,598✔
661
            input_utxos: salted_input_utxos,
3,598✔
662
            transaction_kernel,
3,598✔
663
        }
3,598✔
664
    }
3,598✔
665
}
666

667
impl From<PrimitiveWitness> for TimeLockWitness {
668
    fn from(primitive_witness: PrimitiveWitness) -> Self {
81✔
669
        let release_dates = primitive_witness
81✔
670
            .input_utxos
81✔
671
            .utxos
81✔
672
            .iter()
81✔
673
            .map(TimeLock::extract_release_date)
81✔
674
            .collect_vec();
81✔
675
        let transaction_kernel = TransactionKernel::from(primitive_witness.clone());
81✔
676
        let input_utxos = primitive_witness.input_utxos.clone();
81✔
677

81✔
678
        Self {
81✔
679
            release_dates,
81✔
680
            input_utxos,
81✔
681
            transaction_kernel,
81✔
682
        }
81✔
683
    }
81✔
684
}
685

686
#[cfg(any(test, feature = "arbitrary-impls"))]
687
pub mod neptune_arbitrary {
688
    use num_traits::CheckedSub;
689
    use proptest::arbitrary::Arbitrary;
690
    use proptest::collection::vec;
691
    use proptest::strategy::BoxedStrategy;
692
    use proptest::strategy::Strategy;
693
    use proptest_arbitrary_interop::arb;
694

695
    use super::super::native_currency_amount::NativeCurrencyAmount;
696
    use super::*;
697
    use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelModifier;
698
    use crate::models::blockchain::transaction::PublicAnnouncement;
699

700
    impl Arbitrary for TimeLockWitness {
701
        /// Parameters are:
702
        ///  - release_dates : `Vec<u64>` One release date per input UTXO. 0 if the time lock
703
        ///    coin is absent.
704
        ///  - num_outputs : usize Number of outputs.
705
        ///  - num_public_announcements : usize Number of public announcements.
706
        ///  - transaction_timestamp: Timestamp determining when the transaction takes place.
707
        type Parameters = (Vec<Timestamp>, usize, usize, Timestamp);
708

709
        type Strategy = BoxedStrategy<Self>;
710

711
        fn arbitrary_with(parameters: Self::Parameters) -> Self::Strategy {
61✔
712
            let (release_dates, num_outputs, num_public_announcements, transaction_timestamp) =
61✔
713
                parameters;
61✔
714
            let num_inputs = release_dates.len();
61✔
715
            (
61✔
716
                vec(arb::<Digest>(), num_inputs),
61✔
717
                vec(NativeCurrencyAmount::arbitrary_non_negative(), num_inputs),
61✔
718
                vec(arb::<Digest>(), num_outputs),
61✔
719
                vec(NativeCurrencyAmount::arbitrary_non_negative(), num_outputs),
61✔
720
                vec(arb::<PublicAnnouncement>(), num_public_announcements),
61✔
721
                NativeCurrencyAmount::arbitrary_coinbase(),
61✔
722
                NativeCurrencyAmount::arbitrary_non_negative(),
61✔
723
            )
61✔
724
                .prop_flat_map(
61✔
725
                    move |(
61✔
726
                        input_address_seeds,
727
                        input_amounts,
728
                        output_address_seeds,
729
                        mut output_amounts,
730
                        public_announcements,
731
                        maybe_coinbase,
732
                        mut fee,
733
                    )| {
61✔
734
                        // generate inputs
61✔
735
                        let (mut input_utxos, input_lock_scripts_and_witnesses) =
61✔
736
                            PrimitiveWitness::transaction_inputs_from_address_seeds_and_amounts(
61✔
737
                                &input_address_seeds,
61✔
738
                                &input_amounts,
61✔
739
                            );
61✔
740
                        let total_inputs = input_amounts.into_iter().sum::<NativeCurrencyAmount>();
61✔
741

742
                        // add time locks to input UTXOs (changes Utxo hash)
743
                        for (utxo, release_date) in input_utxos.iter_mut().zip(release_dates.iter())
127✔
744
                        {
745
                            if !release_date.is_zero() {
127✔
746
                                let time_lock_coin = TimeLock::until(*release_date);
86✔
747
                                let mut coins = utxo.coins().to_vec();
86✔
748
                                coins.push(time_lock_coin);
86✔
749
                                *utxo = (utxo.lock_script_hash(), coins).into()
86✔
750
                            }
41✔
751
                        }
752

753
                        // generate valid output amounts
754
                        PrimitiveWitness::find_balanced_output_amounts_and_fee(
61✔
755
                            total_inputs,
61✔
756
                            maybe_coinbase,
61✔
757
                            &mut output_amounts,
61✔
758
                            &mut fee,
61✔
759
                        );
61✔
760

61✔
761
                        // generate output UTXOs
61✔
762
                        let output_utxos =
61✔
763
                            PrimitiveWitness::valid_tx_outputs_from_amounts_and_address_seeds(
61✔
764
                                &output_amounts,
61✔
765
                                &output_address_seeds,
61✔
766
                                None,
61✔
767
                            );
61✔
768

61✔
769
                        // generate primitive transaction witness and time lock witness from there
61✔
770
                        PrimitiveWitness::arbitrary_primitive_witness_with(
61✔
771
                            &input_utxos,
61✔
772
                            &input_lock_scripts_and_witnesses,
61✔
773
                            &output_utxos,
61✔
774
                            &public_announcements,
61✔
775
                            NativeCurrencyAmount::zero(),
61✔
776
                            maybe_coinbase,
61✔
777
                        )
61✔
778
                        .prop_map(move |mut transaction_primitive_witness| {
61✔
779
                            let modified_kernel = TransactionKernelModifier::default()
61✔
780
                                .timestamp(transaction_timestamp)
61✔
781
                                .modify(transaction_primitive_witness.kernel);
61✔
782

61✔
783
                            transaction_primitive_witness.kernel = modified_kernel;
61✔
784
                            TimeLockWitness::from(transaction_primitive_witness)
61✔
785
                        })
61✔
786
                        .boxed()
61✔
787
                    },
61✔
788
                )
61✔
789
                .boxed()
61✔
790
        }
61✔
791
    }
792

793
    /// Generate a `Strategy` for a [`PrimitiveWitness`] with the given numbers of
794
    /// inputs, outputs, and public announcements, with active timelocks.
795
    ///
796
    /// The UTXOs are timelocked with a release date set between `now` and six
797
    /// months from `now`.
798
    ///
799
    // Public bc used in benchmarks.
800
    #[doc(hidden)]
801
    pub fn arbitrary_primitive_witness_with_active_timelocks(
75✔
802
        num_inputs: usize,
75✔
803
        num_outputs: usize,
75✔
804
        num_announcements: usize,
75✔
805
        now: Timestamp,
75✔
806
    ) -> BoxedStrategy<PrimitiveWitness> {
75✔
807
        vec(
75✔
808
            Timestamp::arbitrary_between(now, now + Timestamp::months(6)),
75✔
809
            num_inputs + num_outputs,
75✔
810
        )
75✔
811
        .prop_flat_map(move |release_dates| {
75✔
812
            arbitrary_primitive_witness_with_timelocks(
75✔
813
                num_inputs,
75✔
814
                num_outputs,
75✔
815
                num_announcements,
75✔
816
                now,
75✔
817
                release_dates,
75✔
818
            )
75✔
819
        })
75✔
820
        .boxed()
75✔
821
    }
75✔
822

823
    /// Generate a `Strategy` for a [`PrimitiveWitness`] with the given numbers of
824
    /// inputs, outputs, and public announcements, with expired timelocks.
825
    ///
826
    /// The UTXOs are timelocked with a release date set between six months in the
827
    /// past relative to `now` and `now`.
828
    ///
829
    // Public bc used in benchmarks.
830
    #[doc(hidden)]
831
    pub fn arbitrary_primitive_witness_with_expired_timelocks(
33✔
832
        num_inputs: usize,
33✔
833
        num_outputs: usize,
33✔
834
        num_announcements: usize,
33✔
835
        now: Timestamp,
33✔
836
    ) -> BoxedStrategy<PrimitiveWitness> {
33✔
837
        vec(
33✔
838
            Timestamp::arbitrary_between(now - Timestamp::months(6), now - Timestamp::millis(1)),
33✔
839
            num_inputs + num_outputs,
33✔
840
        )
33✔
841
        .prop_flat_map(move |release_dates| {
137✔
842
            arbitrary_primitive_witness_with_timelocks(
137✔
843
                num_inputs,
137✔
844
                num_outputs,
137✔
845
                num_announcements,
137✔
846
                now,
137✔
847
                release_dates,
137✔
848
            )
137✔
849
        })
137✔
850
        .boxed()
33✔
851
    }
33✔
852

853
    #[expect(unused_variables, reason = "under development")]
854
    fn arbitrary_primitive_witness_with_timelocks(
212✔
855
        num_inputs: usize,
212✔
856
        num_outputs: usize,
212✔
857
        num_announcements: usize,
212✔
858
        now: Timestamp,
212✔
859
        release_dates: Vec<Timestamp>,
212✔
860
    ) -> BoxedStrategy<PrimitiveWitness> {
212✔
861
        (
212✔
862
            NativeCurrencyAmount::arbitrary_non_negative(),
212✔
863
            vec(arb::<Digest>(), num_inputs),
212✔
864
            vec(arb::<u64>(), num_inputs),
212✔
865
            vec(arb::<Digest>(), num_outputs),
212✔
866
            vec(arb::<u64>(), num_outputs),
212✔
867
            vec(arb::<PublicAnnouncement>(), num_announcements),
212✔
868
            arb::<u64>(),
212✔
869
            arb::<Option<u64>>(),
212✔
870
        )
212✔
871
            .prop_flat_map(
212✔
872
                move |(
212✔
873
                    total_amount,
874
                    input_address_seeds,
875
                    input_dist,
876
                    output_address_seeds,
877
                    output_dist,
878
                    public_announcements,
879
                    fee_dist,
880
                    maybe_coinbase_dist,
881
                )| {
212✔
882
                    let maybe_coinbase_dist = if num_inputs.is_zero() {
212✔
UNCOV
883
                        maybe_coinbase_dist
×
884
                    } else {
885
                        None
212✔
886
                    };
887

888
                    // distribute total amount across inputs (+ coinbase)
889
                    let mut input_denominator = input_dist.iter().map(|u| *u as f64).sum::<f64>();
427✔
890
                    if let Some(d) = maybe_coinbase_dist {
212✔
UNCOV
891
                        input_denominator += d as f64;
×
892
                    }
212✔
893
                    let input_weights = input_dist
212✔
894
                        .into_iter()
212✔
895
                        .map(|u| (u as f64) / input_denominator)
427✔
896
                        .collect_vec();
212✔
897
                    let mut input_amounts = input_weights
212✔
898
                        .into_iter()
212✔
899
                        .map(|w| total_amount.to_nau_f64() * w)
427✔
900
                        .map(|f| NativeCurrencyAmount::try_from(f).unwrap())
427✔
901
                        .collect_vec();
212✔
902
                    let maybe_coinbase = if maybe_coinbase_dist.is_some()
212✔
903
                        || input_amounts.is_empty()
212✔
904
                    {
UNCOV
905
                        Some(
×
UNCOV
906
                            total_amount
×
UNCOV
907
                                .checked_sub(
×
UNCOV
908
                                    &input_amounts.iter().copied().sum::<NativeCurrencyAmount>(),
×
UNCOV
909
                                )
×
UNCOV
910
                                .unwrap(),
×
UNCOV
911
                        )
×
912
                    } else {
913
                        let sum_of_all_but_last = input_amounts
212✔
914
                            .iter()
212✔
915
                            .rev()
212✔
916
                            .skip(1)
212✔
917
                            .copied()
212✔
918
                            .sum::<NativeCurrencyAmount>();
212✔
919
                        *input_amounts.last_mut().unwrap() =
212✔
920
                            total_amount.checked_sub(&sum_of_all_but_last).unwrap();
212✔
921
                        None
212✔
922
                    };
923

924
                    // distribute total amount across outputs
925
                    let output_denominator =
212✔
926
                        output_dist.iter().map(|u| *u as f64).sum::<f64>() + (fee_dist as f64);
386✔
927
                    let output_weights = output_dist
212✔
928
                        .into_iter()
212✔
929
                        .map(|u| (u as f64) / output_denominator)
386✔
930
                        .collect_vec();
212✔
931
                    let output_amounts = output_weights
212✔
932
                        .into_iter()
212✔
933
                        .map(|w| total_amount.to_nau_f64() * w)
386✔
934
                        .map(|f| NativeCurrencyAmount::try_from(f).unwrap())
386✔
935
                        .collect_vec();
212✔
936
                    let total_outputs =
212✔
937
                        output_amounts.iter().copied().sum::<NativeCurrencyAmount>();
212✔
938
                    let fee = total_amount.checked_sub(&total_outputs).unwrap();
212✔
939

212✔
940
                    let (mut input_utxos, input_lock_scripts_and_witnesses) =
212✔
941
                        PrimitiveWitness::transaction_inputs_from_address_seeds_and_amounts(
212✔
942
                            &input_address_seeds,
212✔
943
                            &input_amounts,
212✔
944
                        );
212✔
945
                    let total_inputs = input_amounts.iter().copied().sum::<NativeCurrencyAmount>();
212✔
946

212✔
947
                    assert_eq!(
212✔
948
                        total_inputs + maybe_coinbase.unwrap_or(NativeCurrencyAmount::coins(0)),
212✔
949
                        total_outputs + fee
212✔
950
                    );
212✔
951
                    let mut output_utxos =
212✔
952
                        PrimitiveWitness::valid_tx_outputs_from_amounts_and_address_seeds(
212✔
953
                            &output_amounts,
212✔
954
                            &output_address_seeds,
212✔
955
                            None,
212✔
956
                        );
212✔
957
                    let mut counter = 0usize;
212✔
958
                    for utxo in &mut input_utxos {
639✔
959
                        let release_date = release_dates[counter];
427✔
960
                        let time_lock = TimeLock::until(release_date);
427✔
961
                        let mut coins = utxo.coins().to_vec();
427✔
962
                        coins.push(time_lock);
427✔
963
                        *utxo = Utxo::from((utxo.lock_script_hash(), coins));
427✔
964
                        counter += 1;
427✔
965
                    }
427✔
966
                    for utxo in &mut output_utxos {
598✔
967
                        let mut coins = utxo.coins().to_vec();
386✔
968
                        coins.push(TimeLock::until(release_dates[counter]));
386✔
969
                        *utxo = Utxo::from((utxo.lock_script_hash(), coins));
386✔
970
                        counter += 1;
386✔
971
                    }
386✔
972
                    let release_dates = release_dates.clone();
212✔
973

212✔
974
                    let merge_bit = false;
212✔
975
                    PrimitiveWitness::arbitrary_primitive_witness_with_timestamp_and(
212✔
976
                        &input_utxos,
212✔
977
                        &input_lock_scripts_and_witnesses,
212✔
978
                        &output_utxos,
212✔
979
                        &public_announcements,
212✔
980
                        fee,
212✔
981
                        maybe_coinbase,
212✔
982
                        now,
212✔
983
                        merge_bit,
212✔
984
                    )
212✔
985
                    .prop_map(move |primitive_witness_template| {
212✔
986
                        let mut primitive_witness = primitive_witness_template.clone();
212✔
987
                        let modified_kernel = TransactionKernelModifier::default()
212✔
988
                            .timestamp(now)
212✔
989
                            .modify(primitive_witness.kernel);
212✔
990

212✔
991
                        primitive_witness.kernel = modified_kernel;
212✔
992
                        primitive_witness
212✔
993
                    })
212✔
994
                },
212✔
995
            )
212✔
996
            .boxed()
212✔
997
    }
212✔
998
}
999

1000
#[cfg(test)]
1001
mod test {
1002
    use proptest::collection::vec;
1003
    use proptest::prelude::Arbitrary;
1004
    use proptest::prelude::Strategy;
1005
    use proptest::prop_assert;
1006
    use proptest::prop_assert_eq;
1007
    use proptest::strategy::Just;
1008
    use proptest::test_runner::TestRunner;
1009
    use proptest_arbitrary_interop::arb;
1010
    use tasm_lib::twenty_first::math::tip5::Tip5;
1011
    use test_strategy::proptest;
1012

1013
    use super::neptune_arbitrary::arbitrary_primitive_witness_with_active_timelocks;
1014
    use super::neptune_arbitrary::arbitrary_primitive_witness_with_expired_timelocks;
1015
    use super::*;
1016
    use crate::models::proof_abstractions::tasm::builtins as tasm;
1017
    use crate::models::proof_abstractions::tasm::program::test::ConsensusProgramSpecification;
1018

1019
    impl ConsensusProgramSpecification for TimeLock {
1020
        #[expect(clippy::needless_return)]
1021
        fn source(&self) {
81✔
1022
            // get in the current program's hash digest
81✔
1023
            let self_digest: Digest = tasm::own_program_digest();
81✔
1024

81✔
1025
            // read standard input:
81✔
1026
            //  - transaction kernel mast hash
81✔
1027
            //  - input salted utxos digest
81✔
1028
            //  - output salted utxos digest
81✔
1029
            // (All type scripts take this triple as input.)
81✔
1030
            let tx_kernel_digest: Digest = tasm::tasmlib_io_read_stdin___digest();
81✔
1031
            let input_utxos_digest: Digest = tasm::tasmlib_io_read_stdin___digest();
81✔
1032
            let _output_utxos_digest: Digest = tasm::tasmlib_io_read_stdin___digest();
81✔
1033

81✔
1034
            // divine the timestamp and authenticate it against the kernel mast hash
81✔
1035
            let leaf_index: u32 = 5;
81✔
1036
            let timestamp: BFieldElement = tasm::tasmlib_io_read_secin___bfe();
81✔
1037
            let leaf: Digest = Tip5::hash_varlen(&timestamp.encode());
81✔
1038
            let tree_height: u32 = 3;
81✔
1039
            tasm::tasmlib_hashing_merkle_verify(tx_kernel_digest, leaf_index, leaf, tree_height);
81✔
1040

81✔
1041
            // get pointers to objects living in nondeterministic memory:
81✔
1042
            //  - input Salted UTXOs
81✔
1043
            let input_utxos_pointer: u64 = tasm::tasmlib_io_read_secin___bfe().value();
81✔
1044

81✔
1045
            // it's important to read the outputs digest too, but we actually don't care about
81✔
1046
            // the output UTXOs (in this type script)
81✔
1047
            let _output_utxos_pointer: u64 = tasm::tasmlib_io_read_secin___bfe().value();
81✔
1048

81✔
1049
            // authenticate salted input UTXOs against the digest that was read from stdin
81✔
1050
            let input_salted_utxos: SaltedUtxos =
81✔
1051
                tasm::decode_from_memory(BFieldElement::new(input_utxos_pointer));
81✔
1052
            let input_salted_utxos_digest: Digest = Tip5::hash(&input_salted_utxos);
81✔
1053
            assert_eq!(input_salted_utxos_digest, input_utxos_digest);
81✔
1054

1055
            // iterate over inputs
1056
            let input_utxos = input_salted_utxos.utxos;
81✔
1057
            let mut i = 0;
81✔
1058
            while i < input_utxos.len() {
196✔
1059
                // get coins
1060
                let coins = input_utxos[i].coins();
146✔
1061

146✔
1062
                // if this typescript is present
146✔
1063
                let mut j: usize = 0;
146✔
1064
                while j < coins.len() {
366✔
1065
                    let coin: &Coin = &coins[j];
251✔
1066
                    if coin.type_script_hash == self_digest {
251✔
1067
                        // extract state
1068
                        let state: &Vec<BFieldElement> = &coin.state;
105✔
1069

105✔
1070
                        // assert format
105✔
1071
                        assert!(state.len() == 1);
105✔
1072

1073
                        // extract timestamp
1074
                        let release_date: BFieldElement = state[0];
105✔
1075

105✔
1076
                        // test time lock
105✔
1077
                        assert!(release_date.value() < timestamp.value());
105✔
1078
                    }
146✔
1079
                    j += 1;
220✔
1080
                }
1081
                i += 1;
115✔
1082
            }
1083

1084
            return;
50✔
1085
        }
50✔
1086
    }
1087

1088
    #[proptest(cases = 20)]
100✔
1089
    fn test_unlocked(
1090
        #[strategy(1usize..=3)] _num_inputs: usize,
1✔
1091
        #[strategy(1usize..=3)] _num_outputs: usize,
1✔
1092
        #[strategy(1usize..=3)] _num_public_announcements: usize,
1✔
1093
        #[strategy(vec(Just(Timestamp::zero()), #_num_inputs))] _release_dates: Vec<Timestamp>,
20✔
1094
        #[strategy(Just::<Timestamp>(#_release_dates.iter().copied().min().unwrap()))]
1095
        _transaction_timestamp: Timestamp,
20✔
1096
        #[strategy(
1097
            TimeLockWitness::arbitrary_with((
1098
                #_release_dates,
1099
                #_num_outputs,
1100
                #_num_public_announcements,
1101
                #_transaction_timestamp,
1102
            ))
1103
        )]
1104
        time_lock_witness: TimeLockWitness,
20✔
1105
    ) {
1106
        let rust_result = TimeLock.run_rust(
1107
            &time_lock_witness.standard_input(),
1108
            time_lock_witness.nondeterminism(),
1109
        );
1110
        prop_assert!(
1111
            rust_result.is_ok(),
1112
            "time lock program did not halt gracefully"
1113
        );
1114
        let tasm_result = TimeLock.run_tasm(
1115
            &time_lock_witness.standard_input(),
1116
            time_lock_witness.nondeterminism(),
1117
        );
1118
        prop_assert!(
1119
            tasm_result.is_ok(),
1120
            "time lock program did not halt gracefully"
1121
        );
1122
        prop_assert_eq!(rust_result.unwrap(), tasm_result.unwrap());
1123
    }
1124

1125
    #[test]
1126
    fn tx_timestamp_same_as_release_time_must_fail() {
1✔
1127
        // Verify use of `>`, not `>=`.
1✔
1128
        let release_date = Timestamp::now();
1✔
1129
        let mut test_runner = TestRunner::deterministic();
1✔
1130
        let time_lock_witness =
1✔
1131
            TimeLockWitness::arbitrary_with((vec![release_date], 1, 0, release_date))
1✔
1132
                .new_tree(&mut test_runner)
1✔
1133
                .unwrap()
1✔
1134
                .current();
1✔
1135
        assert!(
1✔
1136
            TimeLock {}
1✔
1137
                .run_rust(
1✔
1138
                    &time_lock_witness.standard_input(),
1✔
1139
                    time_lock_witness.nondeterminism(),
1✔
1140
                )
1✔
1141
                .is_err(),
1✔
1142
            "time lock program failed to panic"
×
1143
        );
1144
        assert!(
1✔
1145
            TimeLock {}
1✔
1146
                .run_tasm(
1✔
1147
                    &time_lock_witness.standard_input(),
1✔
1148
                    time_lock_witness.nondeterminism(),
1✔
1149
                )
1✔
1150
                .is_err(),
1✔
1151
            "time lock program failed to panic"
×
1152
        );
1153
    }
1✔
1154

1155
    #[proptest(cases = 20)]
100✔
1156
    fn test_locked(
1157
        #[strategy(1usize..=3)] _num_inputs: usize,
1✔
1158
        #[strategy(1usize..=3)] _num_outputs: usize,
1✔
1159
        #[strategy(1usize..=3)] _num_public_announcements: usize,
1✔
1160
        #[strategy(
1161
            vec(
1162
                Timestamp::arbitrary_between(
1163
                    Timestamp::now() - Timestamp::days(7),
1164
                    Timestamp::now() - Timestamp::days(1),
1165
                ),
1166
                #_num_inputs,
1167
            )
1168
        )]
1169
        _release_dates: Vec<Timestamp>,
20✔
1170
        #[strategy(Just::<Timestamp>(#_release_dates.iter().copied().max().unwrap()))]
1171
        _tx_timestamp: Timestamp,
20✔
1172
        #[strategy(
1173
            TimeLockWitness::arbitrary_with((
1174
                #_release_dates,
1175
                #_num_outputs,
1176
                #_num_public_announcements,
1177
                #_tx_timestamp,
1178
            ))
1179
        )]
1180
        time_lock_witness: TimeLockWitness,
20✔
1181
    ) {
1182
        println!("now: {}", Timestamp::now());
1183
        prop_assert!(
1184
            TimeLock {}
1185
                .run_rust(
1186
                    &time_lock_witness.standard_input(),
1187
                    time_lock_witness.nondeterminism(),
1188
                )
1189
                .is_err(),
1190
            "time lock program failed to panic"
1191
        );
1192
        prop_assert!(
1193
            TimeLock {}
1194
                .run_tasm(
1195
                    &time_lock_witness.standard_input(),
1196
                    time_lock_witness.nondeterminism(),
1197
                )
1198
                .is_err(),
1199
            "time lock program failed to panic"
1200
        );
1201
    }
1202

1203
    #[proptest(cases = 20)]
100✔
1204
    fn test_released(
1205
        #[strategy(1usize..=3)] _num_inputs: usize,
1✔
1206
        #[strategy(1usize..=3)] _num_outputs: usize,
1✔
1207
        #[strategy(1usize..=3)] _num_public_announcements: usize,
1✔
1208
        #[strategy(
1209
            vec(
1210
                Timestamp::arbitrary_between(
1211
                    Timestamp::now() - Timestamp::days(7),
1212
                    Timestamp::now() - Timestamp::days(1),
1213
                ),
1214
                #_num_inputs,
1215
            )
1216
        )]
1217
        _release_dates: Vec<Timestamp>,
20✔
1218
        #[strategy(Just::<Timestamp>(#_release_dates.iter().copied().max().unwrap()))]
1219
        _tx_timestamp: Timestamp,
20✔
1220
        #[strategy(
1221
            TimeLockWitness::arbitrary_with((
1222
                #_release_dates,
1223
                #_num_outputs,
1224
                #_num_public_announcements,
1225
                #_tx_timestamp + Timestamp::days(1),
1226
            ))
1227
        )]
1228
        time_lock_witness: TimeLockWitness,
20✔
1229
    ) {
1230
        println!("now: {}", Timestamp::now());
1231
        let rust_result = TimeLock.run_rust(
1232
            &time_lock_witness.standard_input(),
1233
            time_lock_witness.nondeterminism(),
1234
        );
1235
        prop_assert!(
1236
            rust_result.is_ok(),
1237
            "time lock program did not halt gracefully"
1238
        );
1239
        let tasm_result = TimeLock.run_tasm(
1240
            &time_lock_witness.standard_input(),
1241
            time_lock_witness.nondeterminism(),
1242
        );
1243
        prop_assert!(
1244
            tasm_result.is_ok(),
1245
            "time lock program did not halt gracefully"
1246
        );
1247
        prop_assert_eq!(rust_result.unwrap(), tasm_result.unwrap());
1248
    }
1249

1250
    #[proptest(cases = 5)]
15✔
1251
    fn primitive_witness_with_active_timelocks_is_invalid(
1252
        #[strategy(arb::<Timestamp>())] _now: Timestamp,
1✔
1253
        #[strategy(arbitrary_primitive_witness_with_active_timelocks(2, 2, 2, #_now))]
1254
        primitive_witness: PrimitiveWitness,
5✔
1255
    ) {
1256
        // Negative test: Primitive witness spending inputs that are timelocked
1257
        // must fail to validate.
1258
        let rt = crate::tests::tokio_runtime();
1259
        prop_assert!(rt.block_on(primitive_witness.validate()).is_err());
1260
    }
1261

1262
    #[proptest(cases = 10)]
30✔
1263
    fn arbitrary_primitive_witness_with_active_timelocks_fails(
1264
        #[strategy(arb::<Timestamp>())] _now: Timestamp,
1✔
1265
        #[strategy(arbitrary_primitive_witness_with_active_timelocks(2, 2, 2, #_now))]
1266
        primitive_witness: PrimitiveWitness,
10✔
1267
    ) {
1268
        let time_lock_witness = TimeLockWitness::from(primitive_witness);
1269

1270
        prop_assert!(
1271
            TimeLock {}
1272
                .run_rust(
1273
                    &time_lock_witness.standard_input(),
1274
                    time_lock_witness.nondeterminism(),
1275
                )
1276
                .is_err(),
1277
            "time lock program failed to panic"
1278
        );
1279
        prop_assert!(
1280
            TimeLock {}
1281
                .run_tasm(
1282
                    &time_lock_witness.standard_input(),
1283
                    time_lock_witness.nondeterminism(),
1284
                )
1285
                .is_err(),
1286
            "time lock program failed to panic"
1287
        );
1288
    }
1289

1290
    #[proptest(cases = 10)]
30✔
1291
    fn arbitrary_primitive_witness_with_expired_timelocks_passes(
1292
        #[strategy(arb::<Timestamp>())] _now: Timestamp,
1✔
1293
        #[strategy(arbitrary_primitive_witness_with_expired_timelocks(2, 2, 2, #_now))]
1294
        primitive_witness: PrimitiveWitness,
10✔
1295
    ) {
1296
        let time_lock_witness = TimeLockWitness::from(primitive_witness);
1297

1298
        let rust_result = TimeLock.run_rust(
1299
            &time_lock_witness.standard_input(),
1300
            time_lock_witness.nondeterminism(),
1301
        );
1302
        prop_assert!(
1303
            rust_result.is_ok(),
1304
            "time lock program did not halt gracefully"
1305
        );
1306
        let tasm_result = TimeLock.run_tasm(
1307
            &time_lock_witness.standard_input(),
1308
            time_lock_witness.nondeterminism(),
1309
        );
1310
        prop_assert!(
1311
            tasm_result.is_ok(),
1312
            "time lock program did not halt gracefully"
1313
        );
1314
        prop_assert_eq!(tasm_result.unwrap(), rust_result.unwrap());
1315
    }
1316
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc