• 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

22.42
/src/lib/runtime_config/runtime_config.ml
1
open Core_kernel
16✔
2

3
module Fork_config = struct
4
  (* Note that length might be smaller than the gernesis_slot
5
     or equal if a block was produced in every slot possible. *)
6
  type t =
16✔
7
    { state_hash : string
×
8
    ; blockchain_length : int (* number of blocks produced since genesis *)
×
9
    ; global_slot_since_genesis : int (* global slot since genesis *)
×
10
    }
11
  [@@deriving yojson, bin_io_unversioned]
64✔
12

13
  let gen =
14
    let open Quickcheck.Generator.Let_syntax in
15
    let%bind global_slot_since_genesis = Int.gen_incl 0 1_000_000 in
16✔
16
    let%bind blockchain_length = Int.gen_incl 0 global_slot_since_genesis in
×
17
    let%map state_hash = Mina_base.State_hash.gen in
18
    let state_hash = Mina_base.State_hash.to_base58_check state_hash in
×
19
    { state_hash; blockchain_length; global_slot_since_genesis }
×
20
end
21

22
let yojson_strip_fields ~keep_fields = function
23
  | `Assoc l ->
20,018✔
24
      `Assoc
25
        (List.filter l ~f:(fun (fld, _) ->
20,018✔
26
             Array.mem ~equal:String.equal keep_fields fld ) )
60,063✔
27
  | json ->
×
28
      json
29

30
let yojson_rename_fields ~alternates = function
31
  | `Assoc l ->
×
32
      `Assoc
33
        (List.map l ~f:(fun (fld, json) ->
×
34
             let fld =
×
35
               Option.value ~default:fld
36
                 (Array.find_map alternates ~f:(fun (alt, orig) ->
×
37
                      if String.equal fld alt then Some orig else None ) )
×
38
             in
39
             (fld, json) ) )
×
40
  | json ->
×
41
      json
42

43
let opt_fallthrough ~default x2 =
44
  Option.value_map ~default x2 ~f:(fun x -> Some x)
×
45

46
let result_opt ~f x =
47
  match x with
5✔
48
  | Some x ->
1✔
49
      Result.map ~f:Option.some (f x)
1✔
50
  | None ->
4✔
51
      Result.return None
52

53
let dump_on_error yojson x =
54
  Result.map_error x ~f:(fun str ->
20,018✔
55
      str ^ "\n\nCould not parse JSON:\n" ^ Yojson.Safe.pretty_to_string yojson )
×
56

57
let of_yojson_generic ~fields of_yojson json =
58
  dump_on_error json @@ of_yojson
20,018✔
59
  @@ yojson_strip_fields ~keep_fields:fields json
20,018✔
60

61
let rec deferred_list_fold ~init ~f = function
62
  | [] ->
×
63
      Async.Deferred.Result.return init
64
  | h :: t ->
×
65
      let open Async.Deferred.Result.Let_syntax in
66
      let%bind init = f init h in
×
67
      deferred_list_fold ~init ~f t
×
68

69
module Json_layout = struct
70
  module Accounts = struct
71
    module Single = struct
72
      module Timed = struct
73
        type t =
×
74
          { initial_minimum_balance : Currency.Balance.t
×
75
          ; cliff_time : Mina_numbers.Global_slot_since_genesis.t
×
76
          ; cliff_amount : Currency.Amount.t
×
77
          ; vesting_period : Mina_numbers.Global_slot_span.t
×
78
          ; vesting_increment : Currency.Amount.t
×
79
          }
80
        [@@deriving yojson, fields, sexp]
81

82
        let fields = Fields.names |> Array.of_list
16✔
83

84
        let of_yojson json = of_yojson_generic ~fields of_yojson json
×
85
      end
86

87
      module Permissions = struct
88
        module Auth_required = struct
89
          type t = None | Either | Proof | Signature | Impossible
×
90
          [@@deriving sexp, bin_io_unversioned]
64✔
91

92
          let to_yojson = function
93
            | None ->
1,452✔
94
                `String "none"
95
            | Either ->
×
96
                `String "either"
97
            | Proof ->
×
98
                `String "proof"
99
            | Signature ->
7,986✔
100
                `String "signature"
101
            | Impossible ->
×
102
                `String "impossible"
103

104
          let of_yojson = function
105
            | `String s -> (
×
106
                match String.lowercase s with
107
                | "none" ->
×
108
                    Ok None
109
                | "either" ->
×
110
                    Ok Either
111
                | "proof" ->
×
112
                    Ok Proof
113
                | "signature" ->
×
114
                    Ok Signature
115
                | "impossible" ->
×
116
                    Ok Impossible
117
                | _ ->
×
118
                    Error (sprintf "Invalid Auth_required.t value: %s" s) )
×
119
            | _ ->
×
120
                Error
121
                  "Runtime_config.Json_Account.Single.Permissions.Auth_Required.t"
122

123
          let of_account_perm = function
124
            | Mina_base.Permissions.Auth_required.None ->
×
125
                None
126
            | Either ->
×
127
                Either
128
            | Proof ->
×
129
                Proof
130
            | Signature ->
×
131
                Signature
132
            | Impossible ->
×
133
                Impossible
134

135
          let to_account_perm = function
136
            | None ->
×
137
                Mina_base.Permissions.Auth_required.None
138
            | Either ->
×
139
                Either
140
            | Proof ->
×
141
                Proof
142
            | Signature ->
×
143
                Signature
144
            | Impossible ->
×
145
                Impossible
146
        end
147

148
        module Txn_version = struct
149
          type t = Mina_numbers.Txn_version.Stable.Latest.t
16✔
150
          [@@deriving bin_io_unversioned]
64✔
151

152
          include (
153
            Mina_numbers.Txn_version :
154
              module type of Mina_numbers.Txn_version with type t := t )
155
        end
156

157
        module Verification_key_perm = struct
158
          type t = { auth : Auth_required.t; txn_version : Txn_version.t }
×
159
          [@@deriving sexp, yojson, bin_io_unversioned]
64✔
160
        end
161

162
        type t =
16✔
163
          { edit_state : Auth_required.t
×
164
                [@default
165
                  Auth_required.of_account_perm
×
166
                    Mina_base.Permissions.user_default.edit_state]
167
          ; send : Auth_required.t
×
168
                [@default
169
                  Auth_required.of_account_perm
×
170
                    Mina_base.Permissions.user_default.send]
171
          ; receive : Auth_required.t
×
172
                [@default
173
                  Auth_required.of_account_perm
×
174
                    Mina_base.Permissions.user_default.receive]
175
          ; access : Auth_required.t
×
176
                [@default
177
                  Auth_required.of_account_perm
×
178
                    Mina_base.Permissions.user_default.access]
179
          ; set_delegate : Auth_required.t
×
180
                [@default
181
                  Auth_required.of_account_perm
×
182
                    Mina_base.Permissions.user_default.set_delegate]
183
          ; set_permissions : Auth_required.t
×
184
                [@default
185
                  Auth_required.of_account_perm
×
186
                    Mina_base.Permissions.user_default.set_permissions]
187
          ; set_verification_key : Verification_key_perm.t
×
188
                [@default
189
                  { auth =
190
                      Auth_required.of_account_perm
×
191
                        (fst
×
192
                           Mina_base.Permissions.user_default
193
                             .set_verification_key )
194
                  ; txn_version =
195
                      snd
×
196
                        Mina_base.Permissions.user_default.set_verification_key
197
                  }]
198
          ; set_zkapp_uri : Auth_required.t
×
199
                [@default
200
                  Auth_required.of_account_perm
×
201
                    Mina_base.Permissions.user_default.set_zkapp_uri]
202
          ; edit_action_state : Auth_required.t
×
203
                [@default
204
                  Auth_required.of_account_perm
×
205
                    Mina_base.Permissions.user_default.edit_action_state]
206
          ; set_token_symbol : Auth_required.t
×
207
                [@default
208
                  Auth_required.of_account_perm
×
209
                    Mina_base.Permissions.user_default.set_token_symbol]
210
          ; increment_nonce : Auth_required.t
×
211
                [@default
212
                  Auth_required.of_account_perm
×
213
                    Mina_base.Permissions.user_default.increment_nonce]
214
          ; set_voting_for : Auth_required.t
×
215
                [@default
216
                  Auth_required.of_account_perm
×
217
                    Mina_base.Permissions.user_default.set_voting_for]
218
          ; set_timing : Auth_required.t
×
219
                [@default
220
                  Auth_required.of_account_perm
×
221
                    Mina_base.Permissions.user_default.set_timing]
222
          }
223
        [@@deriving yojson, fields, sexp, bin_io_unversioned]
64✔
224

225
        let fields = Fields.names |> Array.of_list
16✔
226

227
        let of_yojson json = of_yojson_generic ~fields of_yojson json
×
228

229
        let to_yojson t =
230
          `Assoc
726✔
231
            [ ("edit_state", Auth_required.to_yojson t.edit_state)
726✔
232
            ; ("send", Auth_required.to_yojson t.send)
726✔
233
            ; ("receive", Auth_required.to_yojson t.receive)
726✔
234
            ; ("access", Auth_required.to_yojson t.access)
726✔
235
            ; ("set_delegate", Auth_required.to_yojson t.set_delegate)
726✔
236
            ; ("set_permissions", Auth_required.to_yojson t.set_permissions)
726✔
237
            ; ( "set_verification_key"
238
              , Verification_key_perm.to_yojson t.set_verification_key )
726✔
239
            ; ("set_zkapp_uri", Auth_required.to_yojson t.set_zkapp_uri)
726✔
240
            ; ("edit_action_state", Auth_required.to_yojson t.edit_action_state)
726✔
241
            ; ("set_token_symbol", Auth_required.to_yojson t.set_token_symbol)
726✔
242
            ; ("increment_nonce", Auth_required.to_yojson t.increment_nonce)
726✔
243
            ; ("set_voting_for", Auth_required.to_yojson t.set_voting_for)
726✔
244
            ; ("set_timing", Auth_required.to_yojson t.set_timing)
726✔
245
            ]
246

247
        let of_permissions (perm : Mina_base.Permissions.t) =
248
          { edit_state = Auth_required.of_account_perm perm.edit_action_state
×
249
          ; send = Auth_required.of_account_perm perm.send
×
250
          ; receive = Auth_required.of_account_perm perm.receive
×
251
          ; set_delegate = Auth_required.of_account_perm perm.set_delegate
×
252
          ; set_permissions = Auth_required.of_account_perm perm.set_permissions
×
253
          ; set_verification_key =
254
              (let auth, txn_version = perm.set_verification_key in
255
               { auth = Auth_required.of_account_perm auth; txn_version } )
×
256
          ; set_token_symbol =
257
              Auth_required.of_account_perm perm.set_token_symbol
×
258
          ; access = Auth_required.of_account_perm perm.access
×
259
          ; edit_action_state =
260
              Auth_required.of_account_perm perm.edit_action_state
×
261
          ; set_zkapp_uri = Auth_required.of_account_perm perm.set_zkapp_uri
×
262
          ; increment_nonce = Auth_required.of_account_perm perm.increment_nonce
×
263
          ; set_timing = Auth_required.of_account_perm perm.set_timing
×
264
          ; set_voting_for = Auth_required.of_account_perm perm.set_voting_for
×
265
          }
266
      end
267

268
      module Zkapp_account = struct
269
        module Field = struct
270
          type t = Snark_params.Tick.Field.t
16✔
271
          [@@deriving sexp, bin_io_unversioned]
64✔
272

273
          let to_yojson t = `String (Snark_params.Tick.Field.to_string t)
×
274

275
          let of_yojson = function
276
            | `String s ->
×
277
                Ok (Snark_params.Tick.Field.of_string s)
×
278
            | _ ->
×
279
                Error
280
                  "Invalid JSON in runtime config Zkapp_account.state, \
281
                   expected string"
282
        end
283

284
        module Verification_key = struct
285
          type t = Pickles.Side_loaded.Verification_key.Stable.Latest.t
16✔
286
          [@@deriving sexp, bin_io_unversioned]
64✔
287

288
          let to_yojson t =
289
            `String (Pickles.Side_loaded.Verification_key.to_base64 t)
×
290

291
          let of_yojson = function
292
            | `String s ->
×
293
                let vk_or_err =
294
                  Pickles.Side_loaded.Verification_key.of_base64 s
295
                in
296
                Result.map_error vk_or_err ~f:Error.to_string_hum
×
297
            | _ ->
×
298
                Error
299
                  "Invalid JSON in runtime config \
300
                   Zkapp_account.verification_key, expected string"
301
        end
302

303
        module Zkapp_version = struct
304
          type t = Mina_numbers.Zkapp_version.Stable.Latest.t
16✔
305
          [@@deriving bin_io_unversioned]
64✔
306

307
          include (
308
            Mina_numbers.Zkapp_version :
309
              module type of Mina_numbers.Zkapp_version with type t := t )
310
        end
311

312
        type t =
16✔
313
          { app_state : Field.t list
×
314
          ; verification_key : Verification_key.t option [@default None]
×
315
          ; zkapp_version : Zkapp_version.t
×
316
          ; action_state : Field.t list
×
317
          ; last_action_slot : int
×
318
          ; proved_state : bool
×
319
          ; zkapp_uri : string
×
320
          }
321
        [@@deriving sexp, fields, yojson, bin_io_unversioned]
64✔
322

323
        let fields = Fields.names |> Array.of_list
16✔
324

325
        let of_yojson json = of_yojson_generic ~fields of_yojson json
×
326

327
        let of_zkapp (zkapp : Mina_base.Zkapp_account.t) : t =
328
          let open Mina_base.Zkapp_account in
×
329
          { app_state = Mina_base.Zkapp_state.V.to_list zkapp.app_state
×
330
          ; verification_key =
331
              Option.map zkapp.verification_key ~f:With_hash.data
×
332
          ; zkapp_version = zkapp.zkapp_version
333
          ; action_state =
334
              Pickles_types.Vector.Vector_5.to_list zkapp.action_state
×
335
          ; last_action_slot =
336
              Unsigned.UInt32.to_int
×
337
              @@ Mina_numbers.Global_slot_since_genesis.to_uint32
×
338
                   zkapp.last_action_slot
339
          ; proved_state = zkapp.proved_state
340
          ; zkapp_uri = zkapp.zkapp_uri
341
          }
342
      end
343

344
      type t =
×
345
        { pk : string
×
346
        ; sk : string option [@default None]
40,014✔
347
        ; balance : Currency.Balance.t
×
348
        ; delegate : string option [@default None]
752✔
349
        ; timing : Timed.t option [@default None]
×
350
        ; token : string option [@default None]
726✔
351
        ; nonce : Mina_numbers.Account_nonce.t
6✔
352
              [@default Mina_numbers.Account_nonce.zero]
353
        ; receipt_chain_hash : string option [@default None]
726✔
354
        ; voting_for : string option [@default None]
726✔
355
        ; zkapp : Zkapp_account.t option [@default None]
×
356
        ; permissions : Permissions.t option [@default None]
×
357
        ; token_symbol : string option [@default None]
726✔
358
        }
359
      [@@deriving sexp, fields, yojson]
40,020✔
360

361
      let fields = Fields.names |> Array.of_list
16✔
362

363
      let of_yojson json = of_yojson_generic ~fields of_yojson json
20,014✔
364

365
      let default : t =
366
        { pk = Signature_lib.Public_key.Compressed.(to_base58_check empty)
16✔
367
        ; sk = None
368
        ; balance = Currency.Balance.zero
369
        ; delegate = None
370
        ; timing = None
371
        ; token = None
372
        ; nonce = Mina_numbers.Account_nonce.zero
373
        ; receipt_chain_hash = None
374
        ; voting_for = None
375
        ; zkapp = None
376
        ; permissions = None
377
        ; token_symbol = None
378
        }
379
    end
380

381
    type t = Single.t list [@@deriving yojson]
×
382
  end
383

384
  module Ledger = struct
385
    module Balance_spec = struct
386
      type t = { number : int; balance : Currency.Balance.t }
×
387
      [@@deriving yojson]
×
388
    end
389

390
    type t =
×
391
      { accounts : Accounts.t option [@default None]
3✔
392
      ; num_accounts : int option [@default None]
2✔
393
      ; balances : Balance_spec.t list [@default []]
×
394
      ; hash : string option [@default None]
3✔
395
      ; s3_data_hash : string option [@default None]
×
396
      ; name : string option [@default None]
×
397
      ; add_genesis_winner : bool option [@default None]
4✔
398
      }
399
    [@@deriving yojson, fields]
3✔
400

401
    let fields = Fields.names |> Array.of_list
16✔
402

403
    let of_yojson json = of_yojson_generic ~fields of_yojson json
3✔
404
  end
405

406
  module Proof_keys = struct
407
    module Transaction_capacity = struct
408
      type t =
×
409
        { log_2 : int option [@default None] [@key "2_to_the"]
×
410
        ; txns_per_second_x10 : int option [@default None]
×
411
        }
412
      [@@deriving yojson]
×
413

414
      (* we don't deriving the field names here, because the first one differs from the
415
         field in the record type
416
      *)
417
      let fields = [| "2_to_the"; "txns_per_second_x10" |]
418

419
      let alternates = [| ("two_to_the", "2_to_the"); ("log_2", "2_to_the") |]
420

421
      let of_yojson json =
422
        json
×
423
        |> yojson_rename_fields ~alternates
×
424
        |> yojson_strip_fields ~keep_fields:fields
×
425
        |> of_yojson |> dump_on_error json
×
426
    end
427

428
    type t =
×
429
      { level : string option [@default None]
×
430
      ; sub_windows_per_window : int option [@default None]
×
431
      ; ledger_depth : int option [@default None]
×
432
      ; work_delay : int option [@default None]
×
433
      ; block_window_duration_ms : int option [@default None]
×
434
      ; transaction_capacity : Transaction_capacity.t option [@default None]
×
435
      ; coinbase_amount : Currency.Amount.t option [@default None]
×
436
      ; supercharged_coinbase_factor : int option [@default None]
×
437
      ; account_creation_fee : Currency.Fee.t option [@default None]
×
438
      ; fork : Fork_config.t option [@default None]
×
439
      }
440
    [@@deriving yojson, fields]
×
441

442
    let fields = Fields.names |> Array.of_list
16✔
443

444
    let of_yojson json = of_yojson_generic ~fields of_yojson json
×
445
  end
446

447
  module Genesis = struct
448
    type t =
×
449
      { k : int option [@default None]
×
450
      ; delta : int option [@default None]
×
451
      ; slots_per_epoch : int option [@default None]
×
452
      ; slots_per_sub_window : int option [@default None]
×
453
      ; grace_period_slots : int option [@default None]
×
454
      ; genesis_state_timestamp : string option [@default None]
×
455
      }
456
    [@@deriving yojson, fields]
×
457

458
    let fields = Fields.names |> Array.of_list
16✔
459

460
    let of_yojson json = of_yojson_generic ~fields of_yojson json
×
461
  end
462

463
  module Daemon = struct
464
    type t =
×
465
      { txpool_max_size : int option [@default None]
×
466
      ; peer_list_url : string option [@default None]
×
467
      ; zkapp_proof_update_cost : float option [@default None]
×
468
      ; zkapp_signed_single_update_cost : float option [@default None]
×
469
      ; zkapp_signed_pair_update_cost : float option [@default None]
×
470
      ; zkapp_transaction_cost_limit : float option [@default None]
×
471
      ; max_event_elements : int option [@default None]
×
472
      ; max_action_elements : int option [@default None]
×
473
      ; zkapp_cmd_limit_hardcap : int option [@default None]
×
474
      ; slot_tx_end : int option [@default None]
×
475
      ; slot_chain_end : int option [@default None]
×
476
      ; minimum_user_command_fee : Currency.Fee.t option [@default None]
×
477
      ; network_id : string option [@default None]
×
478
      ; sync_ledger_max_subtree_depth : int option [@default None]
×
479
      ; sync_ledger_default_subtree_depth : int option [@default None]
×
480
      }
481
    [@@deriving yojson, fields]
×
482

483
    let fields = Fields.names |> Array.of_list
16✔
484

485
    let of_yojson json = of_yojson_generic ~fields of_yojson json
×
486
  end
487

488
  module Epoch_data = struct
489
    module Data = struct
490
      type t =
×
491
        { accounts : Accounts.t option [@default None]
×
492
        ; seed : string
×
493
        ; s3_data_hash : string option [@default None]
×
494
        ; hash : string option [@default None]
×
495
        }
496
      [@@deriving yojson, fields]
×
497

498
      let fields = Fields.names |> Array.of_list
16✔
499

500
      let of_yojson json = of_yojson_generic ~fields of_yojson json
×
501
    end
502

503
    type t =
×
504
      { staking : Data.t
×
505
      ; next : (Data.t option[@default None]) (*If None then next = staking*)
×
506
      }
507
    [@@deriving yojson, fields]
508

509
    let fields = Fields.names |> Array.of_list
16✔
510

511
    let of_yojson json = of_yojson_generic ~fields of_yojson json
×
512
  end
513

514
  type t =
×
515
    { daemon : Daemon.t option [@default None]
×
516
    ; genesis : Genesis.t option [@default None]
×
517
    ; proof : Proof_keys.t option [@default None]
×
518
    ; ledger : Ledger.t option [@default None]
1✔
519
    ; epoch_data : Epoch_data.t option [@default None]
×
520
    }
521
  [@@deriving yojson, fields]
522

523
  let fields = Fields.names |> Array.of_list
16✔
524

525
  let of_yojson json = of_yojson_generic ~fields of_yojson json
1✔
526
end
527

528
(** JSON representation:
529

530
  { "daemon":
531
      { "txpool_max_size": 1
532
      , "peer_list_url": "https://www.example.com/peer-list.txt" }
533
  , "genesis": { "k": 1, "delta": 1 }
534
  , "proof":
535
      { "level": "check"
536
      , "sub_windows_per_window": 8
537
      , "ledger_depth": 14
538
      , "work_delay": 2
539
      , "block_window_duration_ms": 120000
540
      , "transaction_capacity": {"txns_per_second_x10": 2}
541
      , "coinbase_amount": "200"
542
      , "supercharged_coinbase_factor": 2
543
      , "account_creation_fee": "0.001" }
544
  , "ledger":
545
      { "name": "release"
546
      , "accounts":
547
          [ { "pk": "public_key"
548
            , "sk": "secret_key"
549
            , "balance": "0.000600000"
550
            , "delegate": "public_key" }
551
          , { "pk": "public_key"
552
            , "sk": "secret_key"
553
            , "balance": "0.000000000"
554
            , "delegate": "public_key" } ]
555
      , "hash": "root_hash"
556
      , "num_accounts": 10
557
      , "genesis_state_timestamp": "2000-00-00 12:00:00+0100" } }
558

559
  All fields are optional *except*:
560
  * each account in [ledger.accounts] must have a [balance] field
561
  * if [ledger] is present, it must feature one of [name], [accounts] or [hash].
562

563
*)
564

565
module Accounts = struct
566
  module Single = struct
567
    module Timed = struct
568
      type t = Json_layout.Accounts.Single.Timed.t =
16✔
569
        { initial_minimum_balance : Currency.Balance.Stable.Latest.t
×
570
        ; cliff_time : Mina_numbers.Global_slot_since_genesis.Stable.Latest.t
×
571
        ; cliff_amount : Currency.Amount.Stable.Latest.t
×
572
        ; vesting_period : Mina_numbers.Global_slot_span.Stable.Latest.t
×
573
        ; vesting_increment : Currency.Amount.Stable.Latest.t
×
574
        }
575
      [@@deriving bin_io_unversioned, sexp]
64✔
576
    end
577

578
    module Permissions = Json_layout.Accounts.Single.Permissions
579
    module Zkapp_account = Json_layout.Accounts.Single.Zkapp_account
580

581
    type t = Json_layout.Accounts.Single.t =
16✔
582
      { pk : string
×
583
      ; sk : string option
×
584
      ; balance : Currency.Balance.Stable.Latest.t
×
585
      ; delegate : string option
×
586
      ; timing : Timed.t option
×
587
      ; token : string option
×
588
      ; nonce : Mina_numbers.Account_nonce.Stable.Latest.t
×
589
      ; receipt_chain_hash : string option
×
590
      ; voting_for : string option
×
591
      ; zkapp : Zkapp_account.t option
×
592
      ; permissions : Permissions.t option
×
593
      ; token_symbol : string option
×
594
      }
595
    [@@deriving bin_io_unversioned, sexp]
64✔
596

597
    let to_json_layout : t -> Json_layout.Accounts.Single.t = Fn.id
598

599
    let of_json_layout : Json_layout.Accounts.Single.t -> (t, string) Result.t =
600
      Result.return
601

602
    let to_yojson x = Json_layout.Accounts.Single.to_yojson (to_json_layout x)
×
603

604
    let of_yojson json =
605
      Result.bind ~f:of_json_layout (Json_layout.Accounts.Single.of_yojson json)
×
606

607
    let default = Json_layout.Accounts.Single.default
608

609
    let of_account (a : Mina_base.Account.t) : (t, string) Result.t =
610
      let open Result.Let_syntax in
×
611
      let open Signature_lib in
612
      return
613
        { pk = Public_key.Compressed.to_base58_check a.public_key
×
614
        ; sk = None
615
        ; balance = a.balance
616
        ; delegate =
617
            Option.map a.delegate ~f:(fun pk ->
×
618
                Public_key.Compressed.to_base58_check pk )
×
619
        ; timing =
620
            ( match a.timing with
621
            | Untimed ->
×
622
                None
623
            | Timed t ->
×
624
                let open Timed in
625
                Some
626
                  { initial_minimum_balance = t.initial_minimum_balance
627
                  ; cliff_time = t.cliff_time
628
                  ; cliff_amount = t.cliff_amount
629
                  ; vesting_period = t.vesting_period
630
                  ; vesting_increment = t.vesting_increment
631
                  } )
632
        ; token = Some (Mina_base.Token_id.to_string a.token_id)
×
633
        ; token_symbol = Some a.token_symbol
634
        ; zkapp = Option.map a.zkapp ~f:Zkapp_account.of_zkapp
×
635
        ; nonce = a.nonce
636
        ; receipt_chain_hash =
637
            Some
638
              (Mina_base.Receipt.Chain_hash.to_base58_check a.receipt_chain_hash)
×
639
        ; voting_for = Some (Mina_base.State_hash.to_base58_check a.voting_for)
×
640
        ; permissions = Some (Permissions.of_permissions a.permissions)
×
641
        }
642

643
    let to_account ?(ignore_missing_fields = false) (a : t) :
×
644
        Mina_base.Account.t =
645
      let open Signature_lib in
20,000✔
646
      let timing =
647
        let open Mina_base.Account_timing.Poly in
648
        match a.timing with
649
        | None ->
20,000✔
650
            Untimed
651
        | Some
×
652
            { initial_minimum_balance
653
            ; cliff_time
654
            ; cliff_amount
655
            ; vesting_period
656
            ; vesting_increment
657
            } ->
658
            Timed
659
              { initial_minimum_balance
660
              ; cliff_time
661
              ; cliff_amount
662
              ; vesting_period
663
              ; vesting_increment
664
              }
665
      in
666
      let to_permissions (perms : Permissions.t) =
667
        Mina_base.Permissions.Poly.
×
668
          { edit_state =
669
              Json_layout.Accounts.Single.Permissions.Auth_required
670
              .to_account_perm perms.edit_state
×
671
          ; access =
672
              Json_layout.Accounts.Single.Permissions.Auth_required
673
              .to_account_perm perms.access
×
674
          ; send =
675
              Json_layout.Accounts.Single.Permissions.Auth_required
676
              .to_account_perm perms.send
×
677
          ; receive =
678
              Json_layout.Accounts.Single.Permissions.Auth_required
679
              .to_account_perm perms.receive
×
680
          ; set_delegate =
681
              Json_layout.Accounts.Single.Permissions.Auth_required
682
              .to_account_perm perms.set_delegate
×
683
          ; set_permissions =
684
              Json_layout.Accounts.Single.Permissions.Auth_required
685
              .to_account_perm perms.set_permissions
×
686
          ; set_verification_key =
687
              ( Json_layout.Accounts.Single.Permissions.Auth_required
688
                .to_account_perm perms.set_verification_key.auth
×
689
              , perms.set_verification_key.txn_version )
690
          ; set_zkapp_uri =
691
              Json_layout.Accounts.Single.Permissions.Auth_required
692
              .to_account_perm perms.set_zkapp_uri
×
693
          ; edit_action_state =
694
              Json_layout.Accounts.Single.Permissions.Auth_required
695
              .to_account_perm perms.edit_action_state
×
696
          ; set_token_symbol =
697
              Json_layout.Accounts.Single.Permissions.Auth_required
698
              .to_account_perm perms.set_token_symbol
×
699
          ; increment_nonce =
700
              Json_layout.Accounts.Single.Permissions.Auth_required
701
              .to_account_perm perms.increment_nonce
×
702
          ; set_voting_for =
703
              Json_layout.Accounts.Single.Permissions.Auth_required
704
              .to_account_perm perms.set_voting_for
×
705
          ; set_timing =
706
              Json_layout.Accounts.Single.Permissions.Auth_required
707
              .to_account_perm perms.set_timing
×
708
          }
709
      in
710
      let permissions =
711
        match (ignore_missing_fields, a.permissions) with
712
        | _, Some perms ->
×
713
            to_permissions perms
×
714
        | false, None ->
×
715
            failwithf "no permissions set for account %s" a.pk ()
×
716
        | true, _ ->
20,000✔
717
            Mina_base.Permissions.user_default
718
      in
719
      let mk_zkapp (app : Zkapp_account.t) :
720
          ( Mina_base.Zkapp_state.Value.t
721
          , Mina_base.Verification_key_wire.t option
722
          , Zkapp_account.Zkapp_version.t
723
          , Zkapp_account.Field.t
724
          , Mina_numbers.Global_slot_since_genesis.t
725
          , bool
726
          , string )
727
          Mina_base.Zkapp_account.Poly.t =
728
        let hash_data = Mina_base.Verification_key_wire.digest_vk in
×
729
        Zkapp_account.
730
          { app_state = Mina_base.Zkapp_state.V.of_list_exn app.app_state
×
731
          ; verification_key =
732
              Option.map ~f:With_hash.(of_data ~hash_data) app.verification_key
×
733
          ; zkapp_version = app.zkapp_version
734
          ; action_state =
735
              Pickles_types.Vector.Vector_5.of_list_exn app.action_state
×
736
          ; last_action_slot =
737
              Mina_numbers.Global_slot_since_genesis.of_uint32
×
738
              @@ Unsigned.UInt32.of_int app.last_action_slot
×
739
          ; proved_state = app.proved_state
740
          ; zkapp_uri = app.zkapp_uri
741
          }
742
      in
743
      let receipt_chain_hash =
744
        match (ignore_missing_fields, a.receipt_chain_hash) with
745
        | _, Some rch ->
×
746
            Mina_base.Receipt.Chain_hash.of_base58_check_exn rch
×
747
        | false, None ->
×
748
            failwithf "no receipt_chain_hash set for account %s" a.pk ()
×
749
        | true, _ ->
20,000✔
750
            Mina_base.Receipt.Chain_hash.empty
751
      in
752
      let voting_for =
753
        match (ignore_missing_fields, a.voting_for) with
754
        | _, Some voting_for ->
×
755
            Mina_base.State_hash.of_base58_check_exn voting_for
×
756
        | false, None ->
×
757
            failwithf "no voting_for set for account %s" a.pk ()
×
758
        | true, _ ->
20,000✔
759
            Mina_base.State_hash.dummy
760
      in
761
      { public_key = Public_key.Compressed.of_base58_check_exn a.pk
20,000✔
762
      ; token_id =
763
          Mina_base.Token_id.(Option.value_map ~default ~f:of_string a.token)
20,000✔
764
      ; token_symbol = Option.value ~default:"" a.token_symbol
20,000✔
765
      ; balance = a.balance
766
      ; nonce = a.nonce
767
      ; receipt_chain_hash
768
      ; delegate =
769
          Option.map ~f:Public_key.Compressed.of_base58_check_exn a.delegate
20,000✔
770
      ; voting_for
771
      ; timing
772
      ; permissions
773
      ; zkapp = Option.map ~f:mk_zkapp a.zkapp
20,000✔
774
      }
775

776
    let gen =
777
      Quickcheck.Generator.map Mina_base.Account.gen ~f:(fun a ->
16✔
778
          (* This will never fail with a proper account generator. *)
779
          of_account a |> Result.ok_or_failwith )
×
780
  end
781

782
  type single = Single.t =
783
    { pk : string
784
    ; sk : string option
785
    ; balance : Currency.Balance.t
786
    ; delegate : string option
787
    ; timing : Single.Timed.t option
788
    ; token : string option
789
    ; nonce : Mina_numbers.Account_nonce.t
790
    ; receipt_chain_hash : string option
791
    ; voting_for : string option
792
    ; zkapp : Single.Zkapp_account.t option
793
    ; permissions : Single.Permissions.t option
794
    ; token_symbol : string option
795
    }
796

797
  type t = Single.t list [@@deriving bin_io_unversioned]
16✔
798

799
  let to_json_layout : t -> Json_layout.Accounts.t =
800
    List.map ~f:Single.to_json_layout
801

802
  let of_json_layout (t : Json_layout.Accounts.t) : (t, string) Result.t =
803
    let exception Stop of string in
3✔
804
    try
805
      Result.return
3✔
806
      @@ List.map t ~f:(fun x ->
3✔
807
             match Single.of_json_layout x with
20,014✔
808
             | Ok x ->
20,014✔
809
                 x
810
             | Error err ->
×
811
                 raise (Stop err) )
812
    with Stop err -> Error err
×
813

814
  let to_yojson x = Json_layout.Accounts.to_yojson (to_json_layout x)
4✔
815

816
  let of_yojson json =
817
    Result.bind ~f:of_json_layout (Json_layout.Accounts.of_yojson json)
×
818
end
819

820
module Ledger = struct
821
  type base =
16✔
822
    | Named of string  (** One of the named ledgers in [Genesis_ledger] *)
×
823
    | Accounts of Accounts.t  (** A ledger generated from the given accounts *)
×
824
    | Hash
×
825
        (** The ledger with the given root hash stored in the containing Ledger.t *)
826
  [@@deriving bin_io_unversioned]
64✔
827

828
  type t =
16✔
829
    { base : base
830
    ; num_accounts : int option
831
    ; balances : (int * Currency.Balance.Stable.Latest.t) list
832
    ; hash : string option
833
    ; s3_data_hash : string option
834
    ; name : string option
835
    ; add_genesis_winner : bool option
836
    }
837
  [@@deriving bin_io_unversioned]
64✔
838

839
  let to_json_layout
840
      { base
841
      ; num_accounts
842
      ; balances
843
      ; hash
844
      ; name
845
      ; add_genesis_winner
846
      ; s3_data_hash
847
      } : Json_layout.Ledger.t =
848
    let balances =
3✔
849
      List.map balances ~f:(fun (number, balance) ->
850
          { Json_layout.Ledger.Balance_spec.number; balance } )
×
851
    in
852
    let without_base : Json_layout.Ledger.t =
3✔
853
      { accounts = None
854
      ; num_accounts
855
      ; balances
856
      ; hash
857
      ; s3_data_hash
858
      ; name
859
      ; add_genesis_winner
860
      }
861
    in
862
    match base with
863
    | Named name ->
×
864
        { without_base with name = Some name }
865
    | Accounts accounts ->
3✔
866
        { without_base with accounts = Some (Accounts.to_json_layout accounts) }
3✔
867
    | Hash ->
×
868
        without_base
869

870
  let of_json_layout
871
      ({ accounts
872
       ; num_accounts
873
       ; balances
874
       ; hash
875
       ; s3_data_hash
876
       ; name
877
       ; add_genesis_winner
878
       } :
879
        Json_layout.Ledger.t ) : (t, string) Result.t =
880
    let open Result.Let_syntax in
3✔
881
    let%map base =
882
      match accounts with
883
      | Some accounts ->
3✔
884
          let%map accounts = Accounts.of_json_layout accounts in
3✔
885
          Accounts accounts
3✔
886
      | None -> (
×
887
          match name with
888
          | Some name ->
×
889
              return (Named name)
×
890
          | None -> (
×
891
              match hash with
892
              | Some _ ->
×
893
                  return Hash
×
894
              | None ->
×
895
                  Error
896
                    "Runtime_config.Ledger.of_json_layout: Expected a field \
897
                     'accounts', 'name' or 'hash'" ) )
898
    in
899
    let balances =
3✔
900
      List.map balances
901
        ~f:(fun { Json_layout.Ledger.Balance_spec.number; balance } ->
902
          (number, balance) )
×
903
    in
904
    { base
3✔
905
    ; num_accounts
906
    ; balances
907
    ; hash
908
    ; s3_data_hash
909
    ; name
910
    ; add_genesis_winner
911
    }
912

913
  let to_yojson x = Json_layout.Ledger.to_yojson (to_json_layout x)
3✔
914

915
  let of_yojson json =
916
    Result.bind ~f:of_json_layout (Json_layout.Ledger.of_yojson json)
2✔
917

918
  let gen =
919
    let open Quickcheck in
920
    let open Generator.Let_syntax in
921
    let%bind accounts = Generator.list Accounts.Single.gen in
16✔
922
    let num_accounts = List.length accounts in
×
923
    let balances =
×
924
      List.mapi accounts ~f:(fun number a -> (number, a.balance))
×
925
    in
926
    let%bind hash =
927
      Mina_base.Ledger_hash.(Generator.map ~f:to_base58_check gen)
×
928
      |> Option.quickcheck_generator
×
929
    in
930
    let%bind name = String.gen_nonempty in
931
    let%map add_genesis_winner = Bool.quickcheck_generator in
932
    { base = Accounts accounts
×
933
    ; num_accounts = Some num_accounts
934
    ; balances
935
    ; hash
936
    ; s3_data_hash = None
937
    ; name = Some name
938
    ; add_genesis_winner = Some add_genesis_winner
939
    }
940
end
941

942
module Proof_keys = struct
943
  module Level = struct
944
    type t = Full | Check | No_check [@@deriving bin_io_unversioned, equal]
×
945

946
    let to_string = function
947
      | Full ->
×
948
          "full"
949
      | Check ->
×
950
          "check"
951
      | No_check ->
×
952
          "none"
953

954
    let of_string str =
955
      match String.lowercase str with
×
956
      | "full" ->
×
957
          Ok Full
958
      | "check" ->
×
959
          Ok Check
960
      | "none" ->
×
961
          Ok No_check
962
      | _ ->
×
963
          Error "Expected one of 'full', 'check', or 'none'"
964

965
    let to_json_layout = to_string
966

967
    let of_json_layout str =
968
      Result.map_error (of_string str) ~f:(fun err ->
×
969
          "Runtime_config.Proof_keys.Level.of_json_layout: Could not decode \
×
970
           field 'level'. " ^ err )
971

972
    let to_yojson x = `String (to_json_layout x)
×
973

974
    let of_yojson = function
975
      | `String str ->
×
976
          of_json_layout str
977
      | _ ->
×
978
          Error
979
            "Runtime_config.Proof_keys.Level.of_json_layout: Expected the \
980
             field 'level' to contain a string"
981

982
    let gen = Quickcheck.Generator.of_list [ Full; Check; No_check ]
16✔
983
  end
984

985
  module Transaction_capacity = struct
986
    type t = Log_2 of int | Txns_per_second_x10 of int
×
987
    [@@deriving bin_io_unversioned]
64✔
988

989
    let to_json_layout : t -> Json_layout.Proof_keys.Transaction_capacity.t =
990
      function
991
      | Log_2 i ->
×
992
          { log_2 = Some i; txns_per_second_x10 = None }
993
      | Txns_per_second_x10 i ->
×
994
          { log_2 = None; txns_per_second_x10 = Some i }
995

996
    let of_json_layout :
997
        Json_layout.Proof_keys.Transaction_capacity.t -> (t, string) Result.t =
998
      function
999
      | { log_2 = Some i; txns_per_second_x10 = None } ->
×
1000
          Ok (Log_2 i)
1001
      | { txns_per_second_x10 = Some i; log_2 = None } ->
×
1002
          Ok (Txns_per_second_x10 i)
1003
      | _ ->
×
1004
          Error
1005
            "Runtime_config.Proof_keys.Transaction_capacity.of_json_layout: \
1006
             Expected exactly one of the fields '2_to_the' or \
1007
             'txns_per_second_x10'"
1008

1009
    let to_yojson x =
1010
      Json_layout.Proof_keys.Transaction_capacity.to_yojson (to_json_layout x)
×
1011

1012
    let of_yojson json =
1013
      Result.bind ~f:of_json_layout
×
1014
        (Json_layout.Proof_keys.Transaction_capacity.of_yojson json)
×
1015

1016
    let gen =
1017
      let open Quickcheck in
1018
      let log_2_gen =
1019
        Generator.map ~f:(fun i -> Log_2 i) @@ Int.gen_incl 0 10
×
1020
      in
1021
      let txns_per_second_x10_gen =
16✔
1022
        Generator.map ~f:(fun i -> Txns_per_second_x10 i) @@ Int.gen_incl 0 1000
×
1023
      in
1024
      Generator.union [ log_2_gen; txns_per_second_x10_gen ]
16✔
1025

1026
    let small : t = Log_2 2
1027

1028
    let medium : t = Log_2 3
1029
  end
1030

1031
  type t =
16✔
1032
    { level : Level.t option
1033
    ; sub_windows_per_window : int option
1034
    ; ledger_depth : int option
1035
    ; work_delay : int option
1036
    ; block_window_duration_ms : int option
1037
    ; transaction_capacity : Transaction_capacity.t option
1038
    ; coinbase_amount : Currency.Amount.Stable.Latest.t option
1039
    ; supercharged_coinbase_factor : int option
1040
    ; account_creation_fee : Currency.Fee.Stable.Latest.t option
1041
    ; fork : Fork_config.t option
1042
    }
1043
  [@@deriving bin_io_unversioned]
64✔
1044

1045
  let make ?level ?sub_windows_per_window ?ledger_depth ?work_delay
1046
      ?block_window_duration_ms ?transaction_capacity ?coinbase_amount
1047
      ?supercharged_coinbase_factor ?account_creation_fee ?fork () =
1048
    { level
×
1049
    ; sub_windows_per_window
1050
    ; ledger_depth
1051
    ; work_delay
1052
    ; block_window_duration_ms
1053
    ; transaction_capacity
1054
    ; coinbase_amount
1055
    ; supercharged_coinbase_factor
1056
    ; account_creation_fee
1057
    ; fork
1058
    }
1059

1060
  let to_json_layout
1061
      { level
1062
      ; sub_windows_per_window
1063
      ; ledger_depth
1064
      ; work_delay
1065
      ; block_window_duration_ms
1066
      ; transaction_capacity
1067
      ; coinbase_amount
1068
      ; supercharged_coinbase_factor
1069
      ; account_creation_fee
1070
      ; fork
1071
      } =
1072
    { Json_layout.Proof_keys.level = Option.map ~f:Level.to_json_layout level
×
1073
    ; sub_windows_per_window
1074
    ; ledger_depth
1075
    ; work_delay
1076
    ; block_window_duration_ms
1077
    ; transaction_capacity =
1078
        Option.map ~f:Transaction_capacity.to_json_layout transaction_capacity
×
1079
    ; coinbase_amount
1080
    ; supercharged_coinbase_factor
1081
    ; account_creation_fee
1082
    ; fork
1083
    }
1084

1085
  let of_json_layout
1086
      { Json_layout.Proof_keys.level
1087
      ; sub_windows_per_window
1088
      ; ledger_depth
1089
      ; work_delay
1090
      ; block_window_duration_ms
1091
      ; transaction_capacity
1092
      ; coinbase_amount
1093
      ; supercharged_coinbase_factor
1094
      ; account_creation_fee
1095
      ; fork
1096
      } =
1097
    let open Result.Let_syntax in
×
1098
    let%map level = result_opt ~f:Level.of_json_layout level
×
1099
    and transaction_capacity =
1100
      result_opt ~f:Transaction_capacity.of_json_layout transaction_capacity
×
1101
    in
1102
    { level
×
1103
    ; sub_windows_per_window
1104
    ; ledger_depth
1105
    ; work_delay
1106
    ; block_window_duration_ms
1107
    ; transaction_capacity
1108
    ; coinbase_amount
1109
    ; supercharged_coinbase_factor
1110
    ; account_creation_fee
1111
    ; fork
1112
    }
1113

1114
  let to_yojson x = Json_layout.Proof_keys.to_yojson (to_json_layout x)
×
1115

1116
  let of_yojson json =
1117
    Result.bind ~f:of_json_layout (Json_layout.Proof_keys.of_yojson json)
×
1118

1119
  let combine t1 t2 =
1120
    { level = opt_fallthrough ~default:t1.level t2.level
×
1121
    ; sub_windows_per_window =
1122
        opt_fallthrough ~default:t1.sub_windows_per_window
×
1123
          t2.sub_windows_per_window
1124
    ; ledger_depth = opt_fallthrough ~default:t1.ledger_depth t2.ledger_depth
×
1125
    ; work_delay = opt_fallthrough ~default:t1.work_delay t2.work_delay
×
1126
    ; block_window_duration_ms =
1127
        opt_fallthrough ~default:t1.block_window_duration_ms
×
1128
          t2.block_window_duration_ms
1129
    ; transaction_capacity =
1130
        opt_fallthrough ~default:t1.transaction_capacity t2.transaction_capacity
×
1131
    ; coinbase_amount =
1132
        opt_fallthrough ~default:t1.coinbase_amount t2.coinbase_amount
×
1133
    ; supercharged_coinbase_factor =
1134
        opt_fallthrough ~default:t1.supercharged_coinbase_factor
×
1135
          t2.supercharged_coinbase_factor
1136
    ; account_creation_fee =
1137
        opt_fallthrough ~default:t1.account_creation_fee t2.account_creation_fee
×
1138
    ; fork = opt_fallthrough ~default:t1.fork t2.fork
×
1139
    }
1140

1141
  let gen =
1142
    let open Quickcheck.Generator.Let_syntax in
1143
    let%bind level = Level.gen in
1144
    let%bind sub_windows_per_window = Int.gen_incl 0 1000 in
×
1145
    let%bind ledger_depth = Int.gen_incl 0 64 in
×
1146
    let%bind work_delay = Int.gen_incl 0 1000 in
×
1147
    let%bind block_window_duration_ms = Int.gen_incl 1_000 360_000 in
×
1148
    let%bind transaction_capacity = Transaction_capacity.gen in
1149
    let%bind coinbase_amount =
1150
      Currency.Amount.(gen_incl zero (of_mina_int_exn 1))
×
1151
    in
1152
    let%bind supercharged_coinbase_factor = Int.gen_incl 0 100 in
×
1153
    let%bind account_creation_fee =
1154
      Currency.Fee.(gen_incl one (of_mina_int_exn 10))
×
1155
    in
1156
    let%map fork =
1157
      let open Quickcheck.Generator in
1158
      union [ map ~f:Option.some Fork_config.gen; return None ]
×
1159
    in
1160
    { level = Some level
×
1161
    ; sub_windows_per_window = Some sub_windows_per_window
1162
    ; ledger_depth = Some ledger_depth
1163
    ; work_delay = Some work_delay
1164
    ; block_window_duration_ms = Some block_window_duration_ms
1165
    ; transaction_capacity = Some transaction_capacity
1166
    ; coinbase_amount = Some coinbase_amount
1167
    ; supercharged_coinbase_factor = Some supercharged_coinbase_factor
1168
    ; account_creation_fee = Some account_creation_fee
1169
    ; fork
1170
    }
1171
end
1172

1173
module Genesis = struct
1174
  type t = Json_layout.Genesis.t =
16✔
1175
    { k : int option (* the depth of finality constant (in slots) *)
1176
    ; delta : int option (* max permissible delay of packets (in slots) *)
1177
    ; slots_per_epoch : int option
1178
    ; slots_per_sub_window : int option
1179
    ; grace_period_slots : int option
1180
    ; genesis_state_timestamp : string option
1181
    }
1182
  [@@deriving bin_io_unversioned]
64✔
1183

1184
  let to_json_layout : t -> Json_layout.Genesis.t = Fn.id
1185

1186
  let of_json_layout : Json_layout.Genesis.t -> (t, string) Result.t =
1187
    Result.return
1188

1189
  let to_yojson x = Json_layout.Genesis.to_yojson (to_json_layout x)
×
1190

1191
  let of_yojson json =
1192
    Result.bind ~f:of_json_layout (Json_layout.Genesis.of_yojson json)
×
1193

1194
  let combine t1 t2 =
1195
    { k = opt_fallthrough ~default:t1.k t2.k
×
1196
    ; delta = opt_fallthrough ~default:t1.delta t2.delta
×
1197
    ; slots_per_epoch =
1198
        opt_fallthrough ~default:t1.slots_per_epoch t2.slots_per_epoch
×
1199
    ; slots_per_sub_window =
1200
        opt_fallthrough ~default:t1.slots_per_sub_window t2.slots_per_sub_window
×
1201
    ; grace_period_slots =
1202
        opt_fallthrough ~default:t1.grace_period_slots t2.grace_period_slots
×
1203
    ; genesis_state_timestamp =
1204
        opt_fallthrough ~default:t1.genesis_state_timestamp
×
1205
          t2.genesis_state_timestamp
1206
    }
1207

1208
  let gen =
1209
    let open Quickcheck.Generator.Let_syntax in
1210
    let%bind k = Int.gen_incl 0 1000 in
16✔
1211
    let%bind delta = Int.gen_incl 0 1000 in
×
1212
    let%bind slots_per_epoch = Int.gen_incl 1 1_000_000 in
×
1213
    let%bind slots_per_sub_window = Int.gen_incl 1 1_000 in
×
1214
    let%bind grace_period_slots =
1215
      Quickcheck.Generator.union
×
1216
        [ return None
×
1217
        ; Quickcheck.Generator.map ~f:Option.some @@ Int.gen_incl 0 1000
×
1218
        ]
1219
    in
1220
    let%map genesis_state_timestamp =
1221
      Time.(gen_incl epoch (of_string "2050-01-01 00:00:00Z"))
×
1222
      |> Quickcheck.Generator.map ~f:Time.to_string
×
1223
    in
1224
    { k = Some k
×
1225
    ; delta = Some delta
1226
    ; slots_per_epoch = Some slots_per_epoch
1227
    ; slots_per_sub_window = Some slots_per_sub_window
1228
    ; grace_period_slots
1229
    ; genesis_state_timestamp = Some genesis_state_timestamp
1230
    }
1231
end
1232

1233
module Daemon = struct
1234
  (* Peer list URL should usually be None. This option is better provided with
1235
     a command line argument. Putting it in the config makes the network explicitly
1236
     rely on a certain number of nodes, reducing decentralisation. See #14766 *)
1237
  type t = Json_layout.Daemon.t =
16✔
1238
    { txpool_max_size : int option
1239
    ; peer_list_url : string option
1240
    ; zkapp_proof_update_cost : float option [@default None]
1241
    ; zkapp_signed_single_update_cost : float option [@default None]
1242
    ; zkapp_signed_pair_update_cost : float option [@default None]
1243
    ; zkapp_transaction_cost_limit : float option [@default None]
1244
    ; max_event_elements : int option [@default None]
1245
    ; max_action_elements : int option [@default None]
1246
    ; zkapp_cmd_limit_hardcap : int option [@default None]
1247
    ; slot_tx_end : int option [@default None]
1248
    ; slot_chain_end : int option [@default None]
1249
    ; minimum_user_command_fee : Currency.Fee.Stable.Latest.t option
1250
          [@default None]
1251
    ; network_id : string option [@default None]
1252
    ; sync_ledger_max_subtree_depth : int option [@default None]
1253
    ; sync_ledger_default_subtree_depth : int option [@default None]
1254
    }
1255
  [@@deriving bin_io_unversioned]
64✔
1256

1257
  let to_json_layout : t -> Json_layout.Daemon.t = Fn.id
1258

1259
  let of_json_layout : Json_layout.Daemon.t -> (t, string) Result.t =
1260
    Result.return
1261

1262
  let to_yojson x = Json_layout.Daemon.to_yojson (to_json_layout x)
×
1263

1264
  let of_yojson json =
1265
    Result.bind ~f:of_json_layout (Json_layout.Daemon.of_yojson json)
×
1266

1267
  let combine t1 t2 =
1268
    { txpool_max_size =
×
1269
        opt_fallthrough ~default:t1.txpool_max_size t2.txpool_max_size
×
1270
    ; peer_list_url = opt_fallthrough ~default:t1.peer_list_url t2.peer_list_url
×
1271
    ; zkapp_proof_update_cost =
1272
        opt_fallthrough ~default:t1.zkapp_proof_update_cost
×
1273
          t2.zkapp_proof_update_cost
1274
    ; zkapp_signed_single_update_cost =
1275
        opt_fallthrough ~default:t1.zkapp_signed_single_update_cost
×
1276
          t2.zkapp_signed_single_update_cost
1277
    ; zkapp_signed_pair_update_cost =
1278
        opt_fallthrough ~default:t1.zkapp_signed_pair_update_cost
×
1279
          t2.zkapp_signed_pair_update_cost
1280
    ; zkapp_transaction_cost_limit =
1281
        opt_fallthrough ~default:t1.zkapp_transaction_cost_limit
×
1282
          t2.zkapp_transaction_cost_limit
1283
    ; max_event_elements =
1284
        opt_fallthrough ~default:t1.max_event_elements t2.max_event_elements
×
1285
    ; max_action_elements =
1286
        opt_fallthrough ~default:t1.max_action_elements t2.max_action_elements
×
1287
    ; zkapp_cmd_limit_hardcap =
1288
        opt_fallthrough ~default:t1.zkapp_cmd_limit_hardcap
×
1289
          t2.zkapp_cmd_limit_hardcap
1290
    ; slot_tx_end = opt_fallthrough ~default:t1.slot_tx_end t2.slot_tx_end
×
1291
    ; slot_chain_end =
1292
        opt_fallthrough ~default:t1.slot_chain_end t2.slot_chain_end
×
1293
    ; minimum_user_command_fee =
1294
        opt_fallthrough ~default:t1.minimum_user_command_fee
×
1295
          t2.minimum_user_command_fee
1296
    ; network_id = opt_fallthrough ~default:t1.network_id t2.network_id
×
1297
    ; sync_ledger_max_subtree_depth =
1298
        opt_fallthrough ~default:t1.sync_ledger_max_subtree_depth
×
1299
          t2.sync_ledger_max_subtree_depth
1300
    ; sync_ledger_default_subtree_depth =
1301
        opt_fallthrough ~default:t1.sync_ledger_default_subtree_depth
×
1302
          t2.sync_ledger_default_subtree_depth
1303
    }
1304

1305
  let gen =
1306
    let open Quickcheck.Generator.Let_syntax in
1307
    let%bind txpool_max_size = Int.gen_incl 0 1000 in
16✔
1308
    let%bind zkapp_proof_update_cost = Float.gen_incl 0.0 100.0 in
×
1309
    let%bind zkapp_signed_single_update_cost = Float.gen_incl 0.0 100.0 in
×
1310
    let%bind zkapp_signed_pair_update_cost = Float.gen_incl 0.0 100.0 in
×
1311
    let%bind zkapp_transaction_cost_limit = Float.gen_incl 0.0 100.0 in
×
1312
    let%bind max_event_elements = Int.gen_incl 0 100 in
×
1313
    let%bind zkapp_cmd_limit_hardcap = Int.gen_incl 0 1000 in
×
1314
    let%bind minimum_user_command_fee =
1315
      Currency.Fee.(gen_incl one (of_mina_int_exn 10))
×
1316
    in
1317
    let%map max_action_elements = Int.gen_incl 0 1000 in
×
1318
    { txpool_max_size = Some txpool_max_size
×
1319
    ; peer_list_url = None
1320
    ; zkapp_proof_update_cost = Some zkapp_proof_update_cost
1321
    ; zkapp_signed_single_update_cost = Some zkapp_signed_single_update_cost
1322
    ; zkapp_signed_pair_update_cost = Some zkapp_signed_pair_update_cost
1323
    ; zkapp_transaction_cost_limit = Some zkapp_transaction_cost_limit
1324
    ; max_event_elements = Some max_event_elements
1325
    ; max_action_elements = Some max_action_elements
1326
    ; zkapp_cmd_limit_hardcap = Some zkapp_cmd_limit_hardcap
1327
    ; slot_tx_end = None
1328
    ; slot_chain_end = None
1329
    ; minimum_user_command_fee = Some minimum_user_command_fee
1330
    ; network_id = None
1331
    ; sync_ledger_max_subtree_depth = None
1332
    ; sync_ledger_default_subtree_depth = None
1333
    }
1334
end
1335

1336
module Epoch_data = struct
1337
  module Data = struct
1338
    type t = { ledger : Ledger.t; seed : string }
×
1339
    [@@deriving bin_io_unversioned, yojson]
64✔
1340

1341
    let gen =
1342
      let open Quickcheck.Generator.Let_syntax in
1343
      let%bind ledger = Ledger.gen in
1344
      let%map seed = String.gen_nonempty in
1345
      { ledger; seed }
×
1346
  end
1347

1348
  type t =
16✔
1349
    { staking : Data.t; next : Data.t option (*If None, then next = staking*) }
×
1350
  [@@deriving bin_io_unversioned, yojson]
64✔
1351

1352
  let to_json_layout : t -> Json_layout.Epoch_data.t =
1353
   fun { staking; next } ->
1354
    let accounts (ledger : Ledger.t) =
×
1355
      match ledger.base with Accounts acc -> Some acc | _ -> None
×
1356
    in
1357
    let staking =
1358
      { Json_layout.Epoch_data.Data.accounts = accounts staking.ledger
×
1359
      ; seed = staking.seed
1360
      ; hash = staking.ledger.hash
1361
      ; s3_data_hash = staking.ledger.s3_data_hash
1362
      }
1363
    in
1364
    let next =
1365
      Option.map next ~f:(fun n ->
1366
          { Json_layout.Epoch_data.Data.accounts = accounts n.ledger
×
1367
          ; seed = n.seed
1368
          ; hash = n.ledger.hash
1369
          ; s3_data_hash = n.ledger.s3_data_hash
1370
          } )
1371
    in
1372
    { Json_layout.Epoch_data.staking; next }
×
1373

1374
  let of_json_layout : Json_layout.Epoch_data.t -> (t, string) Result.t =
1375
   fun { staking; next } ->
1376
    let open Result.Let_syntax in
×
1377
    let data (t : [ `Staking | `Next ])
1378
        { Json_layout.Epoch_data.Data.accounts; seed; hash; s3_data_hash } =
1379
      let%map base =
1380
        match accounts with
1381
        | Some accounts ->
×
1382
            return @@ Ledger.Accounts accounts
×
1383
        | None -> (
×
1384
            match hash with
1385
            | Some _ ->
×
1386
                return @@ Ledger.Hash
×
1387
            | None ->
×
1388
                let ledger_name =
1389
                  match t with `Staking -> "staking" | `Next -> "next"
×
1390
                in
1391
                Error
1392
                  (sprintf
×
1393
                     "Runtime_config.Epoch_data.of_json_layout: Expected a \
1394
                      field 'accounts', or 'hash' in '%s' ledger"
1395
                     ledger_name ) )
1396
      in
1397
      let ledger =
×
1398
        { Ledger.base
1399
        ; num_accounts = None
1400
        ; balances = []
1401
        ; hash
1402
        ; s3_data_hash
1403
        ; name = None
1404
        ; add_genesis_winner = Some false
1405
        }
1406
      in
1407
      { Data.ledger; seed }
1408
    in
1409
    let%bind staking = data `Staking staking in
×
1410
    let%map next =
1411
      Option.value_map next ~default:(Ok None) ~f:(fun next ->
×
1412
          Result.map ~f:Option.some @@ data `Next next )
×
1413
    in
1414
    { staking; next }
×
1415

1416
  let to_yojson x = Json_layout.Epoch_data.to_yojson (to_json_layout x)
×
1417

1418
  let of_yojson json =
1419
    Result.bind ~f:of_json_layout (Json_layout.Epoch_data.of_yojson json)
×
1420

1421
  let gen =
1422
    let open Quickcheck.Generator.Let_syntax in
1423
    let%bind staking = Data.gen in
1424
    let%map next = Option.quickcheck_generator Data.gen in
×
1425
    { staking; next }
×
1426
end
1427

1428
type t =
16✔
1429
  { daemon : Daemon.t option
1430
  ; genesis : Genesis.t option
1431
  ; proof : Proof_keys.t option
1432
  ; ledger : Ledger.t option
1433
  ; epoch_data : Epoch_data.t option
1434
  }
1435
[@@deriving bin_io_unversioned]
64✔
1436

1437
let make ?daemon ?genesis ?proof ?ledger ?epoch_data () =
1438
  { daemon; genesis; proof; ledger; epoch_data }
×
1439

1440
let to_json_layout { daemon; genesis; proof; ledger; epoch_data } =
1441
  { Json_layout.daemon = Option.map ~f:Daemon.to_json_layout daemon
×
1442
  ; genesis = Option.map ~f:Genesis.to_json_layout genesis
×
1443
  ; proof = Option.map ~f:Proof_keys.to_json_layout proof
×
1444
  ; ledger = Option.map ~f:Ledger.to_json_layout ledger
×
1445
  ; epoch_data = Option.map ~f:Epoch_data.to_json_layout epoch_data
×
1446
  }
1447

1448
let of_json_layout { Json_layout.daemon; genesis; proof; ledger; epoch_data } =
1449
  let open Result.Let_syntax in
1✔
1450
  let%map daemon = result_opt ~f:Daemon.of_json_layout daemon
1✔
1451
  and genesis = result_opt ~f:Genesis.of_json_layout genesis
1✔
1452
  and proof = result_opt ~f:Proof_keys.of_json_layout proof
1✔
1453
  and ledger = result_opt ~f:Ledger.of_json_layout ledger
1✔
1454
  and epoch_data = result_opt ~f:Epoch_data.of_json_layout epoch_data in
1✔
1455
  { daemon; genesis; proof; ledger; epoch_data }
1✔
1456

1457
let to_yojson x = Json_layout.to_yojson (to_json_layout x)
×
1458

1459
let to_yojson_without_accounts x =
1460
  let layout = to_json_layout x in
×
1461
  let genesis_accounts =
×
1462
    let%bind.Option { accounts; _ } = layout.ledger in
1463
    Option.map ~f:List.length accounts
×
1464
  in
1465
  let staking_accounts =
×
1466
    let%bind.Option { staking; _ } = layout.epoch_data in
1467
    Option.map ~f:List.length staking.accounts
×
1468
  in
1469
  let next_accounts =
×
1470
    let%bind.Option { next; _ } = layout.epoch_data in
1471
    let%bind.Option { accounts; _ } = next in
1472
    Option.map ~f:List.length accounts
×
1473
  in
1474
  let layout =
×
1475
    let f ledger = { ledger with Json_layout.Ledger.accounts = None } in
×
1476
    { layout with
1477
      ledger = Option.map ~f layout.ledger
×
1478
    ; epoch_data =
1479
        Option.map layout.epoch_data ~f:(fun { staking; next } ->
×
1480
            { Json_layout.Epoch_data.staking = { staking with accounts = None }
×
1481
            ; next = Option.map next ~f:(fun n -> { n with accounts = None })
×
1482
            } )
1483
    }
1484
  in
1485
  ( Json_layout.to_yojson layout
×
1486
  , `Accounts_omitted
1487
      (`Genesis genesis_accounts, `Staking staking_accounts, `Next next_accounts)
1488
  )
1489

1490
let of_yojson json = Result.bind ~f:of_json_layout (Json_layout.of_yojson json)
1✔
1491

1492
let default =
1493
  { daemon = None
1494
  ; genesis = None
1495
  ; proof = None
1496
  ; ledger = None
1497
  ; epoch_data = None
1498
  }
1499

1500
let combine t1 t2 =
1501
  let merge ~combine t1 t2 =
×
1502
    match (t1, t2) with
×
1503
    | Some t1, Some t2 ->
×
1504
        Some (combine t1 t2)
×
1505
    | Some t, None | None, Some t ->
×
1506
        Some t
1507
    | None, None ->
×
1508
        None
1509
  in
1510
  { daemon = merge ~combine:Daemon.combine t1.daemon t2.daemon
×
1511
  ; genesis = merge ~combine:Genesis.combine t1.genesis t2.genesis
×
1512
  ; proof = merge ~combine:Proof_keys.combine t1.proof t2.proof
×
1513
  ; ledger = opt_fallthrough ~default:t1.ledger t2.ledger
×
1514
  ; epoch_data = opt_fallthrough ~default:t1.epoch_data t2.epoch_data
×
1515
  }
1516

1517
let gen =
1518
  let open Quickcheck.Generator.Let_syntax in
1519
  let%map daemon = Daemon.gen
1520
  and genesis = Genesis.gen
1521
  and proof = Proof_keys.gen
1522
  and ledger = Ledger.gen
1523
  and epoch_data = Epoch_data.gen in
1524
  { daemon = Some daemon
×
1525
  ; genesis = Some genesis
1526
  ; proof = Some proof
1527
  ; ledger = Some ledger
1528
  ; epoch_data = Some epoch_data
1529
  }
1530

1531
let ledger_accounts (ledger : Mina_ledger.Ledger.Any_ledger.witness) =
1532
  let open Async.Deferred.Result.Let_syntax in
×
1533
  let yield = Async_unix.Scheduler.yield_every ~n:100 |> Staged.unstage in
1534
  let%bind accounts =
1535
    Mina_ledger.Ledger.Any_ledger.M.to_list ledger
×
1536
    |> Async.Deferred.map ~f:Result.return
×
1537
  in
1538
  let%map accounts =
1539
    deferred_list_fold ~init:[]
×
1540
      ~f:(fun acc el ->
1541
        let open Async.Deferred.Infix in
×
1542
        let%bind () = yield () >>| Result.return in
×
1543
        let%map elt = Accounts.Single.of_account el |> Async.Deferred.return in
×
1544
        elt :: acc )
×
1545
      accounts
1546
  in
1547
  List.rev accounts
×
1548

1549
let ledger_of_accounts accounts =
1550
  Ledger.
×
1551
    { base = Accounts accounts
1552
    ; num_accounts = None
1553
    ; balances = []
1554
    ; hash = None
1555
    ; s3_data_hash = None
1556
    ; name = None
1557
    ; add_genesis_winner = Some false
1558
    }
1559

1560
let make_fork_config ~staged_ledger ~global_slot_since_genesis ~state_hash
1561
    ~blockchain_length ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger
1562
    ~next_epoch_seed =
1563
  let open Async.Deferred.Result.Let_syntax in
×
1564
  let global_slot_since_genesis =
1565
    Mina_numbers.Global_slot_since_genesis.to_int global_slot_since_genesis
1566
  in
1567
  let blockchain_length = Unsigned.UInt32.to_int blockchain_length in
×
1568
  let yield () =
×
1569
    let open Async.Deferred.Infix in
×
1570
    Async_unix.Scheduler.yield () >>| Result.return
×
1571
  in
1572
  let%bind () = yield () in
×
1573
  let%bind accounts =
1574
    Mina_ledger.Ledger.Any_ledger.cast (module Mina_ledger.Ledger) staged_ledger
×
1575
    |> ledger_accounts
×
1576
  in
1577
  let hash =
×
1578
    Option.some @@ Mina_base.Ledger_hash.to_base58_check
×
1579
    @@ Mina_ledger.Ledger.merkle_root staged_ledger
×
1580
  in
1581
  let fork =
×
1582
    Fork_config.
1583
      { state_hash = Mina_base.State_hash.to_base58_check state_hash
×
1584
      ; blockchain_length
1585
      ; global_slot_since_genesis
1586
      }
1587
  in
1588
  let%bind () = yield () in
×
1589
  let%bind staking_ledger_accounts = ledger_accounts staking_ledger in
×
1590
  let%bind () = yield () in
×
1591
  let%map next_epoch_ledger_accounts =
1592
    match next_epoch_ledger with
1593
    | None ->
×
1594
        return None
×
1595
    | Some l ->
×
1596
        ledger_accounts l >>| Option.return
×
1597
  in
1598
  let epoch_data =
×
1599
    let open Epoch_data in
1600
    let open Data in
1601
    { staking =
1602
        { ledger = ledger_of_accounts staking_ledger_accounts
×
1603
        ; seed = staking_epoch_seed
1604
        }
1605
    ; next =
1606
        Option.map next_epoch_ledger_accounts ~f:(fun accounts ->
×
1607
            { ledger = ledger_of_accounts accounts; seed = next_epoch_seed } )
×
1608
    }
1609
  in
1610
  make
1611
  (* add_genesis_winner must be set to false, because this
1612
     config effectively creates a continuation of the current
1613
     blockchain state and therefore the genesis ledger already
1614
     contains the winner of the previous block. No need to
1615
     artificially add it. In fact, it wouldn't work at all,
1616
     because the new node would try to create this account at
1617
     startup, even though it already exists, leading to an error.*)
1618
    ~epoch_data
1619
    ~ledger:
1620
      { base = Accounts accounts
1621
      ; num_accounts = None
1622
      ; balances = []
1623
      ; hash
1624
      ; s3_data_hash = None
1625
      ; name = None
1626
      ; add_genesis_winner = Some false
1627
      }
1628
    ~proof:(Proof_keys.make ~fork ()) ()
×
1629

1630
let slot_tx_end, slot_chain_end =
1631
  let f get_runtime t =
1632
    let open Option.Let_syntax in
×
1633
    t.daemon >>= get_runtime >>| Mina_numbers.Global_slot_since_hard_fork.of_int
×
1634
  in
1635
  (f (fun d -> d.slot_tx_end), f (fun d -> d.slot_chain_end))
×
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