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

Neptune-Crypto / neptune-core / 13927738105

18 Mar 2025 03:56PM UTC coverage: 84.335% (+0.06%) from 84.279%
13927738105

Pull #512

github

web-flow
Merge b521aa39c into ee3795966
Pull Request #512: `proptest_state_machine` over `PeerMessage`

9 of 25 new or added lines in 6 files covered. (36.0%)

34 existing lines in 4 files now uncovered.

50810 of 60248 relevant lines covered (84.33%)

176238.36 hits per line

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

99.16
/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 {
274,975✔
40
        Coin {
274,975✔
41
            type_script_hash: TimeLock.hash(),
274,975✔
42
            state: vec![date.0],
274,975✔
43
        }
274,975✔
44
    }
274,975✔
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,706✔
49
        utxo.coins()
1,706✔
50
            .iter()
1,706✔
51
            .find_map(Coin::release_date)
1,706✔
52
            .unwrap_or_else(Timestamp::zero)
1,706✔
53
    }
1,706✔
54
}
55

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

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

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

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

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

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

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

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

580
        *HASH.get_or_init(|| self.program().hash())
303,238✔
581
    }
303,238✔
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,732✔
601
        let mut memory: HashMap<BFieldElement, BFieldElement> = HashMap::new();
3,732✔
602
        let input_salted_utxos_address = FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
3,732✔
603
        let output_salted_utxos_address = encode_to_memory::<TimeLockWitnessMemory>(
3,732✔
604
            &mut memory,
3,732✔
605
            input_salted_utxos_address,
3,732✔
606
            &self.input_utxos,
3,732✔
607
        );
3,732✔
608
        let individual_tokens = vec![
3,732✔
609
            self.transaction_kernel.timestamp.0,
3,732✔
610
            input_salted_utxos_address,
3,732✔
611
            output_salted_utxos_address,
3,732✔
612
        ];
3,732✔
613
        let mast_path = self
3,732✔
614
            .transaction_kernel
3,732✔
615
            .mast_path(TransactionKernelField::Timestamp)
3,732✔
616
            .clone();
3,732✔
617
        NonDeterminism::new(individual_tokens)
3,732✔
618
            .with_digests(mast_path)
3,732✔
619
            .with_ram(memory)
3,732✔
620
    }
3,732✔
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,570✔
645
        TypeScriptAndWitness::new_with_nondeterminism(TimeLock.program(), self.nondeterminism())
3,570✔
646
    }
3,570✔
647

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

3,570✔
659
        Self {
3,570✔
660
            release_dates,
3,570✔
661
            input_utxos: salted_input_utxos,
3,570✔
662
            transaction_kernel,
3,570✔
663
        }
3,570✔
664
    }
3,570✔
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())
119✔
744
                        {
745
                            if !release_date.is_zero() {
119✔
746
                                let time_lock_coin = TimeLock::until(*release_date);
80✔
747
                                let mut coins = utxo.coins().to_vec();
80✔
748
                                coins.push(time_lock_coin);
80✔
749
                                *utxo = (utxo.lock_script_hash(), coins).into()
80✔
750
                            }
39✔
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(
27✔
832
        num_inputs: usize,
27✔
833
        num_outputs: usize,
27✔
834
        num_announcements: usize,
27✔
835
        now: Timestamp,
27✔
836
    ) -> BoxedStrategy<PrimitiveWitness> {
27✔
837
        vec(
27✔
838
            Timestamp::arbitrary_between(now - Timestamp::months(6), now - Timestamp::millis(1)),
27✔
839
            num_inputs + num_outputs,
27✔
840
        )
27✔
841
        .prop_flat_map(move |release_dates| {
118✔
842
            arbitrary_primitive_witness_with_timelocks(
118✔
843
                num_inputs,
118✔
844
                num_outputs,
118✔
845
                num_announcements,
118✔
846
                now,
118✔
847
                release_dates,
118✔
848
            )
118✔
849
        })
118✔
850
        .boxed()
27✔
851
    }
27✔
852

853
    #[expect(unused_variables, reason = "under development")]
854
    fn arbitrary_primitive_witness_with_timelocks(
193✔
855
        num_inputs: usize,
193✔
856
        num_outputs: usize,
193✔
857
        num_announcements: usize,
193✔
858
        now: Timestamp,
193✔
859
        release_dates: Vec<Timestamp>,
193✔
860
    ) -> BoxedStrategy<PrimitiveWitness> {
193✔
861
        (
193✔
862
            NativeCurrencyAmount::arbitrary_non_negative(),
193✔
863
            vec(arb::<Digest>(), num_inputs),
193✔
864
            vec(arb::<u64>(), num_inputs),
193✔
865
            vec(arb::<Digest>(), num_outputs),
193✔
866
            vec(arb::<u64>(), num_outputs),
193✔
867
            vec(arb::<PublicAnnouncement>(), num_announcements),
193✔
868
            arb::<u64>(),
193✔
869
            arb::<Option<u64>>(),
193✔
870
        )
193✔
871
            .prop_flat_map(
193✔
872
                move |(
193✔
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
                )| {
193✔
882
                    let maybe_coinbase_dist = if num_inputs.is_zero() {
193✔
883
                        maybe_coinbase_dist
2✔
884
                    } else {
885
                        None
191✔
886
                    };
887

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

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

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

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

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

193✔
991
                        primitive_witness.kernel = modified_kernel;
193✔
992
                        primitive_witness
193✔
993
                    })
193✔
994
                },
193✔
995
            )
193✔
996
            .boxed()
193✔
997
    }
193✔
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
    use tokio::runtime::Runtime;
1013

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

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

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

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

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

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

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

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

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

98✔
1071
                        // assert format
98✔
1072
                        assert!(state.len() == 1);
98✔
1073

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

98✔
1077
                        // test time lock
98✔
1078
                        assert!(release_date.value() < timestamp.value());
98✔
1079
                    }
137✔
1080
                    j += 1;
204✔
1081
                }
1082
                i += 1;
106✔
1083
            }
1084

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

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

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

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

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

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

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

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

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

1300
        let rust_result = TimeLock.run_rust(
1301
            &time_lock_witness.standard_input(),
1302
            time_lock_witness.nondeterminism(),
1303
        );
1304
        prop_assert!(
1305
            rust_result.is_ok(),
1306
            "time lock program did not halt gracefully"
1307
        );
1308
        let tasm_result = TimeLock.run_tasm(
1309
            &time_lock_witness.standard_input(),
1310
            time_lock_witness.nondeterminism(),
1311
        );
1312
        prop_assert!(
1313
            tasm_result.is_ok(),
1314
            "time lock program did not halt gracefully"
1315
        );
1316
        prop_assert_eq!(tasm_result.unwrap(), rust_result.unwrap());
1317
    }
1318
}
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