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

Neptune-Crypto / neptune-core / 14052448145

25 Mar 2025 05:35AM UTC coverage: 84.189% (-0.02%) from 84.209%
14052448145

Pull #389

github

web-flow
Merge 88f602a6c into 187d28fd3
Pull Request #389: doc : RPC md book documentation

50722 of 60248 relevant lines covered (84.19%)

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

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

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

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

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

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

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

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

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

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

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

3,526✔
659
        Self {
3,526✔
660
            release_dates,
3,526✔
661
            input_utxos: salted_input_utxos,
3,526✔
662
            transaction_kernel,
3,526✔
663
        }
3,526✔
664
    }
3,526✔
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())
116✔
744
                        {
745
                            if !release_date.is_zero() {
116✔
746
                                let time_lock_coin = TimeLock::until(*release_date);
73✔
747
                                let mut coins = utxo.coins().to_vec();
73✔
748
                                coins.push(time_lock_coin);
73✔
749
                                *utxo = (utxo.lock_script_hash(), coins).into()
73✔
750
                            }
43✔
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
×
884
                    } else {
885
                        None
193✔
886
                    };
887

888
                    // distribute total amount across inputs (+ coinbase)
889
                    let mut input_denominator = input_dist.iter().map(|u| *u as f64).sum::<f64>();
390✔
890
                    if let Some(d) = maybe_coinbase_dist {
193✔
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)
390✔
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)
390✔
900
                        .map(|f| NativeCurrencyAmount::try_from(f).unwrap())
390✔
901
                        .collect_vec();
193✔
902
                    let maybe_coinbase = if maybe_coinbase_dist.is_some()
193✔
903
                        || input_amounts.is_empty()
193✔
904
                    {
905
                        Some(
×
906
                            total_amount
×
907
                                .checked_sub(
×
908
                                    &input_amounts.iter().copied().sum::<NativeCurrencyAmount>(),
×
909
                                )
×
910
                                .unwrap(),
×
911
                        )
×
912
                    } else {
913
                        let sum_of_all_but_last = input_amounts
193✔
914
                            .iter()
193✔
915
                            .rev()
193✔
916
                            .skip(1)
193✔
917
                            .copied()
193✔
918
                            .sum::<NativeCurrencyAmount>();
193✔
919
                        *input_amounts.last_mut().unwrap() =
193✔
920
                            total_amount.checked_sub(&sum_of_all_but_last).unwrap();
193✔
921
                        None
193✔
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);
375✔
927
                    let output_weights = output_dist
193✔
928
                        .into_iter()
193✔
929
                        .map(|u| (u as f64) / output_denominator)
375✔
930
                        .collect_vec();
193✔
931
                    let output_amounts = output_weights
193✔
932
                        .into_iter()
193✔
933
                        .map(|w| total_amount.to_nau_f64() * w)
375✔
934
                        .map(|f| NativeCurrencyAmount::try_from(f).unwrap())
375✔
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 {
583✔
959
                        let release_date = release_dates[counter];
390✔
960
                        let time_lock = TimeLock::until(release_date);
390✔
961
                        let mut coins = utxo.coins().to_vec();
390✔
962
                        coins.push(time_lock);
390✔
963
                        *utxo = Utxo::from((utxo.lock_script_hash(), coins));
390✔
964
                        counter += 1;
390✔
965
                    }
390✔
966
                    for utxo in &mut output_utxos {
568✔
967
                        let mut coins = utxo.coins().to_vec();
375✔
968
                        coins.push(TimeLock::until(release_dates[counter]));
375✔
969
                        *utxo = Utxo::from((utxo.lock_script_hash(), coins));
375✔
970
                        counter += 1;
375✔
971
                    }
375✔
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() {
337✔
1066
                    let coin: &Coin = &coins[j];
231✔
1067
                    if coin.type_script_hash == self_digest {
231✔
1068
                        // extract state
1069
                        let state: &Vec<BFieldElement> = &coin.state;
94✔
1070

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

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

94✔
1077
                        // test time lock
94✔
1078
                        assert!(release_date.value() < timestamp.value());
94✔
1079
                    }
137✔
1080
                    j += 1;
200✔
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