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

MinaProtocol / mina / 2863

05 Nov 2024 06:20PM UTC coverage: 30.754% (-16.6%) from 47.311%
2863

push

buildkite

web-flow
Merge pull request #16296 from MinaProtocol/dkijania/more_multi_jobs

more multi jobs in CI

20276 of 65930 relevant lines covered (30.75%)

8631.7 hits per line

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

28.7
/src/lib/mina_base/zkapp_command.ml
1
open Core_kernel
9✔
2
open Signature_lib
3

4
module Call_forest = struct
5
  let empty = Outside_hash_image.t
6

7
  module Tree = struct
8
    [%%versioned
9
    module Stable = struct
10
      module V1 = struct
11
        type ('account_update, 'account_update_digest, 'digest) t =
14✔
12
              ( 'account_update
13
              , 'account_update_digest
14
              , 'digest )
15
              Mina_wire_types.Mina_base.Zkapp_command.Call_forest.Tree.V1.t =
16
          { account_update : 'account_update
×
17
          ; account_update_digest : 'account_update_digest
×
18
          ; calls :
×
19
              ( ('account_update, 'account_update_digest, 'digest) t
×
20
              , 'digest )
×
21
              With_stack_hash.Stable.V1.t
×
22
              list
×
23
          }
24
        [@@deriving sexp, compare, equal, hash, yojson]
27✔
25

26
        let to_latest = Fn.id
27
      end
28
    end]
29

30
    let rec fold_forest (ts : (_ t, _) With_stack_hash.t list) ~f ~init =
31
      List.fold ts ~init ~f:(fun acc { elt; stack_hash = _ } ->
×
32
          fold elt ~init:acc ~f )
×
33

34
    and fold { account_update; calls; account_update_digest = _ } ~f ~init =
35
      fold_forest calls ~f ~init:(f init account_update)
×
36

37
    let rec fold_forest2_exn (ts1 : (_ t, _) With_stack_hash.t list)
38
        (ts2 : (_ t, _) With_stack_hash.t list) ~f ~init =
39
      List.fold2_exn ts1 ts2 ~init
154✔
40
        ~f:(fun
41
             acc
42
             { elt = elt1; stack_hash = _ }
43
             { elt = elt2; stack_hash = _ }
44
           -> fold2_exn elt1 elt2 ~init:acc ~f )
134✔
45

46
    and fold2_exn
47
        { account_update = account_update1
48
        ; calls = calls1
49
        ; account_update_digest = _
50
        }
51
        { account_update = account_update2
52
        ; calls = calls2
53
        ; account_update_digest = _
54
        } ~f ~init =
55
      fold_forest2_exn calls1 calls2 ~f
134✔
56
        ~init:(f init account_update1 account_update2)
134✔
57

58
    let iter_forest2_exn ts1 ts2 ~f =
59
      fold_forest2_exn ts1 ts2 ~init:() ~f:(fun () p1 p2 -> f p1 p2)
×
60

61
    let iter2_exn ts1 ts2 ~f =
62
      fold2_exn ts1 ts2 ~init:() ~f:(fun () p1 p2 -> f p1 p2)
×
63

64
    let rec mapi_with_trees' ~i (t : _ t) ~f =
65
      let account_update = f i t.account_update t in
902✔
66
      let l, calls = mapi_forest_with_trees' ~i:(i + 1) t.calls ~f in
902✔
67
      ( l
902✔
68
      , { calls
69
        ; account_update
70
        ; account_update_digest = t.account_update_digest
71
        } )
72

73
    and mapi_forest_with_trees' ~i x ~f =
74
      let rec go i acc = function
1,042✔
75
        | [] ->
1,042✔
76
            (i, List.rev acc)
1,042✔
77
        | t :: ts ->
902✔
78
            let l, elt' = mapi_with_trees' ~i ~f (With_stack_hash.elt t) in
902✔
79
            go l (With_stack_hash.map t ~f:(fun _ -> elt') :: acc) ts
902✔
80
      in
81
      go i [] x
82

83
    let mapi_with_trees t ~f = mapi_with_trees' ~i:0 t ~f |> snd
×
84

85
    let mapi_forest_with_trees t ~f = mapi_forest_with_trees' ~i:0 t ~f |> snd
×
86

87
    let mapi' ~i t ~f =
88
      mapi_with_trees' ~i t ~f:(fun i account_update _ -> f i account_update)
×
89

90
    let mapi_forest' ~i t ~f =
91
      mapi_forest_with_trees' ~i t ~f:(fun i account_update _ ->
140✔
92
          f i account_update )
902✔
93

94
    let rec deferred_mapi_with_trees' ~i (t : _ t) ~f =
95
      let open Async_kernel.Deferred.Let_syntax in
×
96
      let%bind l, calls =
97
        deferred_mapi_forest_with_trees' ~i:(i + 1) t.calls ~f
×
98
      in
99
      let%map account_update = f i t.account_update t in
×
100
      ( l
×
101
      , { calls
102
        ; account_update
103
        ; account_update_digest = t.account_update_digest
104
        } )
105

106
    and deferred_mapi_forest_with_trees' ~i x ~f =
107
      let open Async_kernel.Deferred.Let_syntax in
×
108
      let rec go i acc = function
109
        | [] ->
×
110
            return (i, List.rev acc)
×
111
        | t :: ts ->
×
112
            let%bind l, elt' =
113
              deferred_mapi_with_trees' ~i ~f (With_stack_hash.elt t)
×
114
            in
115
            go l (With_stack_hash.map t ~f:(fun _ -> elt') :: acc) ts
×
116
      in
117
      go i [] x
118

119
    let map_forest ~f t = mapi_forest' ~i:0 ~f:(fun _ x -> f x) t |> snd
140✔
120

121
    let mapi_forest ~f t = mapi_forest' ~i:0 ~f t |> snd
×
122

123
    let deferred_map_forest ~f t =
124
      let open Async_kernel.Deferred in
×
125
      deferred_mapi_forest_with_trees' ~i:0 ~f:(fun _ x -> f x) t >>| snd
×
126

127
    let deferred_mapi_forest ~f t =
128
      let open Async_kernel.Deferred in
×
129
      deferred_mapi_forest_with_trees' ~i:0 ~f t >>| snd
×
130

131
    let hash { account_update = _; calls; account_update_digest } =
132
      let stack_hash =
×
133
        match calls with [] -> empty | e :: _ -> e.stack_hash
×
134
      in
135
      Random_oracle.hash ~init:Hash_prefix_states.account_update_node
136
        [| account_update_digest; stack_hash |]
137
  end
138

139
  type ('a, 'b, 'c) tree = ('a, 'b, 'c) Tree.t
140

141
  module type Digest_intf = sig
142
    module Account_update : sig
143
      include Digest_intf.S
144

145
      module Checked : sig
146
        include Digest_intf.S_checked
147

148
        val create :
149
          ?chain:Mina_signature_kind.t -> Account_update.Checked.t -> t
150

151
        val create_body :
152
          ?chain:Mina_signature_kind.t -> Account_update.Body.Checked.t -> t
153
      end
154

155
      include Digest_intf.S_aux with type t := t and type checked := Checked.t
156

157
      val create : ?chain:Mina_signature_kind.t -> Account_update.t -> t
158

159
      val create_body :
160
        ?chain:Mina_signature_kind.t -> Account_update.Body.t -> t
161
    end
162

163
    module rec Forest : sig
164
      include Digest_intf.S
165

166
      module Checked : sig
167
        include Digest_intf.S_checked
168

169
        val empty : t
170

171
        val cons : Tree.Checked.t -> t -> t
172
      end
173

174
      include Digest_intf.S_aux with type t := t and type checked := Checked.t
175

176
      val empty : t
177

178
      val cons : Tree.t -> Forest.t -> Forest.t
179
    end
180

181
    and Tree : sig
182
      include Digest_intf.S
183

184
      module Checked : sig
185
        include Digest_intf.S_checked
186

187
        val create :
188
             account_update:Account_update.Checked.t
189
          -> calls:Forest.Checked.t
190
          -> Tree.Checked.t
191
      end
192

193
      include Digest_intf.S_aux with type t := t and type checked := Checked.t
194

195
      val create : (_, Account_update.t, Forest.t) tree -> Tree.t
196
    end
197
  end
198

199
  module Make_digest_sig
200
      (T : Mina_wire_types.Mina_base.Zkapp_command.Digest_types.S) =
201
  struct
202
    module type S =
203
      Digest_intf
204
        with type Account_update.Stable.V1.t = T.Account_update.V1.t
205
         and type Forest.Stable.V1.t = T.Forest.V1.t
206
  end
207

208
  module Make_digest_types = struct
209
    module Account_update = struct
210
      [%%versioned
211
      module Stable = struct
212
        module V1 = struct
213
          type t = Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t
×
214
          [@@deriving sexp, compare, equal, hash, yojson]
45✔
215

216
          let to_latest = Fn.id
217
        end
218
      end]
219
    end
220

221
    module Forest = struct
222
      [%%versioned
223
      module Stable = struct
224
        module V1 = struct
225
          type t = Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t
×
226
          [@@deriving sexp, compare, equal, hash, yojson]
45✔
227

228
          let to_latest = Fn.id
229
        end
230
      end]
231
    end
232

233
    module Tree = struct
234
      [%%versioned
235
      module Stable = struct
236
        module V1 = struct
237
          type t = Kimchi_backend.Pasta.Basic.Fp.Stable.V1.t
×
238
          [@@deriving sexp, compare, equal, hash, yojson]
45✔
239

240
          let to_latest = Fn.id
241
        end
242
      end]
243
    end
244
  end
245

246
  module Make_digest_str
247
      (T : Mina_wire_types.Mina_base.Zkapp_command.Digest_concrete) :
248
    Make_digest_sig(T).S = struct
249
    module M = struct
250
      open Pickles.Impls.Step.Field
251
      module Checked = Pickles.Impls.Step.Field
252

253
      let typ = typ
254

255
      let constant = constant
256
    end
257

258
    module Account_update = struct
259
      include Make_digest_types.Account_update
260
      include M
261

262
      module Checked = struct
263
        include Checked
264

265
        let create = Account_update.Checked.digest
266

267
        let create_body = Account_update.Body.Checked.digest
268
      end
269

270
      let create : ?chain:Mina_signature_kind.t -> Account_update.t -> t =
271
        Account_update.digest
272

273
      let create_body :
274
          ?chain:Mina_signature_kind.t -> Account_update.Body.t -> t =
275
        Account_update.Body.digest
276
    end
277

278
    module Forest = struct
279
      include Make_digest_types.Forest
280
      include M
281

282
      module Checked = struct
283
        include Checked
284

285
        let empty = constant empty
9✔
286

287
        let cons hash h_tl =
288
          Random_oracle.Checked.hash
32✔
289
            ~init:Hash_prefix_states.account_update_cons [| hash; h_tl |]
290
      end
291

292
      let empty = empty
293

294
      let cons hash h_tl =
295
        Random_oracle.hash ~init:Hash_prefix_states.account_update_cons
390✔
296
          [| hash; h_tl |]
297
    end
298

299
    module Tree = struct
300
      include Make_digest_types.Tree
301
      include M
302

303
      module Checked = struct
304
        include Checked
305

306
        let create ~(account_update : Account_update.Checked.t)
307
            ~(calls : Forest.Checked.t) =
308
          Random_oracle.Checked.hash
32✔
309
            ~init:Hash_prefix_states.account_update_node
310
            [| (account_update :> t); (calls :> t) |]
311
      end
312

313
      let create ({ account_update = _; calls; account_update_digest } : _ tree)
314
          =
315
        let stack_hash =
390✔
316
          match calls with [] -> empty | e :: _ -> e.stack_hash
66✔
317
        in
318
        Random_oracle.hash ~init:Hash_prefix_states.account_update_node
319
          [| account_update_digest; stack_hash |]
320
    end
321
  end
322

323
  module Digest =
324
    Mina_wire_types.Mina_base.Zkapp_command.Digest_make
325
      (Make_digest_sig)
326
      (Make_digest_str)
327

328
  let fold = Tree.fold_forest
329

330
  let iteri t ~(f : int -> 'a -> unit) : unit =
331
    let (_ : int) = fold t ~init:0 ~f:(fun acc x -> f acc x ; acc + 1) in
×
332
    ()
×
333

334
  [%%versioned
335
  module Stable = struct
336
    module V1 = struct
337
      type ('account_update, 'account_update_digest, 'digest) t =
×
338
        ( ('account_update, 'account_update_digest, 'digest) Tree.Stable.V1.t
×
339
        , 'digest )
×
340
        With_stack_hash.Stable.V1.t
×
341
        list
×
342
      [@@deriving sexp, compare, equal, hash, yojson]
63✔
343

344
      let to_latest = Fn.id
345
    end
346
  end]
347

348
  module Shape = struct
349
    module I = struct
350
      type t = int
351

352
      let quickcheck_shrinker = Quickcheck.Shrinker.empty ()
9✔
353

354
      let quickcheck_generator = [%quickcheck.generator: int]
355

356
      let quickcheck_observer = [%quickcheck.observer: int]
357
    end
358

359
    type t = Node of (I.t * t) list [@@deriving quickcheck]
×
360
  end
361

362
  let rec shape (t : _ t) : Shape.t =
363
    Node (List.mapi t ~f:(fun i { elt; stack_hash = _ } -> (i, shape elt.calls)))
×
364

365
  let match_up (type a b) (xs : a list) (ys : (int * b) list) : (a * b) list =
366
    let rec go i_curr xs ys =
×
367
      match (xs, ys) with
×
368
      | [], [] ->
×
369
          []
370
      | x :: xs', (i, y) :: ys' ->
×
371
          if i_curr = i then (x, y) :: go (i_curr + 1) xs' ys'
×
372
          else if i_curr < i then go (i_curr + 1) xs' ys'
×
373
          else assert false
×
374
      | [], _ :: _ ->
375
          assert false
376
      | _ :: _, [] ->
×
377
          []
378
    in
379
    go 0 xs ys
380

381
  let rec mask (t : ('p, 'h1, unit) t) (Node shape : Shape.t) :
382
      ('p, 'h1, unit) t =
383
    List.map (match_up t shape)
×
384
      ~f:(fun ({ With_stack_hash.elt = t_sub; stack_hash = () }, shape_sub) ->
385
        { With_stack_hash.elt =
×
386
            { t_sub with calls = mask t_sub.calls shape_sub }
×
387
        ; stack_hash = ()
388
        } )
389

390
  let rec of_account_updates_map ~(f : 'p1 -> 'p2)
391
      ~(account_update_depth : 'p1 -> int) (account_updates : 'p1 list) :
392
      ('p2, unit, unit) t =
393
    match account_updates with
288✔
394
    | [] ->
154✔
395
        []
396
    | p :: ps ->
134✔
397
        let depth = account_update_depth p in
398
        let children, siblings =
134✔
399
          List.split_while ps ~f:(fun p' -> account_update_depth p' > depth)
114✔
400
        in
401
        { With_stack_hash.elt =
134✔
402
            { Tree.account_update = f p
134✔
403
            ; account_update_digest = ()
404
            ; calls = of_account_updates_map ~f ~account_update_depth children
134✔
405
            }
406
        ; stack_hash = ()
407
        }
408
        :: of_account_updates_map ~f ~account_update_depth siblings
134✔
409

410
  let of_account_updates ~account_update_depth account_updates =
411
    of_account_updates_map ~f:Fn.id ~account_update_depth account_updates
20✔
412

413
  let to_account_updates_map ~f (xs : _ t) =
414
    let rec collect depth (xs : _ t) acc =
80✔
415
      match xs with
1,104✔
416
      | [] ->
592✔
417
          acc
418
      | { elt = { account_update; calls; account_update_digest = _ }
512✔
419
        ; stack_hash = _
420
        }
421
        :: xs ->
422
          f ~depth account_update :: acc
512✔
423
          |> collect (depth + 1) calls
512✔
424
          |> collect depth xs
425
    in
426
    List.rev (collect 0 xs [])
80✔
427

428
  let to_account_updates xs =
429
    to_account_updates_map ~f:(fun ~depth:_ account_update -> account_update) xs
40✔
430

431
  let hd_account_update (xs : _ t) =
432
    match xs with
×
433
    | [] ->
×
434
        None
435
    | { elt = { account_update; calls = _; account_update_digest = _ }
×
436
      ; stack_hash = _
437
      }
438
      :: _ ->
439
        Some account_update
440

441
  let map = Tree.map_forest
442

443
  let mapi = Tree.mapi_forest
444

445
  let mapi_with_trees = Tree.mapi_forest_with_trees
446

447
  let deferred_mapi = Tree.deferred_mapi_forest
448

449
  let to_zkapp_command_with_hashes_list (xs : _ t) =
450
    let rec collect (xs : _ t) acc =
×
451
      match xs with
×
452
      | [] ->
×
453
          acc
454
      | { elt = { account_update; calls; account_update_digest = _ }
×
455
        ; stack_hash
456
        }
457
        :: xs ->
458
          (account_update, stack_hash) :: acc |> collect calls |> collect xs
×
459
    in
460
    List.rev (collect xs [])
×
461

462
  let hash_cons hash h_tl =
463
    Random_oracle.hash ~init:Hash_prefix_states.account_update_cons
×
464
      [| hash; h_tl |]
465

466
  let hash = function
467
    | [] ->
129✔
468
        Digest.Forest.empty
469
    | x :: _ ->
304✔
470
        With_stack_hash.stack_hash x
471

472
  let cons_tree tree (forest : _ t) : _ t =
473
    { elt = tree
×
474
    ; stack_hash = Digest.Forest.cons (Digest.Tree.create tree) (hash forest)
×
475
    }
476
    :: forest
477

478
  let cons_aux (type p) ~(digest_account_update : p -> _) ?(calls = [])
×
479
      (account_update : p) (xs : _ t) : _ t =
480
    let account_update_digest = digest_account_update account_update in
×
481
    let tree : _ Tree.t = { account_update; account_update_digest; calls } in
×
482
    cons_tree tree xs
483

484
  let cons ?calls (account_update : Account_update.t) xs =
485
    cons_aux ~digest_account_update:Digest.Account_update.create ?calls
×
486
      account_update xs
487

488
  let rec accumulate_hashes ~hash_account_update (xs : _ t) =
489
    let go = accumulate_hashes ~hash_account_update in
840✔
490
    match xs with
491
    | [] ->
450✔
492
        []
493
    | { elt = { account_update; calls; account_update_digest = _ }
390✔
494
      ; stack_hash = _
495
      }
496
      :: xs ->
497
        let calls = go calls in
498
        let xs = go xs in
390✔
499
        let node =
390✔
500
          { Tree.account_update
501
          ; calls
502
          ; account_update_digest = hash_account_update account_update
390✔
503
          }
504
        in
505
        let node_hash = Digest.Tree.create node in
506
        { elt = node; stack_hash = Digest.Forest.cons node_hash (hash xs) }
390✔
507
        :: xs
508

509
  let accumulate_hashes' (type a b) (xs : (Account_update.t, a, b) t) :
510
      (Account_update.t, Digest.Account_update.t, Digest.Forest.t) t =
511
    let hash_account_update (p : Account_update.t) =
20✔
512
      Digest.Account_update.create p
134✔
513
    in
514
    accumulate_hashes ~hash_account_update xs
515

516
  let accumulate_hashes_predicated xs =
517
    accumulate_hashes ~hash_account_update:Digest.Account_update.create xs
40✔
518

519
  module With_hashes_and_data = struct
520
    [%%versioned
521
    module Stable = struct
522
      module V1 = struct
523
        type 'data t =
×
524
          ( Account_update.Stable.V1.t * 'data
×
525
          , Digest.Account_update.Stable.V1.t
×
526
          , Digest.Forest.Stable.V1.t )
×
527
          Stable.V1.t
×
528
        [@@deriving sexp, compare, equal, hash, yojson]
27✔
529

530
        let to_latest = Fn.id
531
      end
532
    end]
533

534
    let empty = Digest.Forest.empty
535

536
    let hash_account_update ((p : Account_update.t), _) =
537
      Digest.Account_update.create p
×
538

539
    let accumulate_hashes xs : _ t = accumulate_hashes ~hash_account_update xs
×
540

541
    let of_zkapp_command_simple_list (xs : (Account_update.Simple.t * 'a) list)
542
        : _ t =
543
      of_account_updates xs
×
544
        ~account_update_depth:(fun ((p : Account_update.Simple.t), _) ->
545
          p.body.call_depth )
×
546
      |> map ~f:(fun (p, x) -> (Account_update.of_simple p, x))
×
547
      |> accumulate_hashes
548

549
    let of_account_updates (xs : (Account_update.Graphql_repr.t * 'a) list) :
550
        _ t =
551
      of_account_updates_map
×
552
        ~account_update_depth:(fun ((p : Account_update.Graphql_repr.t), _) ->
553
          p.body.call_depth )
×
554
        ~f:(fun (p, x) -> (Account_update.of_graphql_repr p, x))
×
555
        xs
556
      |> accumulate_hashes
557

558
    let to_account_updates (x : _ t) = to_account_updates x
×
559

560
    let to_zkapp_command_with_hashes_list (x : _ t) =
561
      to_zkapp_command_with_hashes_list x
×
562

563
    let account_updates_hash' xs = of_account_updates xs |> hash
×
564

565
    let account_updates_hash xs =
566
      List.map ~f:(fun x -> (x, ())) xs |> account_updates_hash'
×
567
  end
568

569
  module With_hashes = struct
570
    [%%versioned
571
    module Stable = struct
572
      module V1 = struct
573
        type t =
9✔
574
          ( Account_update.Stable.V1.t
×
575
          , Digest.Account_update.Stable.V1.t
×
576
          , Digest.Forest.Stable.V1.t )
×
577
          Stable.V1.t
×
578
        [@@deriving sexp, compare, equal, hash, yojson]
45✔
579

580
        let to_latest = Fn.id
581
      end
582
    end]
583

584
    let empty = Digest.Forest.empty
585

586
    let hash_account_update (p : Account_update.t) =
587
      Digest.Account_update.create p
×
588

589
    let accumulate_hashes xs : t = accumulate_hashes ~hash_account_update xs
×
590

591
    let of_zkapp_command_simple_list (xs : Account_update.Simple.t list) : t =
592
      of_account_updates xs
×
593
        ~account_update_depth:(fun (p : Account_update.Simple.t) ->
594
          p.body.call_depth )
×
595
      |> map ~f:Account_update.of_simple
×
596
      |> accumulate_hashes
597

598
    let of_account_updates (xs : Account_update.Graphql_repr.t list) : t =
599
      of_account_updates_map
×
600
        ~account_update_depth:(fun (p : Account_update.Graphql_repr.t) ->
601
          p.body.call_depth )
×
602
        ~f:(fun p -> Account_update.of_graphql_repr p)
×
603
        xs
604
      |> accumulate_hashes
605

606
    let to_account_updates (x : t) = to_account_updates x
×
607

608
    let to_zkapp_command_with_hashes_list (x : t) =
609
      to_zkapp_command_with_hashes_list x
×
610

611
    let account_updates_hash' xs = of_account_updates xs |> hash
×
612

613
    let account_updates_hash xs =
614
      List.map ~f:(fun x -> x) xs |> account_updates_hash'
×
615
  end
616

617
  let is_empty : _ t -> bool = List.is_empty
618

619
  let to_list (type p) (t : (p, _, _) t) : p list =
620
    List.rev @@ fold t ~init:[] ~f:(fun acc p -> p :: acc)
×
621

622
  let exists (type p) (t : (p, _, _) t) ~(f : p -> bool) : bool =
623
    with_return (fun { return } ->
×
624
        fold t ~init:() ~f:(fun () p -> if f p then return true else ()) ;
×
625
        false )
×
626
end
627

628
module Graphql_repr = struct
629
  [%%versioned
630
  module Stable = struct
631
    module V1 = struct
632
      type t =
18✔
633
        { fee_payer : Account_update.Fee_payer.Stable.V1.t
×
634
        ; account_updates : Account_update.Graphql_repr.Stable.V1.t list
×
635
        ; memo : Signed_command_memo.Stable.V1.t
×
636
        }
637
      [@@deriving sexp, compare, equal, hash, yojson]
45✔
638

639
      let to_latest = Fn.id
640
    end
641
  end]
642
end
643

644
module Simple = struct
645
  (* For easily constructing values *)
646
  [%%versioned
647
  module Stable = struct
648
    module V1 = struct
649
      type t =
18✔
650
        { fee_payer : Account_update.Fee_payer.Stable.V1.t
×
651
        ; account_updates : Account_update.Simple.Stable.V1.t list
×
652
        ; memo : Signed_command_memo.Stable.V1.t
×
653
        }
654
      [@@deriving sexp, compare, equal, hash, yojson]
45✔
655

656
      let to_latest = Fn.id
657
    end
658
  end]
659
end
660

661
module Digest = Call_forest.Digest
662

663
module T = struct
664
  [%%versioned_binable
665
  module Stable = struct
×
666
    [@@@with_top_version_tag]
667

668
    (* DO NOT DELETE VERSIONS!
669
       so we can always get transaction hashes from old transaction ids
670
       the version linter should be checking this
671

672
       IF YOU CREATE A NEW VERSION:
673
       update Transaction_hash.hash_of_transaction_id to handle it
674
       add hash_zkapp_command_vn for that version
675
    *)
676

677
    module V1 = struct
678
      type t = Mina_wire_types.Mina_base.Zkapp_command.V1.t =
172✔
679
        { fee_payer : Account_update.Fee_payer.Stable.V1.t
×
680
        ; account_updates :
×
681
            ( Account_update.Stable.V1.t
×
682
            , Digest.Account_update.Stable.V1.t
×
683
            , Digest.Forest.Stable.V1.t )
×
684
            Call_forest.Stable.V1.t
×
685
        ; memo : Signed_command_memo.Stable.V1.t
×
686
        }
687
      [@@deriving annot, sexp, compare, equal, hash, yojson, fields]
108✔
688

689
      let to_latest = Fn.id
690

691
      module Wire = struct
692
        [%%versioned
693
        module Stable = struct
694
          module V1 = struct
695
            type t =
18✔
696
              { fee_payer : Account_update.Fee_payer.Stable.V1.t
×
697
              ; account_updates :
×
698
                  ( Account_update.Stable.V1.t
×
699
                  , unit
×
700
                  , unit )
×
701
                  Call_forest.Stable.V1.t
×
702
              ; memo : Signed_command_memo.Stable.V1.t
×
703
              }
704
            [@@deriving sexp, compare, equal, hash, yojson]
45✔
705

706
            let to_latest = Fn.id
707
          end
708
        end]
709

710
        let of_graphql_repr (t : Graphql_repr.t) : t =
711
          { fee_payer = t.fee_payer
×
712
          ; memo = t.memo
713
          ; account_updates =
714
              Call_forest.of_account_updates_map t.account_updates
×
715
                ~f:Account_update.of_graphql_repr
716
                ~account_update_depth:(fun (p : Account_update.Graphql_repr.t)
717
                                      -> p.body.call_depth )
×
718
          }
719

720
        let to_graphql_repr (t : t) : Graphql_repr.t =
721
          { fee_payer = t.fee_payer
×
722
          ; memo = t.memo
723
          ; account_updates =
724
              t.account_updates
725
              |> Call_forest.to_account_updates_map
×
726
                   ~f:(fun ~depth account_update ->
727
                     Account_update.to_graphql_repr account_update
×
728
                       ~call_depth:depth )
729
          }
730

731
        let gen =
732
          let open Quickcheck.Generator in
733
          let open Let_syntax in
734
          let gen_call_forest =
735
            fixed_point (fun self ->
736
                let%bind calls_length = small_non_negative_int in
737
                list_with_length calls_length
×
738
                  (let%map account_update = Account_update.gen
739
                   and calls = self in
740
                   { With_stack_hash.stack_hash = ()
×
741
                   ; elt =
742
                       { Call_forest.Tree.account_update
743
                       ; account_update_digest = ()
744
                       ; calls
745
                       }
746
                   } ) )
747
          in
748
          let open Quickcheck.Let_syntax in
9✔
749
          let%map fee_payer = Account_update.Fee_payer.gen
750
          and account_updates = gen_call_forest
751
          and memo = Signed_command_memo.gen in
752
          { fee_payer; account_updates; memo }
×
753

754
        let shrinker : t Quickcheck.Shrinker.t =
755
          Quickcheck.Shrinker.create (fun t ->
9✔
756
              let shape = Call_forest.shape t.account_updates in
×
757
              Sequence.map
×
758
                (Quickcheck.Shrinker.shrink
×
759
                   Call_forest.Shape.quickcheck_shrinker shape )
760
                ~f:(fun shape' ->
761
                  { t with
×
762
                    account_updates = Call_forest.mask t.account_updates shape'
×
763
                  } ) )
764
      end
765

766
      let of_wire (w : Wire.t) : t =
767
        { fee_payer = w.fee_payer
×
768
        ; memo = w.memo
769
        ; account_updates =
770
            w.account_updates
771
            |> Call_forest.accumulate_hashes
×
772
                 ~hash_account_update:(fun (p : Account_update.t) ->
773
                   Digest.Account_update.create p )
×
774
        }
775

776
      let to_wire (t : t) : Wire.t =
777
        let rec forget_hashes = List.map ~f:forget_hash
80✔
778
        and forget_hash = function
779
          | { With_stack_hash.stack_hash = _
488✔
780
            ; elt =
781
                { Call_forest.Tree.account_update
782
                ; account_update_digest = _
783
                ; calls
784
                }
785
            } ->
786
              { With_stack_hash.stack_hash = ()
787
              ; elt =
788
                  { Call_forest.Tree.account_update
789
                  ; account_update_digest = ()
790
                  ; calls = forget_hashes calls
488✔
791
                  }
792
              }
793
        in
794
        { fee_payer = t.fee_payer
795
        ; memo = t.memo
796
        ; account_updates = forget_hashes t.account_updates
80✔
797
        }
798

799
      include
800
        Binable.Of_binable_without_uuid
801
          (Wire.Stable.V1)
802
          (struct
803
            type nonrec t = t
804

805
            let of_binable t = of_wire t
×
806

807
            let to_binable = to_wire
808
          end)
809
    end
810
  end]
×
811
end
812

813
include T
814

815
[%%define_locally Stable.Latest.(of_wire, to_wire)]
816

817
[%%define_locally Stable.Latest.Wire.(gen)]
818

819
let of_simple (w : Simple.t) : t =
820
  { fee_payer = w.fee_payer
×
821
  ; memo = w.memo
822
  ; account_updates =
823
      Call_forest.of_account_updates w.account_updates
×
824
        ~account_update_depth:(fun (p : Account_update.Simple.t) ->
825
          p.body.call_depth )
×
826
      |> Call_forest.map ~f:Account_update.of_simple
×
827
      |> Call_forest.accumulate_hashes
×
828
           ~hash_account_update:(fun (p : Account_update.t) ->
829
             Digest.Account_update.create p )
×
830
  }
831

832
let to_simple (t : t) : Simple.t =
833
  { fee_payer = t.fee_payer
20✔
834
  ; memo = t.memo
835
  ; account_updates =
836
      t.account_updates
837
      |> Call_forest.to_account_updates_map
20✔
838
           ~f:(fun ~depth { Account_update.body = b; authorization } ->
839
             { Account_update.Simple.authorization
122✔
840
             ; body =
841
                 { public_key = b.public_key
842
                 ; token_id = b.token_id
843
                 ; update = b.update
844
                 ; balance_change = b.balance_change
845
                 ; increment_nonce = b.increment_nonce
846
                 ; events = b.events
847
                 ; actions = b.actions
848
                 ; call_data = b.call_data
849
                 ; preconditions = b.preconditions
850
                 ; use_full_commitment = b.use_full_commitment
851
                 ; implicit_account_creation_fee =
852
                     b.implicit_account_creation_fee
853
                 ; may_use_token = b.may_use_token
854
                 ; call_depth = depth
855
                 ; authorization_kind = b.authorization_kind
856
                 }
857
             } )
858
  }
859

860
let all_account_updates (t : t) : _ Call_forest.t =
861
  let p = t.fee_payer in
×
862
  let body = Account_update.Body.of_fee_payer p.body in
863
  let fee_payer : Account_update.t =
×
864
    let p = t.fee_payer in
865
    { authorization = Control.Signature p.authorization; body }
866
  in
867
  Call_forest.cons fee_payer t.account_updates
868

869
let fee (t : t) : Currency.Fee.t = t.fee_payer.body.fee
×
870

871
let fee_payer_account_update ({ fee_payer; _ } : t) = fee_payer
×
872

873
let applicable_at_nonce (t : t) : Account.Nonce.t =
874
  (fee_payer_account_update t).body.nonce
×
875

876
let target_nonce_on_success (t : t) : Account.Nonce.t =
877
  let base_nonce = Account.Nonce.succ (applicable_at_nonce t) in
×
878
  let fee_payer_pubkey = t.fee_payer.body.public_key in
×
879
  let fee_payer_account_update_increments =
880
    List.count (Call_forest.to_list t.account_updates) ~f:(fun p ->
×
881
        Public_key.Compressed.equal p.body.public_key fee_payer_pubkey
×
882
        && p.body.increment_nonce )
×
883
  in
884
  Account.Nonce.add base_nonce
×
885
    (Account.Nonce.of_int fee_payer_account_update_increments)
×
886

887
let nonce_increments (t : t) : int Public_key.Compressed.Map.t =
888
  let base_increments =
×
889
    Public_key.Compressed.Map.of_alist_exn [ (t.fee_payer.body.public_key, 1) ]
890
  in
891
  List.fold_left (Call_forest.to_list t.account_updates) ~init:base_increments
×
892
    ~f:(fun incr_map account_update ->
893
      if account_update.body.increment_nonce then
×
894
        Map.update incr_map account_update.body.public_key
×
895
          ~f:(Option.value_map ~default:1 ~f:(( + ) 1))
896
      else incr_map )
×
897

898
let fee_token (_t : t) = Token_id.default
×
899

900
let fee_payer (t : t) =
901
  Account_id.create t.fee_payer.body.public_key (fee_token t)
×
902

903
let extract_vks (t : t) : (Account_id.t * Verification_key_wire.t) List.t =
904
  account_updates t
×
905
  |> Call_forest.fold ~init:[] ~f:(fun acc (p : Account_update.t) ->
906
         match Account_update.verification_key_update_to_option p with
×
907
         | Zkapp_basic.Set_or_keep.Set (Some vk) ->
×
908
             (Account_update.account_id p, vk) :: acc
×
909
         | _ ->
×
910
             acc )
911

912
let account_updates_list (t : t) : Account_update.t list =
913
  Call_forest.fold t.account_updates ~init:[] ~f:(Fn.flip List.cons) |> List.rev
×
914

915
let all_account_updates_list (t : t) : Account_update.t list =
916
  Call_forest.fold t.account_updates
×
917
    ~init:[ Account_update.of_fee_payer (fee_payer_account_update t) ]
×
918
    ~f:(Fn.flip List.cons)
×
919
  |> List.rev
920

921
let fee_excess (t : t) =
922
  Fee_excess.of_single (fee_token t, Currency.Fee.Signed.of_unsigned (fee t))
×
923

924
(* always `Accessed` for fee payer *)
925
let account_access_statuses (t : t) (status : Transaction_status.t) =
926
  let init = [ (fee_payer t, `Accessed) ] in
×
927
  let status_sym =
928
    match status with Applied -> `Accessed | Failed _ -> `Not_accessed
×
929
  in
930
  Call_forest.fold t.account_updates ~init ~f:(fun acc p ->
×
931
      (Account_update.account_id p, status_sym) :: acc )
×
932
  |> List.rev |> List.stable_dedup
×
933

934
let accounts_referenced (t : t) =
935
  List.map (account_access_statuses t Applied) ~f:(fun (acct_id, _status) ->
×
936
      acct_id )
×
937

938
let fee_payer_pk (t : t) = t.fee_payer.body.public_key
×
939

940
let value_if b ~then_ ~else_ = if b then then_ else else_
×
941

942
module Virtual = struct
943
  module Bool = struct
944
    type t = bool
945

946
    let true_ = true
947

948
    let assert_ _ = ()
×
949

950
    let equal = Bool.equal
951

952
    let not = not
953

954
    let ( || ) = ( || )
955

956
    let ( && ) = ( && )
957
  end
958

959
  module Unit = struct
960
    type t = unit
961

962
    let if_ = value_if
963
  end
964

965
  module Ledger = Unit
966
  module Account = Unit
967

968
  module Amount = struct
969
    open Currency.Amount
970

971
    type nonrec t = t
972

973
    let if_ = value_if
974

975
    module Signed = Signed
976

977
    let zero = zero
978

979
    let ( - ) (x1 : t) (x2 : t) : Signed.t =
980
      Option.value_exn Signed.(of_unsigned x1 + negate (of_unsigned x2))
×
981

982
    let ( + ) (x1 : t) (x2 : t) : t = Option.value_exn (add x1 x2)
×
983

984
    let add_signed (x1 : t) (x2 : Signed.t) : t =
985
      let y = Option.value_exn Signed.(of_unsigned x1 + x2) in
×
986
      match y.sgn with Pos -> y.magnitude | Neg -> failwith "add_signed"
×
987
  end
988

989
  module Token_id = struct
990
    include Token_id
991

992
    let if_ = value_if
993
  end
994

995
  module Zkapp_command = struct
996
    type t = Account_update.t list
997

998
    let if_ = value_if
999

1000
    type account_update = Account_update.t
1001

1002
    let empty = []
1003

1004
    let is_empty = List.is_empty
1005

1006
    let pop (t : t) = match t with [] -> failwith "pop" | p :: t -> (p, t)
×
1007
  end
1008
end
1009

1010
let check_authorization (p : Account_update.t) : unit Or_error.t =
1011
  match (p.authorization, p.body.authorization_kind) with
134✔
1012
  | None_given, None_given | Proof _, Proof _ | Signature _, Signature ->
5✔
1013
      Ok ()
1014
  | _ ->
×
1015
      let err =
1016
        let expected =
1017
          Account_update.Authorization_kind.to_control_tag
1018
            p.body.authorization_kind
1019
        in
1020
        let got = Control.tag p.authorization in
×
1021
        Error.create "Authorization kind does not match the authorization"
×
1022
          [ ("expected", expected); ("got", got) ]
1023
          [%sexp_of: (string * Control.Tag.t) list]
1024
      in
1025
      Error err
1026

1027
module Verifiable : sig
1028
  [%%versioned:
1029
  module Stable : sig
1030
    module V1 : sig
1031
      type t = private
1032
        { fee_payer : Account_update.Fee_payer.Stable.V1.t
1033
        ; account_updates :
1034
            ( Side_loaded_verification_key.Stable.V2.t
1035
            , Zkapp_basic.F.Stable.V1.t )
1036
            With_hash.Stable.V1.t
1037
            option
1038
            Call_forest.With_hashes_and_data.Stable.V1.t
1039
        ; memo : Signed_command_memo.Stable.V1.t
1040
        }
1041
      [@@deriving sexp, compare, equal, hash, yojson]
1042

1043
      val to_latest : t -> t
1044
    end
1045
  end]
1046

1047
  val load_vk_from_ledger :
1048
       location_of_account:(Account_id.t -> 'loc option)
1049
    -> get:('loc -> Account.t option)
1050
    -> Zkapp_basic.F.t
1051
    -> Account_id.t
1052
    -> Verification_key_wire.t Or_error.t
1053

1054
  val load_vks_from_ledger :
1055
       location_of_account_batch:
1056
         (Account_id.t list -> (Account_id.t * 'loc option) list)
1057
    -> get_batch:('loc list -> ('loc * Account.t option) list)
1058
    -> Account_id.t list
1059
    -> Verification_key_wire.t Account_id.Map.t
1060

1061
  val create :
1062
       T.t
1063
    -> failed:bool
1064
    -> find_vk:
1065
         (Zkapp_basic.F.t -> Account_id.t -> Verification_key_wire.t Or_error.t)
1066
    -> t Or_error.t
1067

1068
  module type Command_wrapper_intf = sig
1069
    type 'a t
1070

1071
    val unwrap : 'a t -> 'a
1072

1073
    val map : 'a t -> f:('a -> 'b) -> 'b t
1074

1075
    val is_failed : 'a t -> bool
1076
  end
1077

1078
  module type Create_all_intf = sig
1079
    type cache
1080

1081
    module Command_wrapper : Command_wrapper_intf
1082

1083
    val create_all :
1084
      T.t Command_wrapper.t list -> cache -> t Command_wrapper.t list Or_error.t
1085
  end
1086

1087
  module From_unapplied_sequence :
1088
    Create_all_intf
1089
      with type 'a Command_wrapper.t = 'a
1090
       and type cache =
1091
        Verification_key_wire.t Zkapp_basic.F_map.Map.t Account_id.Map.t
1092

1093
  module From_applied_sequence :
1094
    Create_all_intf
1095
      with type 'a Command_wrapper.t = 'a With_status.t
1096
       and type cache = Verification_key_wire.t Account_id.Map.t
1097
end = struct
1098
  [%%versioned
1099
  module Stable = struct
1100
    module V1 = struct
1101
      type t =
18✔
1102
        { fee_payer : Account_update.Fee_payer.Stable.V1.t
×
1103
        ; account_updates :
×
1104
            ( Side_loaded_verification_key.Stable.V2.t
×
1105
            , Zkapp_basic.F.Stable.V1.t )
×
1106
            With_hash.Stable.V1.t
×
1107
            option
×
1108
            Call_forest.With_hashes_and_data.Stable.V1.t
×
1109
        ; memo : Signed_command_memo.Stable.V1.t
×
1110
        }
1111
      [@@deriving sexp, compare, equal, hash, yojson]
45✔
1112

1113
      let to_latest = Fn.id
1114
    end
1115
  end]
1116

1117
  let ok_if_vk_hash_expected ~got ~expected =
1118
    if not @@ Zkapp_basic.F.equal (With_hash.hash got) expected then
5✔
1119
      Error
×
1120
        (Error.create "Expected vk hash doesn't match hash in vk we received"
×
1121
           [ ("expected_vk_hash", expected)
1122
           ; ("got_vk_hash", With_hash.hash got)
×
1123
           ]
1124
           [%sexp_of: (string * Zkapp_basic.F.t) list] )
1125
    else Ok got
5✔
1126

1127
  let load_vk_from_ledger ~location_of_account ~get expected_vk_hash account_id
1128
      =
1129
    match
3✔
1130
      let open Option.Let_syntax in
1131
      let%bind location = location_of_account account_id in
3✔
1132
      let%bind (account : Account.t) = get location in
3✔
1133
      let%bind zkapp = account.zkapp in
1134
      zkapp.verification_key
3✔
1135
    with
1136
    | Some vk ->
3✔
1137
        ok_if_vk_hash_expected ~got:vk ~expected:expected_vk_hash
1138
    | None ->
×
1139
        let err =
1140
          Error.create "No verification key found for proved account update"
1141
            ("account_id", account_id) [%sexp_of: string * Account_id.t]
1142
        in
1143
        Error err
×
1144

1145
  let load_vks_from_ledger ~location_of_account_batch ~get_batch account_ids =
1146
    let locations =
200✔
1147
      location_of_account_batch account_ids |> List.filter_map ~f:snd
200✔
1148
    in
1149
    get_batch locations
200✔
1150
    |> List.filter_map ~f:(fun ((_, account) : _ * Account.t option) ->
200✔
1151
           let open Option.Let_syntax in
×
1152
           let account = Option.value_exn account in
1153
           let%bind zkapp = account.zkapp in
1154
           let%map verification_key = zkapp.verification_key in
1155
           (Account.identifier account, verification_key) )
×
1156
    |> Account_id.Map.of_alist_exn
1157

1158
  (* Ensures that there's a verification_key available for all account_updates
1159
   * and creates a valid command associating the correct keys with each
1160
   * account_id.
1161
   *
1162
   * If an account_update replaces the verification_key (or deletes it),
1163
   * subsequent account_updates use the replaced key instead of looking in the
1164
   * ledger for the key (ie set by a previous transaction).
1165
   *)
1166
  let create ({ fee_payer; account_updates; memo } : T.t) ~failed ~find_vk :
1167
      t Or_error.t =
1168
    With_return.with_return (fun { return } ->
20✔
1169
        let tbl = Account_id.Table.create () in
20✔
1170
        let vks_overridden =
20✔
1171
          (* Keep track of the verification keys that have been set so far
1172
             during this transaction.
1173
          *)
1174
          ref Account_id.Map.empty
1175
        in
1176
        let account_updates =
1177
          Call_forest.map account_updates ~f:(fun p ->
1178
              let account_id = Account_update.account_id p in
134✔
1179
              let vks_overriden' =
134✔
1180
                match Account_update.verification_key_update_to_option p with
1181
                | Zkapp_basic.Set_or_keep.Set vk_next ->
42✔
1182
                    Account_id.Map.set !vks_overridden ~key:account_id
42✔
1183
                      ~data:vk_next
1184
                | Zkapp_basic.Set_or_keep.Keep ->
92✔
1185
                    !vks_overridden
1186
              in
1187
              let () =
1188
                match check_authorization p with
1189
                | Ok () ->
134✔
1190
                    ()
1191
                | Error _ as err ->
×
1192
                    return err
×
1193
              in
1194
              match (p.body.authorization_kind, failed) with
1195
              | Proof vk_hash, false -> (
5✔
1196
                  let prioritized_vk =
1197
                    (* only lookup _past_ vk setting, ie exclude the new one we
1198
                     * potentially set in this account_update (use the non-'
1199
                     * vks_overrided) . *)
1200
                    match Account_id.Map.find !vks_overridden account_id with
1201
                    | Some (Some vk) -> (
2✔
1202
                        match
1203
                          ok_if_vk_hash_expected ~got:vk ~expected:vk_hash
1204
                        with
1205
                        | Ok vk ->
2✔
1206
                            Some vk
1207
                        | Error err ->
×
1208
                            return (Error err) )
×
1209
                    | Some None ->
×
1210
                        (* we explicitly have erased the key *)
1211
                        let err =
1212
                          Error.create
1213
                            "No verification key found for proved account \
1214
                             update: the verification key was removed by a \
1215
                             previous account update"
1216
                            ("account_id", account_id)
1217
                            [%sexp_of: string * Account_id.t]
1218
                        in
1219
                        return (Error err)
×
1220
                    | None -> (
3✔
1221
                        (* we haven't set anything; lookup the vk in the fallback *)
1222
                        match find_vk vk_hash account_id with
1223
                        | Error e ->
×
1224
                            return (Error e)
×
1225
                        | Ok vk ->
3✔
1226
                            Some vk )
1227
                  in
1228
                  match prioritized_vk with
1229
                  | Some prioritized_vk ->
5✔
1230
                      Account_id.Table.update tbl account_id ~f:(fun _ ->
1231
                          With_hash.hash prioritized_vk ) ;
5✔
1232
                      (* return the updated overrides *)
1233
                      vks_overridden := vks_overriden' ;
5✔
1234
                      (p, Some prioritized_vk)
1235
                  | None ->
×
1236
                      (* The transaction failed, so we allow the vk to be missing. *)
1237
                      (p, None) )
1238
              | _ ->
129✔
1239
                  vks_overridden := vks_overriden' ;
1240
                  (p, None) )
1241
        in
1242
        Ok { fee_payer; account_updates; memo } )
20✔
1243

1244
  module type Cache_intf = sig
1245
    type t
1246

1247
    val find :
1248
         t
1249
      -> account_id:Account_id.t
1250
      -> vk_hash:Zkapp_basic.F.t
1251
      -> Verification_key_wire.t option
1252

1253
    val add : t -> account_id:Account_id.t -> vk:Verification_key_wire.t -> t
1254
  end
1255

1256
  module type Command_wrapper_intf = sig
1257
    type 'a t
1258

1259
    val unwrap : 'a t -> 'a
1260

1261
    val map : 'a t -> f:('a -> 'b) -> 'b t
1262

1263
    val is_failed : 'a t -> bool
1264
  end
1265

1266
  module type Create_all_intf = sig
1267
    type cache
1268

1269
    module Command_wrapper : Command_wrapper_intf
1270

1271
    val create_all :
1272
      T.t Command_wrapper.t list -> cache -> t Command_wrapper.t list Or_error.t
1273
  end
1274

1275
  module Make_create_all
1276
      (Cache : Cache_intf)
1277
      (Command_wrapper : Command_wrapper_intf) :
1278
    Create_all_intf
1279
      with module Command_wrapper := Command_wrapper
1280
       and type cache = Cache.t = struct
1281
    type cache = Cache.t
1282

1283
    let create_all (wrapped_cmds : T.t Command_wrapper.t list)
1284
        (init_cache : Cache.t) : t Command_wrapper.t list Or_error.t =
1285
      Or_error.try_with (fun () ->
200✔
1286
          snd (* remove the helper cache we folded with *)
200✔
1287
            (List.fold_map wrapped_cmds ~init:init_cache
200✔
1288
               ~f:(fun running_cache wrapped_cmd ->
1289
                 let cmd = Command_wrapper.unwrap wrapped_cmd in
×
1290
                 let cmd_failed = Command_wrapper.is_failed wrapped_cmd in
×
1291
                 let verified_cmd : t =
×
1292
                   create cmd ~failed:cmd_failed
×
1293
                     ~find_vk:(fun vk_hash account_id ->
1294
                       (* first we check if there's anything in the running
1295
                          cache within this chunk so far *)
1296
                       match Cache.find running_cache ~account_id ~vk_hash with
×
1297
                       | None ->
×
1298
                           Error
1299
                             (Error.of_string
×
1300
                                "verification key not found in cache" )
1301
                       | Some vk ->
×
1302
                           Ok vk )
1303
                   |> Or_error.ok_exn
×
1304
                 in
1305
                 let running_cache' =
1306
                   (* update the cache if the command is not failed *)
1307
                   if not cmd_failed then
1308
                     List.fold (extract_vks cmd) ~init:running_cache
×
1309
                       ~f:(fun acc (account_id, vk) ->
1310
                         Cache.add acc ~account_id ~vk )
×
1311
                   else running_cache
×
1312
                 in
1313
                 ( running_cache'
1314
                 , Command_wrapper.map wrapped_cmd ~f:(Fn.const verified_cmd) ) )
×
1315
            ) )
1316
  end
1317

1318
  (* There are 2 situations in which we are converting commands to their verifiable format:
1319
       - we are reasoning about the validity of commands when the sequence is not yet known
1320
       - we are reasoning about the validity of commands when the sequence (and by extension, status) is known
1321
  *)
1322

1323
  module From_unapplied_sequence = struct
1324
    module Cache = struct
1325
      type t = Verification_key_wire.t Zkapp_basic.F_map.Map.t Account_id.Map.t
1326

1327
      let find (t : t) ~account_id ~vk_hash =
1328
        let%bind.Option vks = Map.find t account_id in
×
1329
        Map.find vks vk_hash
×
1330

1331
      let add (t : t) ~account_id ~(vk : Verification_key_wire.t) =
1332
        Map.update t account_id ~f:(fun vks_opt ->
×
1333
            let vks =
×
1334
              Option.value vks_opt ~default:Zkapp_basic.F_map.Map.empty
1335
            in
1336
            Map.set vks ~key:vk.hash ~data:vk )
×
1337
    end
1338

1339
    module Command_wrapper : Command_wrapper_intf with type 'a t = 'a = struct
1340
      type 'a t = 'a
1341

1342
      let unwrap t = t
×
1343

1344
      let map t ~f = f t
×
1345

1346
      let is_failed _ = false
×
1347
    end
1348

1349
    include Make_create_all (Cache) (Command_wrapper)
1350
  end
1351

1352
  module From_applied_sequence = struct
1353
    module Cache = struct
1354
      type t = Verification_key_wire.t Account_id.Map.t
1355

1356
      let find (t : t) ~account_id ~vk_hash =
1357
        let%bind.Option vk = Map.find t account_id in
×
1358
        Option.some_if (Zkapp_basic.F.equal vk_hash vk.hash) vk
×
1359

1360
      let add (t : t) ~account_id ~vk = Map.set t ~key:account_id ~data:vk
×
1361
    end
1362

1363
    module Command_wrapper :
1364
      Command_wrapper_intf with type 'a t = 'a With_status.t = struct
1365
      type 'a t = 'a With_status.t
1366

1367
      let unwrap = With_status.data
1368

1369
      let map { With_status.status; data } ~f =
1370
        { With_status.status; data = f data }
960✔
1371

1372
      let is_failed { With_status.status; _ } =
1373
        match status with Applied -> false | Failed _ -> true
×
1374
    end
1375

1376
    include Make_create_all (Cache) (Command_wrapper)
1377
  end
1378
end
1379

1380
let of_verifiable (t : Verifiable.t) : t =
1381
  { fee_payer = t.fee_payer
20✔
1382
  ; account_updates = Call_forest.map t.account_updates ~f:fst
20✔
1383
  ; memo = t.memo
1384
  }
1385

1386
module Transaction_commitment = struct
1387
  module Stable = Kimchi_backend.Pasta.Basic.Fp.Stable
1388

1389
  type t = (Stable.Latest.t[@deriving sexp])
1390

1391
  let sexp_of_t = Stable.Latest.sexp_of_t
1392

1393
  let t_of_sexp = Stable.Latest.t_of_sexp
1394

1395
  let empty = Outside_hash_image.t
1396

1397
  let typ = Snark_params.Tick.Field.typ
1398

1399
  let create ~(account_updates_hash : Digest.Forest.t) : t =
1400
    (account_updates_hash :> t)
40✔
1401

1402
  let create_complete (t : t) ~memo_hash
1403
      ~(fee_payer_hash : Digest.Account_update.t) =
1404
    Random_oracle.hash ~init:Hash_prefix.account_update_cons
40✔
1405
      [| memo_hash; (fee_payer_hash :> t); t |]
1406

1407
  module Checked = struct
1408
    type t = Pickles.Impls.Step.Field.t
1409

1410
    let create ~(account_updates_hash : Digest.Forest.Checked.t) =
1411
      (account_updates_hash :> t)
24✔
1412

1413
    let create_complete (t : t) ~memo_hash
1414
        ~(fee_payer_hash : Digest.Account_update.Checked.t) =
1415
      Random_oracle.Checked.hash ~init:Hash_prefix.account_update_cons
24✔
1416
        [| memo_hash; (fee_payer_hash :> t); t |]
1417
  end
1418
end
1419

1420
let account_updates_hash (t : t) = Call_forest.hash t.account_updates
40✔
1421

1422
let commitment (t : t) : Transaction_commitment.t =
1423
  Transaction_commitment.create ~account_updates_hash:(account_updates_hash t)
×
1424

1425
(** This module defines weights for each component of a `Zkapp_command.t` element. *)
1426
module Weight = struct
1427
  let account_update : Account_update.t -> int = fun _ -> 1
×
1428

1429
  let fee_payer (_fp : Account_update.Fee_payer.t) : int = 1
×
1430

1431
  let account_updates : (Account_update.t, _, _) Call_forest.t -> int =
1432
    Call_forest.fold ~init:0 ~f:(fun acc p -> acc + account_update p)
×
1433

1434
  let memo : Signed_command_memo.t -> int = fun _ -> 0
×
1435
end
1436

1437
let weight (zkapp_command : t) : int =
1438
  let { fee_payer; account_updates; memo } = zkapp_command in
×
1439
  List.sum
1440
    (module Int)
1441
    ~f:Fn.id
1442
    [ Weight.fee_payer fee_payer
×
1443
    ; Weight.account_updates account_updates
×
1444
    ; Weight.memo memo
×
1445
    ]
1446

1447
module type Valid_intf = sig
1448
  [%%versioned:
1449
  module Stable : sig
1450
    module V1 : sig
1451
      type t = private { zkapp_command : T.Stable.V1.t }
1452
      [@@deriving sexp, compare, equal, hash, yojson]
1453
    end
1454
  end]
1455

1456
  val to_valid_unsafe :
1457
    T.t -> [> `If_this_is_used_it_should_have_a_comment_justifying_it of t ]
1458

1459
  val to_valid :
1460
       T.t
1461
    -> failed:bool
1462
    -> find_vk:
1463
         (   Zkapp_basic.F.t
1464
          -> Account_id.t
1465
          -> (Verification_key_wire.t, Error.t) Result.t )
1466
    -> t Or_error.t
1467

1468
  val of_verifiable : Verifiable.t -> t
1469

1470
  val forget : t -> T.t
1471
end
1472

1473
module Valid :
1474
  Valid_intf
1475
    with type Stable.V1.t = Mina_wire_types.Mina_base.Zkapp_command.Valid.V1.t =
1476
struct
1477
  module S = Stable
1478

1479
  module Verification_key_hash = struct
1480
    [%%versioned
1481
    module Stable = struct
1482
      module V1 = struct
1483
        type t = Zkapp_basic.F.Stable.V1.t
×
1484
        [@@deriving sexp, compare, equal, hash, yojson]
45✔
1485

1486
        let to_latest = Fn.id
1487
      end
1488
    end]
1489
  end
1490

1491
  [%%versioned
1492
  module Stable = struct
1493
    module V1 = struct
1494
      type t = Mina_wire_types.Mina_base.Zkapp_command.Valid.V1.t =
18✔
1495
        { zkapp_command : S.V1.t }
×
1496
      [@@deriving sexp, compare, equal, hash, yojson]
45✔
1497

1498
      let to_latest = Fn.id
1499
    end
1500
  end]
1501

1502
  let create zkapp_command : t = { zkapp_command }
×
1503

1504
  let of_verifiable (t : Verifiable.t) : t = { zkapp_command = of_verifiable t }
20✔
1505

1506
  let to_valid_unsafe (t : T.t) :
1507
      [> `If_this_is_used_it_should_have_a_comment_justifying_it of t ] =
1508
    `If_this_is_used_it_should_have_a_comment_justifying_it (create t)
×
1509

1510
  let forget (t : t) : T.t = t.zkapp_command
20✔
1511

1512
  let to_valid (t : T.t) ~failed ~find_vk : t Or_error.t =
1513
    Verifiable.create t ~failed ~find_vk |> Or_error.map ~f:of_verifiable
20✔
1514
end
1515

1516
[%%define_locally Stable.Latest.(of_yojson, to_yojson)]
1517

1518
(* so transaction ids have a version tag *)
1519
include Codable.Make_base64 (Stable.Latest.With_top_version_tag)
1520

1521
type account_updates =
1522
  (Account_update.t, Digest.Account_update.t, Digest.Forest.t) Call_forest.t
1523

1524
let account_updates_deriver obj =
1525
  let of_zkapp_command_with_depth (ps : Account_update.Graphql_repr.t list) :
23✔
1526
      account_updates =
1527
    Call_forest.of_account_updates ps
20✔
1528
      ~account_update_depth:(fun (p : Account_update.Graphql_repr.t) ->
1529
        p.body.call_depth )
248✔
1530
    |> Call_forest.map ~f:Account_update.of_graphql_repr
20✔
1531
    |> Call_forest.accumulate_hashes'
1532
  and to_zkapp_command_with_depth (ps : account_updates) :
1533
      Account_update.Graphql_repr.t list =
1534
    ps
20✔
1535
    |> Call_forest.to_account_updates_map ~f:(fun ~depth p ->
1536
           Account_update.to_graphql_repr ~call_depth:depth p )
134✔
1537
  in
1538
  let open Fields_derivers_zkapps.Derivers in
1539
  let inner = (list @@ Account_update.Graphql_repr.deriver @@ o ()) @@ o () in
23✔
1540
  iso ~map:of_zkapp_command_with_depth ~contramap:to_zkapp_command_with_depth
23✔
1541
    inner obj
1542

1543
let deriver obj =
1544
  let open Fields_derivers_zkapps.Derivers in
23✔
1545
  let ( !. ) = ( !. ) ~t_fields_annots in
1546
  Fields.make_creator obj
23✔
1547
    ~fee_payer:!.Account_update.Fee_payer.deriver
23✔
1548
    ~account_updates:!.account_updates_deriver
23✔
1549
    ~memo:!.Signed_command_memo.deriver
23✔
1550
  |> finish "ZkappCommand" ~t_toplevel_annots
1551

1552
let arg_typ () = Fields_derivers_zkapps.(arg_typ (deriver @@ Derivers.o ()))
1✔
1553

1554
let typ () = Fields_derivers_zkapps.(typ (deriver @@ Derivers.o ()))
×
1555

1556
let to_json x = Fields_derivers_zkapps.(to_json (deriver @@ Derivers.o ())) x
20✔
1557

1558
let of_json x = Fields_derivers_zkapps.(of_json (deriver @@ Derivers.o ())) x
×
1559

1560
let account_updates_of_json x =
1561
  Fields_derivers_zkapps.(
×
1562
    of_json
×
1563
      ((list @@ Account_update.Graphql_repr.deriver @@ o ()) @@ derivers ()))
×
1564
    x
1565

1566
let zkapp_command_to_json x =
1567
  Fields_derivers_zkapps.(to_json (deriver @@ derivers ())) x
×
1568

1569
let arg_query_string x =
1570
  Fields_derivers_zkapps.Test.Loop.json_to_string_gql @@ to_json x
20✔
1571

1572
let dummy =
1573
  lazy
1574
    (let account_update : Account_update.t =
×
1575
       { body = Account_update.Body.dummy
1576
       ; authorization = Control.dummy_of_tag Signature
×
1577
       }
1578
     in
1579
     let fee_payer : Account_update.Fee_payer.t =
1580
       { body = Account_update.Body.Fee_payer.dummy
1581
       ; authorization = Signature.dummy
1582
       }
1583
     in
1584
     { fee_payer
1585
     ; account_updates = Call_forest.cons account_update []
×
1586
     ; memo = Signed_command_memo.empty
1587
     } )
1588

1589
module Make_update_group (Input : sig
1590
  type global_state
1591

1592
  type local_state
1593

1594
  type spec
1595

1596
  type connecting_ledger_hash
1597

1598
  val zkapp_segment_of_controls : Control.t list -> spec
1599
end) : sig
1600
  module Zkapp_command_intermediate_state : sig
1601
    type state = { global : Input.global_state; local : Input.local_state }
1602

1603
    type t =
1604
      { kind : [ `Same | `New | `Two_new ]
1605
      ; spec : Input.spec
1606
      ; state_before : state
1607
      ; state_after : state
1608
      ; connecting_ledger : Input.connecting_ledger_hash
1609
      }
1610
  end
1611

1612
  val group_by_zkapp_command_rev :
1613
       t list
1614
    -> (Input.global_state * Input.local_state * Input.connecting_ledger_hash)
1615
       list
1616
       list
1617
    -> Zkapp_command_intermediate_state.t list
1618
end = struct
1619
  open Input
1620

1621
  module Zkapp_command_intermediate_state = struct
1622
    type state = { global : global_state; local : local_state }
1623

1624
    type t =
1625
      { kind : [ `Same | `New | `Two_new ]
1626
      ; spec : spec
1627
      ; state_before : state
1628
      ; state_after : state
1629
      ; connecting_ledger : connecting_ledger_hash
1630
      }
1631
  end
1632

1633
  (** [group_by_zkapp_command_rev zkapp_commands stmtss] identifies before/after pairs of
1634
      statements, corresponding to account updates for each zkapp_command in [zkapp_commands] which minimize the
1635
      number of snark proofs needed to prove all of the zkapp_command.
1636

1637
      This function is intended to take multiple zkapp transactions as
1638
      its input, which is then converted to a [Account_update.t list list] using
1639
      [List.map ~f:Zkapp_command.zkapp_command]. The [stmtss] argument should
1640
      be a list of the same length, with 1 more state than the number of
1641
      zkapp_command for each transaction.
1642

1643
      For example, two transactions made up of zkapp_command [[p1; p2; p3]] and
1644
      [[p4; p5]] should have the statements [[[s0; s1; s2; s3]; [s3; s4; s5]]],
1645
      where each [s_n] is the state after applying [p_n] on top of [s_{n-1}], and
1646
      where [s0] is the initial state before any of the transactions have been
1647
      applied.
1648

1649
      Each pair is also identified with one of [`Same], [`New], or [`Two_new],
1650
      indicating that the next one ([`New]) or next two ([`Two_new]) [Zkapp_command.t]s
1651
      will need to be passed as part of the snark witness while applying that
1652
      pair.
1653
  *)
1654
  let group_by_zkapp_command_rev (zkapp_commands : t list)
1655
      (stmtss : (global_state * local_state * connecting_ledger_hash) list list)
1656
      : Zkapp_command_intermediate_state.t list =
1657
    let intermediate_state ~kind ~spec ~before ~after =
×
1658
      let global_before, local_before, _ = before in
×
1659
      let global_after, local_after, connecting_ledger = after in
1660
      { Zkapp_command_intermediate_state.kind
1661
      ; spec
1662
      ; state_before = { global = global_before; local = local_before }
1663
      ; state_after = { global = global_after; local = local_after }
1664
      ; connecting_ledger
1665
      }
1666
    in
1667
    let zkapp_account_updatess =
1668
      []
1669
      :: List.map zkapp_commands ~f:(fun (zkapp_command : t) ->
×
1670
             all_account_updates_list zkapp_command )
×
1671
    in
1672
    let rec group_by_zkapp_command_rev
1673
        (zkapp_commands : Account_update.t list list) stmtss acc =
1674
      match (zkapp_commands, stmtss) with
×
1675
      | ([] | [ [] ]), [ _ ] ->
×
1676
          (* We've associated statements with all given zkapp_command. *)
1677
          acc
1678
      | [ [ { authorization = a1; _ } ] ], [ [ before; after ] ] ->
×
1679
          (* There are no later zkapp_command to pair this one with. Prove it on its
1680
             own.
1681
          *)
1682
          intermediate_state ~kind:`Same
1683
            ~spec:(zkapp_segment_of_controls [ a1 ])
×
1684
            ~before ~after
1685
          :: acc
1686
      | [ []; [ { authorization = a1; _ } ] ], [ [ _ ]; [ before; after ] ] ->
×
1687
          (* This account_update is part of a new transaction, and there are no later
1688
             zkapp_command to pair it with. Prove it on its own.
1689
          *)
1690
          intermediate_state ~kind:`New
1691
            ~spec:(zkapp_segment_of_controls [ a1 ])
×
1692
            ~before ~after
1693
          :: acc
1694
      | ( ({ authorization = Proof _ as a1; _ } :: zkapp_command)
×
1695
          :: zkapp_commands
1696
        , (before :: (after :: _ as stmts)) :: stmtss ) ->
1697
          (* This account_update contains a proof, don't pair it with other account updates. *)
1698
          group_by_zkapp_command_rev
1699
            (zkapp_command :: zkapp_commands)
1700
            (stmts :: stmtss)
1701
            ( intermediate_state ~kind:`Same
1702
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1703
                ~before ~after
1704
            :: acc )
1705
      | ( []
×
1706
          :: ({ authorization = Proof _ as a1; _ } :: zkapp_command)
1707
             :: zkapp_commands
1708
        , [ _ ] :: (before :: (after :: _ as stmts)) :: stmtss ) ->
1709
          (* This account_update is part of a new transaction, and contains a proof, don't
1710
             pair it with other account updates.
1711
          *)
1712
          group_by_zkapp_command_rev
1713
            (zkapp_command :: zkapp_commands)
1714
            (stmts :: stmtss)
1715
            ( intermediate_state ~kind:`New
1716
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1717
                ~before ~after
1718
            :: acc )
1719
      | ( ({ authorization = a1; _ }
×
1720
          :: ({ authorization = Proof _; _ } :: _ as zkapp_command) )
1721
          :: zkapp_commands
1722
        , (before :: (after :: _ as stmts)) :: stmtss ) ->
1723
          (* The next account_update contains a proof, don't pair it with this account_update. *)
1724
          group_by_zkapp_command_rev
1725
            (zkapp_command :: zkapp_commands)
1726
            (stmts :: stmtss)
1727
            ( intermediate_state ~kind:`Same
1728
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1729
                ~before ~after
1730
            :: acc )
1731
      | ( ({ authorization = a1; _ } :: ([] as zkapp_command))
×
1732
          :: (({ authorization = Proof _; _ } :: _) :: _ as zkapp_commands)
1733
        , (before :: (after :: _ as stmts)) :: stmtss ) ->
1734
          (* The next account_update is in the next transaction and contains a proof,
1735
             don't pair it with this account_update.
1736
          *)
1737
          group_by_zkapp_command_rev
1738
            (zkapp_command :: zkapp_commands)
1739
            (stmts :: stmtss)
1740
            ( intermediate_state ~kind:`Same
1741
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1742
                ~before ~after
1743
            :: acc )
1744
      | ( ({ authorization = (Signature _ | None_given) as a1; _ }
×
1745
          :: { authorization = (Signature _ | None_given) as a2; _ }
×
1746
             :: zkapp_command )
1747
          :: zkapp_commands
1748
        , (before :: _ :: (after :: _ as stmts)) :: stmtss ) ->
1749
          (* The next two zkapp_command do not contain proofs, and are within the same
1750
             transaction. Pair them.
1751
             Ok to get "use_full_commitment" of [a1] because neither of them
1752
             contain a proof.
1753
          *)
1754
          group_by_zkapp_command_rev
1755
            (zkapp_command :: zkapp_commands)
1756
            (stmts :: stmtss)
1757
            ( intermediate_state ~kind:`Same
1758
                ~spec:(zkapp_segment_of_controls [ a1; a2 ])
×
1759
                ~before ~after
1760
            :: acc )
1761
      | ( []
×
1762
          :: ({ authorization = a1; _ }
1763
             :: ({ authorization = Proof _; _ } :: _ as zkapp_command) )
1764
             :: zkapp_commands
1765
        , [ _ ] :: (before :: (after :: _ as stmts)) :: stmtss ) ->
1766
          (* This account_update is in the next transaction, and the next account_update contains a
1767
             proof, don't pair it with this account_update.
1768
          *)
1769
          group_by_zkapp_command_rev
1770
            (zkapp_command :: zkapp_commands)
1771
            (stmts :: stmtss)
1772
            ( intermediate_state ~kind:`New
1773
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1774
                ~before ~after
1775
            :: acc )
1776
      | ( []
×
1777
          :: ({ authorization = (Signature _ | None_given) as a1; _ }
×
1778
             :: { authorization = (Signature _ | None_given) as a2; _ }
×
1779
                :: zkapp_command )
1780
             :: zkapp_commands
1781
        , [ _ ] :: (before :: _ :: (after :: _ as stmts)) :: stmtss ) ->
1782
          (* The next two zkapp_command do not contain proofs, and are within the same
1783
             new transaction. Pair them.
1784
             Ok to get "use_full_commitment" of [a1] because neither of them
1785
             contain a proof.
1786
          *)
1787
          group_by_zkapp_command_rev
1788
            (zkapp_command :: zkapp_commands)
1789
            (stmts :: stmtss)
1790
            ( intermediate_state ~kind:`New
1791
                ~spec:(zkapp_segment_of_controls [ a1; a2 ])
×
1792
                ~before ~after
1793
            :: acc )
1794
      | ( [ { authorization = (Signature _ | None_given) as a1; _ } ]
×
1795
          :: ({ authorization = (Signature _ | None_given) as a2; _ }
×
1796
             :: zkapp_command )
1797
             :: zkapp_commands
1798
        , (before :: _after1) :: (_before2 :: (after :: _ as stmts)) :: stmtss )
1799
        ->
1800
          (* The next two zkapp_command do not contain proofs, and the second is within
1801
             a new transaction. Pair them.
1802
             Ok to get "use_full_commitment" of [a1] because neither of them
1803
             contain a proof.
1804
          *)
1805
          group_by_zkapp_command_rev
1806
            (zkapp_command :: zkapp_commands)
1807
            (stmts :: stmtss)
1808
            ( intermediate_state ~kind:`New
1809
                ~spec:(zkapp_segment_of_controls [ a1; a2 ])
×
1810
                ~before ~after
1811
            :: acc )
1812
      | ( []
×
1813
          :: ({ authorization = a1; _ } :: zkapp_command)
1814
             :: (({ authorization = Proof _; _ } :: _) :: _ as zkapp_commands)
1815
        , [ _ ] :: (before :: ([ after ] as stmts)) :: (_ :: _ as stmtss) ) ->
1816
          (* The next transaction contains a proof, and this account_update is in a new
1817
             transaction, don't pair it with the next account_update.
1818
          *)
1819
          group_by_zkapp_command_rev
1820
            (zkapp_command :: zkapp_commands)
1821
            (stmts :: stmtss)
1822
            ( intermediate_state ~kind:`New
1823
                ~spec:(zkapp_segment_of_controls [ a1 ])
×
1824
                ~before ~after
1825
            :: acc )
1826
      | ( []
×
1827
          :: [ { authorization = (Signature _ | None_given) as a1; _ } ]
×
1828
             :: ({ authorization = (Signature _ | None_given) as a2; _ }
×
1829
                :: zkapp_command )
1830
                :: zkapp_commands
1831
        , [ _ ]
1832
          :: [ before; _after1 ]
1833
             :: (_before2 :: (after :: _ as stmts)) :: stmtss ) ->
1834
          (* The next two zkapp_command do not contain proofs, the first is within a
1835
             new transaction, and the second is within another new transaction.
1836
             Pair them.
1837
             Ok to get "use_full_commitment" of [a1] because neither of them
1838
             contain a proof.
1839
          *)
1840
          group_by_zkapp_command_rev
1841
            (zkapp_command :: zkapp_commands)
1842
            (stmts :: stmtss)
1843
            ( intermediate_state ~kind:`Two_new
1844
                ~spec:(zkapp_segment_of_controls [ a1; a2 ])
×
1845
                ~before ~after
1846
            :: acc )
1847
      | [ [ { authorization = a1; _ } ] ], (before :: after :: _) :: _ ->
×
1848
          (* This account_update is the final account_update given. Prove it on its own. *)
1849
          intermediate_state ~kind:`Same
1850
            ~spec:(zkapp_segment_of_controls [ a1 ])
×
1851
            ~before ~after
1852
          :: acc
1853
      | ( [] :: [ { authorization = a1; _ } ] :: [] :: _
×
1854
        , [ _ ] :: (before :: after :: _) :: _ ) ->
1855
          (* This account_update is the final account_update given, in a new transaction. Prove it
1856
             on its own.
1857
          *)
1858
          intermediate_state ~kind:`New
1859
            ~spec:(zkapp_segment_of_controls [ a1 ])
×
1860
            ~before ~after
1861
          :: acc
1862
      | _, [] ->
×
1863
          failwith "group_by_zkapp_command_rev: No statements remaining"
1864
      | ([] | [ [] ]), _ ->
×
1865
          failwith "group_by_zkapp_command_rev: Unmatched statements remaining"
1866
      | [] :: _, [] :: _ ->
×
1867
          failwith
1868
            "group_by_zkapp_command_rev: No final statement for current \
1869
             transaction"
1870
      | [] :: _, (_ :: _ :: _) :: _ ->
×
1871
          failwith
1872
            "group_by_zkapp_command_rev: Unmatched statements for current \
1873
             transaction"
1874
      | [] :: [ _ ] :: _, [ _ ] :: (_ :: _ :: _ :: _) :: _ ->
×
1875
          failwith
1876
            "group_by_zkapp_command_rev: Unmatched statements for next \
1877
             transaction"
1878
      | [ []; [ _ ] ], [ _ ] :: [ _; _ ] :: _ :: _ ->
×
1879
          failwith
1880
            "group_by_zkapp_command_rev: Unmatched statements after next \
1881
             transaction"
1882
      | (_ :: _) :: _, ([] | [ _ ]) :: _ | (_ :: _ :: _) :: _, [ _; _ ] :: _ ->
×
1883
          failwith
1884
            "group_by_zkapp_command_rev: Too few statements remaining for the \
1885
             current transaction"
1886
      | ([] | [ _ ]) :: [] :: _, _ ->
×
1887
          failwith
1888
            "group_by_zkapp_command_rev: The next transaction has no \
1889
             zkapp_command"
1890
      | [] :: (_ :: _) :: _, _ :: ([] | [ _ ]) :: _
×
1891
      | [] :: (_ :: _ :: _) :: _, _ :: [ _; _ ] :: _ ->
×
1892
          failwith
1893
            "group_by_zkapp_command_rev: Too few statements remaining for the \
1894
             next transaction"
1895
      | [ _ ] :: (_ :: _) :: _, _ :: ([] | [ _ ]) :: _ ->
×
1896
          failwith
1897
            "group_by_zkapp_command_rev: Too few statements remaining for the \
1898
             next transaction"
1899
      | [] :: [ _ ] :: (_ :: _) :: _, _ :: _ :: ([] | [ _ ]) :: _ ->
×
1900
          failwith
1901
            "group_by_zkapp_command_rev: Too few statements remaining for the \
1902
             transaction after next"
1903
      | ([] | [ _ ]) :: (_ :: _) :: _, [ _ ] ->
×
1904
          failwith
1905
            "group_by_zkapp_command_rev: No statements given for the next \
1906
             transaction"
1907
      | [] :: [ _ ] :: (_ :: _) :: _, [ _; _ :: _ :: _ ] ->
×
1908
          failwith
1909
            "group_by_zkapp_command_rev: No statements given for transaction \
1910
             after next"
1911
    in
1912
    group_by_zkapp_command_rev zkapp_account_updatess stmtss []
1913
end
1914

1915
(*Transaction_snark.Zkapp_command_segment.Basic.t*)
1916
type possible_segments = Proved | Signed_single | Signed_pair
1917

1918
module Update_group = Make_update_group (struct
1919
  type local_state = unit
1920

1921
  type global_state = unit
1922

1923
  type connecting_ledger_hash = unit
1924

1925
  type spec = possible_segments
1926

1927
  let zkapp_segment_of_controls controls : spec =
1928
    match controls with
×
1929
    | [ Control.Proof _ ] ->
×
1930
        Proved
1931
    | [ (Control.Signature _ | Control.None_given) ] ->
×
1932
        Signed_single
1933
    | [ Control.(Signature _ | None_given); Control.(Signature _ | None_given) ]
×
1934
      ->
1935
        Signed_pair
1936
    | _ ->
×
1937
        failwith "zkapp_segment_of_controls: Unsupported combination"
1938
end)
1939

1940
let zkapp_cost ~proof_segments ~signed_single_segments ~signed_pair_segments
1941
    ~(genesis_constants : Genesis_constants.t) () =
1942
  (*10.26*np + 10.08*n2 + 9.14*n1 < 69.45*)
1943
  let proof_cost = genesis_constants.zkapp_proof_update_cost in
×
1944
  let signed_pair_cost = genesis_constants.zkapp_signed_pair_update_cost in
1945
  let signed_single_cost = genesis_constants.zkapp_signed_single_update_cost in
1946
  Float.(
1947
    (proof_cost * of_int proof_segments)
×
1948
    + (signed_pair_cost * of_int signed_pair_segments)
×
1949
    + (signed_single_cost * of_int signed_single_segments))
×
1950

1951
(* Zkapp_command transactions are filtered using this predicate
1952
   - when adding to the transaction pool
1953
   - in incoming blocks
1954
*)
1955
let valid_size ~(genesis_constants : Genesis_constants.t) (t : t) :
1956
    unit Or_error.t =
1957
  let events_elements events =
×
1958
    List.fold events ~init:0 ~f:(fun acc event -> acc + Array.length event)
×
1959
  in
1960
  let all_updates, num_event_elements, num_action_elements =
1961
    Call_forest.fold t.account_updates
×
1962
      ~init:([ Account_update.of_fee_payer (fee_payer_account_update t) ], 0, 0)
×
1963
      ~f:(fun (acc, num_event_elements, num_action_elements)
1964
              (account_update : Account_update.t) ->
1965
        let account_update_evs_elements =
×
1966
          events_elements account_update.body.events
1967
        in
1968
        let account_update_seq_evs_elements =
×
1969
          events_elements account_update.body.actions
1970
        in
1971
        ( account_update :: acc
×
1972
        , num_event_elements + account_update_evs_elements
1973
        , num_action_elements + account_update_seq_evs_elements ) )
1974
    |> fun (updates, ev, sev) -> (List.rev updates, ev, sev)
×
1975
  in
1976
  let groups =
×
1977
    Update_group.group_by_zkapp_command_rev [ t ]
1978
      ( [ ((), (), ()) ]
1979
      :: [ ((), (), ()) :: List.map all_updates ~f:(fun _ -> ((), (), ())) ] )
×
1980
  in
1981
  let proof_segments, signed_single_segments, signed_pair_segments =
×
1982
    List.fold ~init:(0, 0, 0) groups
1983
      ~f:(fun (proof_segments, signed_singles, signed_pairs) { spec; _ } ->
1984
        match spec with
×
1985
        | Proved ->
×
1986
            (proof_segments + 1, signed_singles, signed_pairs)
1987
        | Signed_single ->
×
1988
            (proof_segments, signed_singles + 1, signed_pairs)
1989
        | Signed_pair ->
×
1990
            (proof_segments, signed_singles, signed_pairs + 1) )
1991
  in
1992
  let cost_limit = genesis_constants.zkapp_transaction_cost_limit in
×
1993
  let max_event_elements = genesis_constants.max_event_elements in
1994
  let max_action_elements = genesis_constants.max_action_elements in
1995
  let zkapp_cost_within_limit =
1996
    Float.(
1997
      zkapp_cost ~proof_segments ~signed_single_segments ~signed_pair_segments
×
1998
        ~genesis_constants ()
1999
      < cost_limit)
2000
  in
2001
  let valid_event_elements = num_event_elements <= max_event_elements in
2002
  let valid_action_elements = num_action_elements <= max_action_elements in
2003
  if zkapp_cost_within_limit && valid_event_elements && valid_action_elements
×
2004
  then Ok ()
×
2005
  else
2006
    let proof_zkapp_command_err =
×
2007
      if zkapp_cost_within_limit then None
×
2008
      else Some (sprintf "zkapp transaction too expensive")
×
2009
    in
2010
    let events_err =
2011
      if valid_event_elements then None
×
2012
      else
2013
        Some
×
2014
          (sprintf "too many event elements (%d, max allowed is %d)"
×
2015
             num_event_elements max_event_elements )
2016
    in
2017
    let actions_err =
2018
      if valid_action_elements then None
×
2019
      else
2020
        Some
×
2021
          (sprintf "too many sequence event elements (%d, max allowed is %d)"
×
2022
             num_action_elements max_action_elements )
2023
    in
2024
    let err_msg =
2025
      List.filter
×
2026
        [ proof_zkapp_command_err; events_err; actions_err ]
2027
        ~f:Option.is_some
2028
      |> List.map ~f:(fun opt -> Option.value_exn opt)
×
2029
      |> String.concat ~sep:"; "
2030
    in
2031
    Error (Error.of_string err_msg)
×
2032

2033
let has_zero_vesting_period t =
2034
  Call_forest.exists t.account_updates ~f:(fun p ->
×
2035
      match p.body.update.timing with
×
2036
      | Keep ->
×
2037
          false
2038
      | Set { vesting_period; _ } ->
×
2039
          Mina_numbers.Global_slot_span.(equal zero) vesting_period )
×
2040

2041
let is_incompatible_version t =
2042
  Call_forest.exists t.account_updates ~f:(fun p ->
×
2043
      match p.body.update.permissions with
×
2044
      | Keep ->
×
2045
          false
2046
      | Set { set_verification_key = _auth, txn_version; _ } ->
×
2047
          not Mina_numbers.Txn_version.(equal_to_current txn_version) )
×
2048

2049
let get_transaction_commitments (zkapp_command : t) =
2050
  let memo_hash = Signed_command_memo.hash zkapp_command.memo in
40✔
2051
  let fee_payer_hash =
40✔
2052
    Account_update.of_fee_payer zkapp_command.fee_payer
40✔
2053
    |> Digest.Account_update.create
2054
  in
2055
  let account_updates_hash = account_updates_hash zkapp_command in
40✔
2056
  let txn_commitment = Transaction_commitment.create ~account_updates_hash in
40✔
2057
  let full_txn_commitment =
2058
    Transaction_commitment.create_complete txn_commitment ~memo_hash
2059
      ~fee_payer_hash
2060
  in
2061
  (txn_commitment, full_txn_commitment)
40✔
2062

2063
let inner_query =
2064
  lazy
2065
    (Option.value_exn ~message:"Invariant: All projectable derivers are Some"
2✔
2066
       Fields_derivers_zkapps.(inner_query (deriver @@ Derivers.o ())) )
2✔
2067

2068
module For_tests = struct
2069
  let replace_vks t vk =
2070
    { t with
×
2071
      account_updates =
2072
        Call_forest.map t.account_updates ~f:(fun (p : Account_update.t) ->
×
2073
            { p with
×
2074
              body =
2075
                { p.body with
2076
                  update =
2077
                    { p.body.update with
2078
                      verification_key =
2079
                        (* replace dummy vks in vk Setting *)
2080
                        ( match p.body.update.verification_key with
2081
                        | Set _vk ->
×
2082
                            Set vk
2083
                        | Keep ->
×
2084
                            Keep )
2085
                    }
2086
                ; authorization_kind =
2087
                    (* replace dummy vk hashes in authorization kind *)
2088
                    ( match p.body.authorization_kind with
2089
                    | Proof _vk_hash ->
×
2090
                        Proof (With_hash.hash vk)
×
2091
                    | ak ->
×
2092
                        ak )
2093
                }
2094
            } )
2095
    }
2096
end
2097

2098
let%test "latest zkApp version" =
2099
  (* if this test fails, update `Transaction_hash.hash_of_transaction_id`
2100
     for latest version, then update this test
2101
  *)
2102
  Stable.Latest.version = 1
×
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