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

MinaProtocol / mina / 3409

26 Feb 2025 01:10PM UTC coverage: 32.353% (-28.4%) from 60.756%
3409

push

buildkite

web-flow
Merge pull request #16687 from MinaProtocol/dw/merge-compatible-into-develop-20250225

Merge compatible into develop [20250224]

23144 of 71535 relevant lines covered (32.35%)

16324.05 hits per line

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

0.0
/src/app/zkapps_examples/zkapps_examples.ml
1
open Core_kernel
2
open Async_kernel
3
open Snark_params.Tick
4
open Snark_params.Tick.Run
5
open Currency
6
open Signature_lib
7
open Mina_base
8

9
module Account_update_under_construction = struct
10
  module In_circuit = struct
11
    module Account_condition = struct
12
      type t = { state_proved : Boolean.var option }
13

14
      let create () = { state_proved = None }
×
15

16
      let to_predicate ({ state_proved } : t) :
17
          Zkapp_precondition.Account.Checked.t =
18
        (* TODO: Don't do this. *)
19
        let var_of_t (type var value) (typ : (var, value) Typ.t) (x : value) :
×
20
            var =
21
          let open Snark_params.Tick in
×
22
          let (Typ typ) = typ in
23
          let fields, aux = typ.value_to_fields x in
24
          let fields = Array.map ~f:Field.Var.constant fields in
×
25
          typ.var_of_fields (fields, aux)
×
26
        in
27
        let default =
28
          var_of_t
29
            (Account_update.Account_precondition.typ ())
×
30
            { balance = Ignore
31
            ; nonce = Ignore
32
            ; receipt_chain_hash = Ignore
33
            ; delegate = Ignore
34
            ; state =
35
                [ Ignore
36
                ; Ignore
37
                ; Ignore
38
                ; Ignore
39
                ; Ignore
40
                ; Ignore
41
                ; Ignore
42
                ; Ignore
43
                ]
44
            ; action_state = Ignore
45
            ; proved_state = Ignore
46
            ; is_new = Ignore
47
            }
48
        in
49
        let proved_state =
×
50
          (* TODO: This is not great. *)
51
          match state_proved with
52
          | None ->
×
53
              default.proved_state
54
          | Some state_proved ->
×
55
              Zkapp_basic.Or_ignore.Checked.make_unsafe Boolean.true_
×
56
                state_proved
57
        in
58
        { default with proved_state }
59

60
      let assert_state_proved (t : t) =
61
        match t.state_proved with
×
62
        | None ->
×
63
            { state_proved = Some Boolean.true_ }
64
        | Some b ->
×
65
            Boolean.Assert.( = ) b Boolean.true_ ;
66
            t
×
67

68
      let assert_state_unproved (t : t) =
69
        match t.state_proved with
×
70
        | None ->
×
71
            { state_proved = Some Boolean.false_ }
72
        | Some b ->
×
73
            Boolean.Assert.( = ) b Boolean.false_ ;
74
            t
×
75
    end
76

77
    module Update = struct
78
      type t = { app_state : Field.t option Zkapp_state.V.t }
79

80
      let create () =
81
        { app_state = [ None; None; None; None; None; None; None; None ] }
×
82

83
      let to_zkapp_command_update ({ app_state } : t) :
84
          Account_update.Update.Checked.t =
85
        (* TODO: Don't do this. *)
86
        let var_of_t (type var value) (typ : (var, value) Typ.t) (x : value) :
×
87
            var =
88
          let open Snark_params.Tick in
×
89
          let (Typ typ) = typ in
90
          let fields, aux = typ.value_to_fields x in
91
          let fields = Array.map ~f:Field.Var.constant fields in
×
92
          typ.var_of_fields (fields, aux)
×
93
        in
94
        let default =
95
          var_of_t
96
            (Account_update.Update.typ ())
×
97
            { app_state = [ Keep; Keep; Keep; Keep; Keep; Keep; Keep; Keep ]
98
            ; delegate = Keep
99
            ; verification_key = Keep
100
            ; permissions = Keep
101
            ; zkapp_uri = Keep
102
            ; token_symbol = Keep
103
            ; timing = Keep
104
            ; voting_for = Keep
105
            }
106
        in
107
        let app_state =
×
108
          Pickles_types.Vector.map app_state ~f:(function
109
            | None ->
×
110
                (* TODO: Shouldn't need to know that the dummy is Field.zero
111
                   here. Functor, perhaps?
112
                *)
113
                Zkapp_basic.Set_or_keep.Checked.keep ~dummy:Field.zero
114
            | Some x ->
×
115
                Zkapp_basic.Set_or_keep.Checked.set x )
116
        in
117
        { default with app_state }
×
118

119
      let set_full_state app_state (_t : t) =
120
        match app_state with
×
121
        | [ a0; a1; a2; a3; a4; a5; a6; a7 ] ->
×
122
            { app_state =
123
                [ Some a0
124
                ; Some a1
125
                ; Some a2
126
                ; Some a3
127
                ; Some a4
128
                ; Some a5
129
                ; Some a6
130
                ; Some a7
131
                ]
132
            }
133
        | _ ->
×
134
            failwith "Incorrect length of app_state"
135

136
      let set_state i value (t : t) =
137
        if i < 0 || i >= 8 then failwith "Incorrect index" ;
×
138
        { app_state =
×
139
            Pickles_types.Vector.mapi t.app_state ~f:(fun j old_value ->
×
140
                if i = j then Some value else old_value )
×
141
        }
142
    end
143

144
    module Events = struct
145
      type t = { events : Field.t array list }
146

147
      let create () = { events = [] }
×
148

149
      let add_events t events : t = { events = t.events @ events }
×
150

151
      let to_zkapp_command_events ({ events } : t) : Zkapp_account.Events.var =
152
        let open Core_kernel in
×
153
        let empty_var : Zkapp_account.Events.var =
154
          exists ~compute:(fun () -> []) Zkapp_account.Events.typ
×
155
        in
156
        (* matches fold_right in Zkapp_account.Events.hash *)
157
        List.fold_right events ~init:empty_var
158
          ~f:(Fn.flip Zkapp_account.Events.push_to_data_as_hash)
×
159
    end
160

161
    module Actions = struct
162
      type t = { actions : Field.t array list }
163

164
      let create () = { actions = [] }
×
165

166
      let add_actions t actions : t = { actions = t.actions @ actions }
×
167

168
      let to_zkapp_command_actions ({ actions } : t) : Zkapp_account.Actions.var
169
          =
170
        let open Core_kernel in
×
171
        let empty_var : Zkapp_account.Events.var =
172
          exists ~compute:(fun () -> []) Zkapp_account.Actions.typ
×
173
        in
174
        (* matches fold_right in Zkapp_account.Actions.hash *)
175
        List.fold_right actions ~init:empty_var
176
          ~f:(Fn.flip Zkapp_account.Actions.push_to_data_as_hash)
×
177
    end
178

179
    module Calls_kind = struct
180
      type t =
181
        | No_calls
182
        | Rev_calls of
183
            ( Zkapp_call_forest.Checked.account_update
184
            * Zkapp_call_forest.Checked.t )
185
            list
186
        | Calls of Zkapp_call_forest.Checked.t
187
    end
188

189
    module Authorization_kind = struct
190
      type t = { is_signed : Boolean.var; is_proved : Boolean.var }
191
    end
192

193
    type t =
194
      { public_key : Public_key.Compressed.var
195
      ; token_id : Token_id.Checked.t
196
      ; balance_change : Currency.Amount.Signed.Checked.t
197
      ; may_use_token : Account_update.May_use_token.Checked.t
198
      ; account_condition : Account_condition.t
199
      ; update : Update.t
200
      ; calls : Calls_kind.t
201
      ; call_data : Field.t option
202
      ; events : Events.t
203
      ; actions : Actions.t
204
      ; authorization_kind : Authorization_kind.t
205
      ; vk_hash : Field.t Option.t
206
      }
207

208
    let create ~public_key ?vk_hash
209
        ?(token_id = Token_id.(Checked.constant default))
×
210
        ?(may_use_token = Account_update.May_use_token.Checked.constant No) () =
×
211
      { public_key
×
212
      ; token_id
213
      ; balance_change =
214
          Amount.Signed.Checked.constant { magnitude = Amount.zero; sgn = Pos }
×
215
      ; may_use_token
216
      ; account_condition = Account_condition.create ()
×
217
      ; update = Update.create ()
×
218
      ; calls = No_calls
219
      ; call_data = None
220
      ; events = Events.create ()
×
221
      ; actions = Actions.create ()
×
222
      ; authorization_kind =
223
          { is_signed = Boolean.false_; is_proved = Boolean.true_ }
224
      ; vk_hash
225
      }
226

227
    let to_account_update_and_calls (t : t) :
228
        Account_update.Body.Checked.t * Zkapp_call_forest.Checked.t =
229
      (* TODO: Don't do this. *)
230
      let var_of_t (type var value) (typ : (var, value) Typ.t) (x : value) : var
×
231
          =
232
        let open Snark_params.Tick in
×
233
        let (Typ typ) = typ in
234
        let fields, aux = typ.value_to_fields x in
235
        let fields = Array.map ~f:Field.Var.constant fields in
×
236
        typ.var_of_fields (fields, aux)
×
237
      in
238
      let account_update : Account_update.Body.Checked.t =
239
        { public_key = t.public_key
240
        ; token_id = t.token_id
241
        ; update = Update.to_zkapp_command_update t.update
×
242
        ; balance_change = t.balance_change
243
        ; increment_nonce = Boolean.false_
244
        ; call_data = Option.value ~default:Field.zero t.call_data
×
245
        ; events = Events.to_zkapp_command_events t.events
×
246
        ; actions = Actions.to_zkapp_command_actions t.actions
×
247
        ; preconditions =
248
            { Account_update.Preconditions.Checked.network =
249
                var_of_t Zkapp_precondition.Protocol_state.typ
×
250
                  { snarked_ledger_hash = Ignore
251
                  ; blockchain_length = Ignore
252
                  ; min_window_density = Ignore
253
                  ; total_currency = Ignore
254
                  ; global_slot_since_genesis = Ignore
255
                  ; staking_epoch_data =
256
                      { ledger =
257
                          { Epoch_ledger.Poly.hash = Ignore
258
                          ; total_currency = Ignore
259
                          }
260
                      ; seed = Ignore
261
                      ; start_checkpoint = Ignore
262
                      ; lock_checkpoint = Ignore
263
                      ; epoch_length = Ignore
264
                      }
265
                  ; next_epoch_data =
266
                      { ledger =
267
                          { Epoch_ledger.Poly.hash = Ignore
268
                          ; total_currency = Ignore
269
                          }
270
                      ; seed = Ignore
271
                      ; start_checkpoint = Ignore
272
                      ; lock_checkpoint = Ignore
273
                      ; epoch_length = Ignore
274
                      }
275
                  }
276
            ; account = Account_condition.to_predicate t.account_condition
×
277
            ; valid_while = var_of_t Zkapp_precondition.Valid_while.typ Ignore
×
278
            }
279
        ; use_full_commitment = Boolean.false_
280
        ; implicit_account_creation_fee =
281
            (* Probably shouldn't hard-code this logic, but :shrug:, it's a
282
               reasonable test.
283
            *)
284
            Token_id.(Checked.equal t.token_id (Checked.constant default))
×
285
        ; may_use_token = t.may_use_token
286
        ; authorization_kind =
287
            (let dummy_vk_hash =
288
               Field.constant (Zkapp_account.dummy_vk_hash ())
×
289
             in
290
             { is_signed = t.authorization_kind.is_signed
×
291
             ; is_proved = t.authorization_kind.is_proved
292
             ; verification_key_hash =
293
                 Option.value ~default:dummy_vk_hash t.vk_hash
×
294
             } )
295
        }
296
      in
297
      let calls =
298
        match t.calls with
299
        | No_calls ->
×
300
            Zkapp_call_forest.Checked.empty ()
×
301
        | Rev_calls rev_calls ->
×
302
            List.fold_left ~init:(Zkapp_call_forest.Checked.empty ()) rev_calls
×
303
              ~f:(fun acc (account_update, calls) ->
304
                Zkapp_call_forest.Checked.push ~account_update ~calls acc )
×
305
        | Calls calls ->
×
306
            calls
307
      in
308
      (account_update, calls)
309

310
    let assert_state_unproved (t : t) =
311
      { t with
×
312
        account_condition =
313
          Account_condition.assert_state_unproved t.account_condition
×
314
      }
315

316
    let assert_state_proved (t : t) =
317
      { t with
×
318
        account_condition =
319
          Account_condition.assert_state_proved t.account_condition
×
320
      }
321

322
    let set_full_state app_state (t : t) =
323
      { t with update = Update.set_full_state app_state t.update }
×
324

325
    let set_state idx data (t : t) =
326
      { t with update = Update.set_state idx data t.update }
×
327

328
    let register_call account_update calls (t : t) =
329
      let rev_calls =
×
330
        match t.calls with
331
        | No_calls ->
×
332
            []
333
        | Rev_calls rev_calls ->
×
334
            rev_calls
335
        | Calls _ ->
×
336
            failwith "Cannot append calls to an already-completed tree"
337
      in
338
      { t with calls = Rev_calls ((account_update, calls) :: rev_calls) }
339

340
    let set_calls calls (t : t) =
341
      ( match t.calls with
×
342
      | No_calls ->
×
343
          ()
344
      | Rev_calls _ ->
×
345
          failwith
346
            "Cannot append an already-completed tree to the current calls"
347
      | Calls _ ->
×
348
          failwith "Cannot join two already-completed trees" ) ;
349
      { t with calls = Calls calls }
350

351
    let set_call_data call_data (t : t) = { t with call_data = Some call_data }
×
352

353
    let add_events events (t : t) =
354
      { t with events = Events.add_events t.events events }
×
355

356
    let add_actions actions (t : t) =
357
      { t with actions = Actions.add_actions t.actions actions }
×
358

359
    let set_balance_change balance_change (t : t) = { t with balance_change }
×
360

361
    let set_authorization_kind authorization_kind (t : t) =
362
      { t with authorization_kind }
×
363
  end
364
end
365

366
class account_update ~public_key ?vk_hash ?token_id ?may_use_token () =
367
  object
368
    val mutable account_update =
369
      Account_update_under_construction.In_circuit.create ~public_key ?vk_hash
×
370
        ?token_id ?may_use_token ()
371

372
    method assert_state_proved =
373
      account_update <-
×
374
        Account_update_under_construction.In_circuit.assert_state_proved
×
375
          account_update
376

377
    method assert_state_unproved =
378
      account_update <-
×
379
        Account_update_under_construction.In_circuit.assert_state_unproved
×
380
          account_update
381

382
    method set_state idx data =
383
      account_update <-
×
384
        Account_update_under_construction.In_circuit.set_state idx data
×
385
          account_update
386

387
    method set_full_state app_state =
388
      account_update <-
×
389
        Account_update_under_construction.In_circuit.set_full_state app_state
×
390
          account_update
391

392
    method set_call_data call_data =
393
      account_update <-
×
394
        Account_update_under_construction.In_circuit.set_call_data call_data
×
395
          account_update
396

397
    method register_call called_account_update sub_calls =
398
      account_update <-
×
399
        Account_update_under_construction.In_circuit.register_call
×
400
          called_account_update sub_calls account_update
401

402
    method set_calls calls =
403
      account_update <-
×
404
        Account_update_under_construction.In_circuit.set_calls calls
×
405
          account_update
406

407
    method add_events events =
408
      account_update <-
×
409
        Account_update_under_construction.In_circuit.add_events events
×
410
          account_update
411

412
    method add_actions actions =
413
      account_update <-
×
414
        Account_update_under_construction.In_circuit.add_actions actions
×
415
          account_update
416

417
    method set_balance_change balance_change =
418
      account_update <-
×
419
        Account_update_under_construction.In_circuit.set_balance_change
×
420
          balance_change account_update
421

422
    method set_authorization_kind authorization_kind =
423
      account_update <-
×
424
        Account_update_under_construction.In_circuit.set_authorization_kind
×
425
          authorization_kind account_update
426

427
    method account_update_under_construction = account_update
×
428
  end
429

430
(* TODO: Move this somewhere convenient. *)
431
let dummy_constraints () =
432
  let x = exists Field.typ ~compute:(fun () -> Field.Constant.of_int 3) in
×
433
  let g = exists Inner_curve.typ ~compute:(fun _ -> Inner_curve.one) in
×
434
  ignore
×
435
    ( Pickles.Scalar_challenge.to_field_checked'
×
436
        (module Impl)
437
        ~num_bits:16
438
        (Kimchi_backend_common.Scalar_challenge.create x)
×
439
      : Field.t * Field.t * Field.t ) ;
440
  ignore
441
    ( Pickles.Step_main_inputs.Ops.scale_fast g ~num_bits:5 (Shifted_value x)
×
442
      : Pickles.Step_main_inputs.Inner_curve.t ) ;
443
  ignore
444
    ( Pickles.Step_main_inputs.Ops.scale_fast g ~num_bits:5 (Shifted_value x)
×
445
      : Pickles.Step_main_inputs.Inner_curve.t ) ;
446
  ignore
447
    ( Pickles.Step_verifier.Scalar_challenge.endo g ~num_bits:4
×
448
        (Kimchi_backend_common.Scalar_challenge.create x)
×
449
      : Field.t * Field.t )
450

451
let exists_deferred ?request:req ?compute typ =
452
  let open Snark_params.Tick.Run in
×
453
  let open Async_kernel in
454
  (* Set up a full Ivar, in case we are generating the constraint system. *)
455
  let deferred = ref (Ivar.create_full ()) in
×
456
  (* Request or compute the [Deferred.t] value. *)
457
  let requested = exists ?request:req ?compute (Typ.prover_value ()) in
×
458
  as_prover (fun () ->
×
459
      (* If we are generating the witness, create a new Ivar.. *)
460
      deferred := Ivar.create () ;
×
461
      (* ..and fill it when the value we want to read resolves. *)
462
      Deferred.upon
463
        (As_prover.read (Typ.prover_value ()) requested)
×
464
        (fun _ -> Ivar.fill !deferred ()) ) ;
×
465
  (* Await the [Deferred.t] if we're generating the witness, otherwise we
466
     immediately bind over the filled Ivar and continue.
467
  *)
468
  Deferred.map (Ivar.read !deferred) ~f:(fun () ->
×
469
      (* Retrieve the value by peeking in the known-resolved deferred. *)
470
      exists typ ~compute:(fun () ->
×
471
          Option.value_exn @@ Deferred.peek
×
472
          @@ As_prover.read (Typ.prover_value ()) requested ) )
×
473

474
type return_type =
475
  { account_update : Account_update.Body.t
476
  ; account_update_digest : Zkapp_command.Digest.Account_update.t
477
  ; calls :
478
      ( ( Account_update.t
479
        , Zkapp_command.Digest.Account_update.t
480
        , Zkapp_command.Digest.Forest.t )
481
        Zkapp_command.Call_forest.Tree.t
482
      , Zkapp_command.Digest.Forest.t )
483
      With_stack_hash.t
484
      list
485
  }
486

487
let to_account_update (account_update : account_update) :
488
    Zkapp_statement.Checked.t * return_type Prover_value.t =
489
  dummy_constraints () ;
×
490
  let account_update, calls =
×
491
    Account_update_under_construction.In_circuit.to_account_update_and_calls
492
      account_update#account_update_under_construction
×
493
  in
494
  let account_update_digest =
×
495
    Zkapp_command.Call_forest.Digest.Account_update.Checked.create
496
      account_update
497
  in
498
  let public_output : Zkapp_statement.Checked.t =
×
499
    { account_update = (account_update_digest :> Field.t)
500
    ; calls = (Zkapp_call_forest.Checked.hash calls :> Field.t)
×
501
    }
502
  in
503
  let auxiliary_output =
504
    Prover_value.create (fun () ->
505
        let account_update =
×
506
          As_prover.read (Account_update.Body.typ ()) account_update
×
507
        in
508
        let account_update_digest =
×
509
          As_prover.read Zkapp_command.Call_forest.Digest.Account_update.typ
510
            account_update_digest
511
        in
512
        let calls = Prover_value.get calls.data in
×
513
        { account_update; calls; account_update_digest } )
×
514
  in
515
  (public_output, auxiliary_output)
×
516

517
open Pickles_types
518
open Hlist
519

520
let wrap_main ~public_key ?token_id ?may_use_token f
521
    { Pickles.Inductive_rule.public_input = vk_hash } =
522
  let account_update =
×
523
    new account_update ~public_key ~vk_hash ?token_id ?may_use_token ()
524
  in
525
  let auxiliary_output = f account_update in
×
526
  { Pickles.Inductive_rule.previous_proof_statements = []
×
527
  ; public_output = account_update
528
  ; auxiliary_output
529
  }
530

531
let compile :
532
    type auxiliary_var auxiliary_value prev_varss prev_valuess widthss heightss max_proofs_verified branches.
533
       ?self:
534
         ( Zkapp_statement.Checked.t
535
         , Zkapp_statement.t
536
         , max_proofs_verified
537
         , branches )
538
         Pickles.Tag.t
539
    -> ?cache:_
540
    -> ?proof_cache:_
541
    -> ?disk_keys:(_, branches) Vector.t * _
542
    -> ?override_wrap_domain:_
543
    -> auxiliary_typ:(auxiliary_var, auxiliary_value) Typ.t
544
    -> branches:(module Nat.Intf with type n = branches)
545
    -> max_proofs_verified:
546
         (module Nat.Add.Intf with type n = max_proofs_verified)
547
    -> name:string
548
    -> choices:
549
         (   self:
550
               ( Zkapp_statement.Checked.t
551
               , Zkapp_statement.t
552
               , max_proofs_verified
553
               , branches )
554
               Pickles.Tag.t
555
          -> ( prev_varss
556
             , prev_valuess
557
             , widthss
558
             , heightss
559
             , Field.t
560
             , Field.Constant.t
561
             , account_update
562
             , unit (* TODO: Remove? *)
563
             , auxiliary_var
564
             , auxiliary_value )
565
             H4_6.T(Pickles.Inductive_rule).t )
566
    -> unit
567
    -> ( Zkapp_statement.Checked.t
568
       , Zkapp_statement.t
569
       , max_proofs_verified
570
       , branches )
571
       Pickles.Tag.t
572
       * _
573
       * (module Pickles.Proof_intf
574
            with type t = ( max_proofs_verified
575
                          , max_proofs_verified )
576
                          Pickles.Proof.t
577
             and type statement = Zkapp_statement.t )
578
       * ( prev_valuess
579
         , widthss
580
         , heightss
581
         , unit
582
         , ( ( Account_update.t
583
             , Zkapp_command.Digest.Account_update.t
584
             , Zkapp_command.Digest.Forest.t )
585
             Zkapp_command.Call_forest.Tree.t
586
           * auxiliary_value )
587
           Deferred.t )
588
         H3_2.T(Pickles.Prover).t =
589
 fun ?self ?cache ?proof_cache ?disk_keys ?override_wrap_domain ~auxiliary_typ
590
     ~branches ~max_proofs_verified ~name ~choices () ->
591
  let vk_hash = ref None in
×
592
  let choices ~self =
593
    let rec go :
×
594
        type prev_varss prev_valuess widthss heightss.
595
           ( prev_varss
596
           , prev_valuess
597
           , widthss
598
           , heightss
599
           , Field.t
600
           , Field.Constant.t
601
           , account_update
602
           , unit
603
           , auxiliary_var
604
           , auxiliary_value )
605
           H4_6.T(Pickles.Inductive_rule).t
606
        -> ( prev_varss
607
           , prev_valuess
608
           , widthss
609
           , heightss
610
           , unit
611
           , unit
612
           , Zkapp_statement.Checked.t
613
           , Zkapp_statement.t
614
           , return_type Prover_value.t * auxiliary_var
615
           , return_type * auxiliary_value )
616
           H4_6.T(Pickles.Inductive_rule.Deferred).t = function
617
      | [] ->
×
618
          []
619
      | { identifier; prevs; main; feature_flags } :: choices ->
×
620
          { identifier
621
          ; prevs
622
          ; feature_flags
623
          ; main =
624
              (fun { Pickles.Inductive_rule.public_input = () } ->
625
                let%map.Deferred vk_hash =
626
                  exists_deferred Field.typ ~compute:(fun () ->
×
627
                      Lazy.force @@ Option.value_exn !vk_hash )
×
628
                in
629
                let { Pickles.Inductive_rule.previous_proof_statements
×
630
                    ; public_output = account_update_under_construction
631
                    ; auxiliary_output
632
                    } =
633
                  main { Pickles.Inductive_rule.public_input = vk_hash }
634
                in
635
                let public_output, account_update_tree =
×
636
                  to_account_update account_update_under_construction
637
                in
638
                { Pickles.Inductive_rule.previous_proof_statements
×
639
                ; public_output
640
                ; auxiliary_output = (account_update_tree, auxiliary_output)
641
                } )
642
          }
643
          :: go choices
×
644
    in
645
    go (choices ~self)
646
  in
647
  let tag, cache_handle, proof, provers =
648
    Pickles.compile_async () ?self ?cache ?proof_cache ?disk_keys
649
      ?override_wrap_domain ~public_input:(Output Zkapp_statement.typ)
650
      ~auxiliary_typ:Typ.(Prover_value.typ () * auxiliary_typ)
×
651
      ~branches ~max_proofs_verified ~name ~choices
652
  in
653
  let () =
×
654
    vk_hash :=
655
      Some
656
        ( lazy
657
          ( Deferred.map ~f:Zkapp_account.digest_vk
×
658
          @@ Pickles.Side_loaded.Verification_key.of_compiled tag ) )
×
659
  in
660
  let provers =
661
    let rec go :
662
        type prev_valuess widthss heightss.
663
           ( prev_valuess
664
           , widthss
665
           , heightss
666
           , unit
667
           , ( Zkapp_statement.t
668
             * (return_type * auxiliary_value)
669
             * (max_proofs_verified, max_proofs_verified) Pickles.Proof.t )
670
             Deferred.t )
671
           H3_2.T(Pickles.Prover).t
672
        -> ( prev_valuess
673
           , widthss
674
           , heightss
675
           , unit
676
           , ( ( Account_update.t
677
               , Zkapp_command.Digest.Account_update.t
678
               , Zkapp_command.Digest.Forest.t )
679
               Zkapp_command.Call_forest.Tree.t
680
             * auxiliary_value )
681
             Deferred.t )
682
           H3_2.T(Pickles.Prover).t = function
683
      | [] ->
×
684
          []
685
      | prover :: provers ->
×
686
          let prover ?handler () =
687
            let open Async_kernel in
×
688
            let%map ( _stmt
689
                    , ( { account_update; account_update_digest; calls }
690
                      , auxiliary_value )
691
                    , proof ) =
692
              prover ?handler ()
×
693
            in
694
            let account_update : Account_update.t =
×
695
              { body = account_update
696
              ; authorization = Proof (Pickles.Side_loaded.Proof.of_proof proof)
×
697
              }
698
            in
699
            ( { Zkapp_command.Call_forest.Tree.account_update
700
              ; account_update_digest
701
              ; calls
702
              }
703
            , auxiliary_value )
704
          in
705
          prover :: go provers
×
706
    in
707
    go provers
×
708
  in
709
  (tag, cache_handle, proof, provers)
710

711
let mk_update_body ?(token_id = Token_id.default)
×
712
    ?(update = Account_update.Update.dummy)
×
713
    ?(balance_change = Amount.Signed.zero) ?(increment_nonce = false)
×
714
    ?(events = []) ?(actions = []) ?(call_data = Field.Constant.zero)
×
715
    ?(preconditions = Account_update.Preconditions.accept)
×
716
    ?(use_full_commitment = false)
×
717
    ?(may_use_token = Account_update.May_use_token.No)
×
718
    ?(authorization_kind = Account_update.Authorization_kind.Signature)
×
719
    ?(implicit_account_creation_fee = false) public_key =
×
720
  { Account_update.Body.public_key
×
721
  ; update
722
  ; token_id
723
  ; balance_change
724
  ; increment_nonce
725
  ; events
726
  ; actions
727
  ; call_data
728
  ; preconditions
729
  ; use_full_commitment
730
  ; may_use_token
731
  ; authorization_kind
732
  ; implicit_account_creation_fee
733
  }
734

735
module Deploy_account_update = struct
736
  let body ?(balance_change = Account_update.Body.dummy.balance_change)
×
737
      ?(access = Permissions.Auth_required.None) public_key token_id vk :
×
738
      Account_update.Body.t =
739
    { Account_update.Body.dummy with
×
740
      public_key
741
    ; balance_change
742
    ; token_id
743
    ; update =
744
        { Account_update.Update.dummy with
745
          verification_key =
746
            Set
747
              { data = vk
748
              ; hash =
749
                  (* TODO: This function should live in
750
                     [Side_loaded_verification_key].
751
                  *)
752
                  Zkapp_account.digest_vk vk
×
753
              }
754
        ; permissions =
755
            Set
756
              { edit_state = Proof
757
              ; send = Either
758
              ; receive = None
759
              ; set_delegate = Proof
760
              ; set_permissions = Proof
761
              ; set_verification_key = (Proof, Mina_numbers.Txn_version.current)
762
              ; set_zkapp_uri = Proof
763
              ; edit_action_state = Proof
764
              ; set_token_symbol = Proof
765
              ; increment_nonce = Proof
766
              ; set_voting_for = Proof
767
              ; set_timing = Proof
768
              ; access
769
              }
770
        }
771
    ; use_full_commitment = true
772
    ; preconditions =
773
        { Account_update.Preconditions.network =
774
            Zkapp_precondition.Protocol_state.accept
775
        ; account = Zkapp_precondition.Account.accept
776
        ; valid_while = Ignore
777
        }
778
    ; authorization_kind = Signature
779
    }
780

781
  let full ?balance_change ?access public_key token_id vk : Account_update.t =
782
    (* TODO: This is a pain. *)
783
    { body = body ?balance_change ?access public_key token_id vk
×
784
    ; authorization = Signature Signature.dummy
785
    }
786
end
787

788
let insert_signatures pk_compressed sk
789
    ({ fee_payer; account_updates; memo } : Zkapp_command.t) : Zkapp_command.t =
790
  let transaction_commitment : Zkapp_command.Transaction_commitment.t =
×
791
    (* TODO: This is a pain. *)
792
    let account_updates_hash = Zkapp_command.Call_forest.hash account_updates in
793
    Zkapp_command.Transaction_commitment.create ~account_updates_hash
×
794
  in
795
  let memo_hash = Signed_command_memo.hash memo in
796
  let full_commitment =
×
797
    Zkapp_command.Transaction_commitment.create_complete transaction_commitment
798
      ~memo_hash
799
      ~fee_payer_hash:
800
        (Zkapp_command.Call_forest.Digest.Account_update.create
×
801
           (Account_update.of_fee_payer fee_payer) )
×
802
  in
803
  let fee_payer =
×
804
    match fee_payer with
805
    | { body = { public_key; _ }; _ }
×
806
      when Public_key.Compressed.equal public_key pk_compressed ->
×
807
        { fee_payer with
×
808
          authorization =
809
            Schnorr.Chunked.sign sk
×
810
              (Random_oracle.Input.Chunked.field full_commitment)
×
811
        }
812
    | fee_payer ->
×
813
        fee_payer
814
  in
815
  let account_updates =
816
    Zkapp_command.Call_forest.map account_updates ~f:(function
817
      | ({ body = { public_key; use_full_commitment; _ }
×
818
         ; authorization = Signature _
819
         } as account_update :
820
          Account_update.t )
821
        when Public_key.Compressed.equal public_key pk_compressed ->
×
822
          let commitment =
×
823
            if use_full_commitment then full_commitment
×
824
            else transaction_commitment
×
825
          in
826
          { account_update with
827
            authorization =
828
              Signature
829
                (Schnorr.Chunked.sign sk
×
830
                   (Random_oracle.Input.Chunked.field commitment) )
×
831
          }
832
      | account_update ->
×
833
          account_update )
834
  in
835
  { fee_payer; account_updates; memo }
×
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