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

MinaProtocol / mina / 800

14 Nov 2025 06:30PM UTC coverage: 32.226% (-4.5%) from 36.753%
800

push

buildkite

web-flow
Merge pull request #18097 from MinaProtocol/georgeee/expose-funs-verifier-frontier

Expose some functions from verifier and frontier

4 of 36 new or added lines in 3 files covered. (11.11%)

3324 existing lines in 134 files now uncovered.

23622 of 73301 relevant lines covered (32.23%)

23472.65 hits per line

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

3.5
/src/lib/transition_frontier/persistent_root/persistent_root.ml
1
open Core
151✔
2
open Mina_base
3
module Ledger = Mina_ledger.Ledger
4
open Frontier_base
5
module Ledger_transfer_any =
6
  Mina_ledger.Ledger_transfer.Make (Ledger.Any_ledger.M) (Ledger.Any_ledger.M)
7
module Root_ledger = Mina_ledger.Root
8

9
let genesis_root_identifier ~genesis_state_hash =
UNCOV
10
  let open Root_identifier.Stable.Latest in
×
11
  { state_hash = genesis_state_hash }
12

13
let with_file ?size filename access_level ~f =
UNCOV
14
  let open Unix in
×
15
  let shared, mode =
16
    match access_level with
UNCOV
17
    | `Read ->
×
18
        (false, [ O_RDONLY ])
UNCOV
19
    | `Write ->
×
20
        (true, [ O_RDWR; O_TRUNC; O_CREAT ])
21
  in
22
  let fd = Unix.openfile filename ~mode in
UNCOV
23
  let buf_size =
×
24
    match size with
UNCOV
25
    | None ->
×
UNCOV
26
        Int64.to_int_exn Unix.(fstat fd).st_size
×
UNCOV
27
    | Some sz ->
×
28
        sz
29
  in
30
  (* Bigstring.map_file has been removed. We copy its old implementation. *)
31
  let buf =
32
    Bigarray.(
UNCOV
33
      array1_of_genarray
×
UNCOV
34
        (Core.Unix.map_file fd char c_layout ~shared [| buf_size |]))
×
35
  in
36
  let x = f buf in
UNCOV
37
  Bigstring.unsafe_destroy buf ;
×
UNCOV
38
  Unix.close fd ;
×
UNCOV
39
  x
×
40

41
(* TODO: create a reusable singleton factory abstraction *)
42
module rec Instance_type : sig
43
  type t =
44
    { snarked_ledger : Root_ledger.t
45
    ; potential_snarked_ledgers : Root_ledger.Config.t Queue.t
46
    ; factory : Factory_type.t
47
    }
48
end =
49
  Instance_type
50

51
and Factory_type : sig
52
  type t =
53
    { directory : string
54
    ; logger : Logger.t
55
    ; mutable instance : Instance_type.t option
56
    ; ledger_depth : int
57
    ; backing_type : Root_ledger.Config.backing_type
58
    }
59
end =
60
  Factory_type
61

62
open Instance_type
63
open Factory_type
64

65
module Instance = struct
66
  type t = Instance_type.t
67

68
  module Config = struct
69
    (** Helper to create a filesystem location (for a file or directory) inside
70
        the [Factory_type.t] directory. *)
UNCOV
71
    let make_instance_location filename t = Filename.concat t.directory filename
×
72

73
    (** Helper to create a [Root_ledger.Config.t] for a snarked ledger based on a
74
        subdirectory of the [Factory_type.t] directory *)
75
    let make_instance_config subdirectory t =
UNCOV
76
      Root_ledger.Config.with_directory ~backing_type:t.backing_type
×
UNCOV
77
        ~directory_name:(make_instance_location subdirectory t)
×
78

79
    (** The config for the actual snarked ledger that is initialized and used by
80
        the daemon *)
81
    let snarked_ledger = make_instance_config "snarked_ledger"
151✔
82

83
    (** The config for the temporary snarked ledger, used while recovering a
84
        vaild potential snarked ledger during startup *)
85
    let tmp_snarked_ledger = make_instance_config "tmp_snarked_ledger"
151✔
86

87
    (** The name of a json file that lists the directory names of the potential
88
        snarked ledgers in the [potential_snarked_ledgers] queue *)
89
    let potential_snarked_ledgers =
90
      make_instance_location "potential_snarked_ledgers.json"
151✔
91

92
    (** A method that generates fresh potential snarked ledger configs, each
93
        using a distinct root subdirectory *)
94
    let make_potential_snarked_ledger t =
95
      let uuid = Uuid_unix.create () in
×
96
      make_instance_config ("snarked_ledger" ^ Uuid.to_string_hum uuid) t
×
97

98
    (** The name of the file recording the [Root_identifier.t] of the snarked
99
        root *)
100
    let root_identifier = make_instance_location "root"
151✔
101
  end
102

103
  (* There is a breaking change in the (Yojson) schema for the Mesa HF ledger
104
     config type -- previously a list of directories (ie strings), it became
105
     a list of objects. This loader is compatible with both for the awkward
106
     period when we don't everyone is running a post-Mesa build.
107
  *)
108
  let potential_snarked_ledgers_to_yojson queue =
109
    `List
×
110
      (List.map (Queue.to_list queue) ~f:(fun cfg ->
×
111
           `String (Root_ledger.Config.primary_directory cfg) ) )
×
112

113
  (* See comment for potential_snarked_ledgers_to_yojson above *)
114
  let potential_snarked_ledgers_of_yojson json =
115
    Yojson.Safe.Util.to_list json
×
116
    |> List.map ~f:(fun json ->
117
           match json with
×
118
           | `String directory_name ->
×
119
               Root_ledger.Config.with_directory
120
                 ~backing_type:Root_ledger.Config.Stable_db ~directory_name
121
           | _ ->
×
122
               Root_ledger.Config.of_yojson json |> Result.ok_or_failwith )
×
123

124
  let load_potential_snarked_ledgers_from_disk factory =
UNCOV
125
    let location = Config.potential_snarked_ledgers factory in
×
UNCOV
126
    if phys_equal (Sys.file_exists location) `Yes then
×
127
      Yojson.Safe.from_file location |> potential_snarked_ledgers_of_yojson
×
UNCOV
128
    else []
×
129

130
  let write_potential_snarked_ledgers_to_disk t =
131
    Yojson.Safe.to_file
×
132
      (Config.potential_snarked_ledgers t.factory)
×
133
      (potential_snarked_ledgers_to_yojson t.potential_snarked_ledgers)
×
134

135
  let enqueue_snarked_ledger ~config t =
136
    Queue.enqueue t.potential_snarked_ledgers config ;
×
137
    write_potential_snarked_ledgers_to_disk t
×
138

139
  let dequeue_snarked_ledger t =
140
    let config = Queue.dequeue_exn t.potential_snarked_ledgers in
×
141
    Root_ledger.Config.delete_any_backing config ;
×
142
    write_potential_snarked_ledgers_to_disk t
×
143

144
  let destroy t =
145
    List.iter
×
146
      (Queue.to_list t.potential_snarked_ledgers)
×
147
      ~f:Root_ledger.Config.delete_any_backing ;
148
    Mina_stdlib_unix.File_system.rmrf
×
149
      (Config.potential_snarked_ledgers t.factory) ;
×
150
    Root_ledger.close t.snarked_ledger ;
×
151
    t.factory.instance <- None
×
152

153
  let close t =
UNCOV
154
    Root_ledger.close t.snarked_ledger ;
×
UNCOV
155
    t.factory.instance <- None
×
156

157
  let create ~logger factory =
UNCOV
158
    let snarked_ledger =
×
159
      Root_ledger.create ~logger ~depth:factory.ledger_depth
UNCOV
160
        ~config:(Config.snarked_ledger factory)
×
161
        ()
162
    in
UNCOV
163
    { snarked_ledger; potential_snarked_ledgers = Queue.create (); factory }
×
164

165
  (** When we load from disk,
166
      1. Check the potential_snarked_ledgers to see if any one of these
167
         matches the snarked_ledger_hash in persistent_frontier;
168
      2. if none of those works, we load the old snarked_ledger and check if
169
         the old snarked_ledger matches with persistent_frontier;
170
      3. if not, we just reset all the persisted data and start from genesis
171
   *)
172
  let load_from_disk factory ~snarked_ledger_hash ~logger =
UNCOV
173
    let potential_snarked_ledgers =
×
174
      load_potential_snarked_ledgers_from_disk factory
175
    in
UNCOV
176
    let snarked_ledger =
×
177
      List.fold_until potential_snarked_ledgers ~init:None
178
        ~f:(fun _ config ->
179
          let potential_snarked_ledger =
×
180
            Root_ledger.create ~logger ~depth:factory.ledger_depth ~config ()
181
          in
182
          let potential_snarked_ledger_hash =
×
183
            Frozen_ledger_hash.of_ledger_hash
184
            @@ Root_ledger.merkle_root potential_snarked_ledger
×
185
          in
186
          [%log debug]
×
187
            ~metadata:
188
              [ ( "potential_snarked_ledger_hash"
189
                , Frozen_ledger_hash.to_yojson potential_snarked_ledger_hash )
×
190
              ]
191
            "loaded potential_snarked_ledger from disk" ;
192
          if
×
193
            Frozen_ledger_hash.equal potential_snarked_ledger_hash
194
              snarked_ledger_hash
195
          then (
×
196
            let snarked_ledger =
197
              Root_ledger.create ~logger ~depth:factory.ledger_depth
198
                ~config:(Config.tmp_snarked_ledger factory)
×
199
                ()
200
            in
201
            match
×
202
              Ledger_transfer_any.transfer_accounts
203
                ~src:(Root_ledger.as_unmasked potential_snarked_ledger)
×
204
                ~dest:(Root_ledger.as_unmasked snarked_ledger)
×
205
            with
206
            | Ok _ ->
×
207
                Root_ledger.close potential_snarked_ledger ;
208
                Root_ledger.Config.delete_any_backing
×
209
                @@ Config.snarked_ledger factory ;
×
210
                Root_ledger.Config.move_backing_exn
×
211
                  ~src:(Config.tmp_snarked_ledger factory)
×
212
                  ~dst:(Config.snarked_ledger factory) ;
×
213
                List.iter potential_snarked_ledgers
214
                  ~f:Root_ledger.Config.delete_any_backing ;
215
                Mina_stdlib_unix.File_system.rmrf
×
216
                  (Config.potential_snarked_ledgers factory) ;
×
217
                Stop (Some snarked_ledger)
×
218
            | Error e ->
×
219
                Root_ledger.close potential_snarked_ledger ;
220
                List.iter potential_snarked_ledgers
×
221
                  ~f:Root_ledger.Config.delete_any_backing ;
222
                Mina_stdlib_unix.File_system.rmrf
×
223
                  (Config.potential_snarked_ledgers factory) ;
×
224
                [%log' error factory.logger]
×
225
                  ~metadata:[ ("error", `String (Error.to_string_hum e)) ]
×
226
                  "Ledger_transfer failed" ;
227
                Stop None )
×
228
          else (
×
229
            Root_ledger.close potential_snarked_ledger ;
230
            Continue None ) )
×
231
        ~finish:(fun _ ->
UNCOV
232
          List.iter potential_snarked_ledgers
×
233
            ~f:Root_ledger.Config.delete_any_backing ;
UNCOV
234
          Mina_stdlib_unix.File_system.rmrf
×
UNCOV
235
            (Config.potential_snarked_ledgers factory) ;
×
UNCOV
236
          None )
×
237
    in
UNCOV
238
    match snarked_ledger with
×
UNCOV
239
    | None ->
×
240
        let snarked_ledger =
241
          Root_ledger.create ~logger ~depth:factory.ledger_depth
UNCOV
242
            ~config:(Config.snarked_ledger factory)
×
243
            ()
244
        in
UNCOV
245
        let potential_snarked_ledger_hash =
×
246
          Frozen_ledger_hash.of_ledger_hash
UNCOV
247
          @@ Root_ledger.merkle_root snarked_ledger
×
248
        in
UNCOV
249
        if
×
250
          Frozen_ledger_hash.equal potential_snarked_ledger_hash
251
            snarked_ledger_hash
252
        then
UNCOV
253
          Ok
×
254
            { snarked_ledger
UNCOV
255
            ; potential_snarked_ledgers = Queue.create ()
×
256
            ; factory
257
            }
258
        else (
×
259
          Root_ledger.close snarked_ledger ;
260
          Error `Snarked_ledger_mismatch )
×
261
    | Some snarked_ledger ->
×
262
        Ok
263
          { snarked_ledger
264
          ; potential_snarked_ledgers = Queue.create ()
×
265
          ; factory
266
          }
267

UNCOV
268
  let snarked_ledger { snarked_ledger; _ } = snarked_ledger
×
269

270
  let set_root_identifier t new_root_identifier =
UNCOV
271
    [%log' trace t.factory.logger]
×
272
      ~metadata:
UNCOV
273
        [ ("root_identifier", Root_identifier.to_yojson new_root_identifier) ]
×
274
      "Setting persistent root identifier" ;
UNCOV
275
    let size = Root_identifier.Stable.Latest.bin_size_t new_root_identifier in
×
UNCOV
276
    with_file (Config.root_identifier t.factory) `Write ~size ~f:(fun buf ->
×
UNCOV
277
        ignore
×
UNCOV
278
          ( Root_identifier.Stable.Latest.bin_write_t buf ~pos:0
×
279
              new_root_identifier
280
            : int ) )
281

282
  (* defaults to genesis *)
283
  let load_root_identifier t =
UNCOV
284
    let file = Config.root_identifier t.factory in
×
UNCOV
285
    match Unix.access file [ `Exists; `Read ] with
×
286
    | Error _ ->
×
287
        None
UNCOV
288
    | Ok () ->
×
289
        with_file file `Read ~f:(fun buf ->
UNCOV
290
            let root_identifier =
×
291
              Root_identifier.Stable.Latest.bin_read_t buf ~pos_ref:(ref 0)
292
            in
UNCOV
293
            [%log' trace t.factory.logger]
×
294
              ~metadata:
UNCOV
295
                [ ("root_identifier", Root_identifier.to_yojson root_identifier)
×
296
                ]
297
              "Loaded persistent root identifier" ;
UNCOV
298
            Some root_identifier )
×
299

300
  let set_root_state_hash t state_hash = set_root_identifier t { state_hash }
×
301
end
302

303
type t = Factory_type.t
304

305
let create ~logger ~directory ~backing_type ~ledger_depth =
UNCOV
306
  { directory; logger; instance = None; ledger_depth; backing_type }
×
307

308
let create_instance_exn t =
UNCOV
309
  assert (Option.is_none t.instance) ;
×
310
  let instance = Instance.create ~logger:t.logger t in
UNCOV
311
  t.instance <- Some instance ;
×
312
  instance
313

314
let load_from_disk_exn t ~snarked_ledger_hash ~logger =
UNCOV
315
  let open Result.Let_syntax in
×
UNCOV
316
  assert (Option.is_none t.instance) ;
×
UNCOV
317
  let%map instance = Instance.load_from_disk t ~snarked_ledger_hash ~logger in
×
UNCOV
318
  t.instance <- Some instance ;
×
319
  instance
320

321
let with_instance_exn t ~f =
UNCOV
322
  let instance = create_instance_exn t in
×
UNCOV
323
  let x = f instance in
×
UNCOV
324
  Instance.close instance ; x
×
325

326
(** Clear the factory directory and recreate the snarked ledger instance for
327
    this factory with [create_root] and [setup] *)
328
let reset_factory_root_exn t ~create_root ~setup =
UNCOV
329
  let open Async.Deferred.Let_syntax in
×
UNCOV
330
  assert (Option.is_none t.instance) ;
×
331
  (* Certain database initialization methods, e.g. creation from a checkpoint,
332
     depend on the parent directory existing and the target directory _not_
333
     existing. *)
UNCOV
334
  let%bind () = Mina_stdlib_unix.File_system.remove_dir t.directory in
×
UNCOV
335
  let%map () = Mina_stdlib_unix.File_system.create_dir t.directory in
×
UNCOV
336
  let root =
×
UNCOV
337
    create_root
×
UNCOV
338
      ~config:(Instance.Config.snarked_ledger t)
×
339
      ~depth:t.ledger_depth ()
340
    |> Or_error.ok_exn
341
  in
UNCOV
342
  Root_ledger.close root ;
×
UNCOV
343
  with_instance_exn t ~f:setup
×
344

345
let reset_to_genesis_exn t ~precomputed_values =
UNCOV
346
  let open Async.Deferred.Let_syntax in
×
347
  let logger = t.logger in
UNCOV
348
  [%log debug] "Resetting snarked_root in $directory to genesis"
×
349
    ~metadata:[ ("directory", `String t.directory) ] ;
350
  let%map () =
UNCOV
351
    reset_factory_root_exn t
×
UNCOV
352
      ~create_root:(Precomputed_values.create_root precomputed_values)
×
353
      ~setup:(fun instance ->
UNCOV
354
        Instance.set_root_identifier instance
×
355
          (genesis_root_identifier
356
             ~genesis_state_hash:
UNCOV
357
               (Precomputed_values.genesis_state_hashes precomputed_values)
×
358
                 .state_hash ) )
359
  in
UNCOV
360
  [%log debug] "Finished resetting snarked_root to genesis"
×
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