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

MinaProtocol / mina / 77

13 Apr 2025 07:49AM UTC coverage: 35.871% (-24.9%) from 60.793%
77

push

buildkite

web-flow
Merge pull request #16866 from MinaProtocol/georgeee/use-stable-zkapp_command-in-network-pool

Use Zkapp_command.Stable.Latest in network_pool

1 of 29 new or added lines in 2 files covered. (3.45%)

16190 existing lines in 348 files now uncovered.

25656 of 71523 relevant lines covered (35.87%)

34337.21 hits per line

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

0.8
/src/lib/bootstrap_controller/bootstrap_controller.ml
1
(* Only show stdout for failed inline tests. *)
8✔
2
open Core
3
open Async
4
open Mina_base
5
module Ledger = Mina_ledger.Ledger
6
module Sync_ledger = Mina_ledger.Sync_ledger
7
open Mina_state
8
open Pipe_lib.Strict_pipe
9
open Network_peer
10
module Transition_cache = Transition_cache
11

12
module type CONTEXT = sig
13
  val logger : Logger.t
14

15
  val precomputed_values : Precomputed_values.t
16

17
  val constraint_constants : Genesis_constants.Constraint_constants.t
18

19
  val consensus_constants : Consensus.Constants.t
20

21
  val ledger_sync_config : Syncable_ledger.daemon_config
22

23
  val proof_cache_db : Proof_cache_tag.cache_db
24
end
25

26
type Structured_log_events.t += Bootstrap_complete
27
  [@@deriving register_event { msg = "Bootstrap state: complete." }]
3✔
28

29
type t =
30
  { context : (module CONTEXT)
31
  ; trust_system : Trust_system.t
32
  ; verifier : Verifier.t
33
  ; mutable best_seen_transition : Mina_block.initial_valid_block
34
  ; mutable current_root : Mina_block.initial_valid_block
35
  ; network : Mina_networking.t
36
  ; mutable num_of_root_snarked_ledger_retargeted : int
37
  }
38

39
type time = Time.Span.t
40

41
let time_to_yojson span =
UNCOV
42
  `String (Printf.sprintf "%f seconds" (Time.Span.to_sec span))
×
43

44
type opt_time = time option
45

46
let opt_time_to_yojson = function
UNCOV
47
  | Some time ->
×
48
      time_to_yojson time
49
  | None ->
×
50
      `Null
51

52
(** An auxiliary data structure for collecting various metrics for boostrap controller. *)
UNCOV
53
type bootstrap_cycle_stats =
×
UNCOV
54
  { cycle_result : string
×
UNCOV
55
  ; sync_ledger_time : time
×
UNCOV
56
  ; staged_ledger_data_download_time : time
×
UNCOV
57
  ; staged_ledger_construction_time : opt_time
×
UNCOV
58
  ; local_state_sync_required : bool
×
UNCOV
59
  ; local_state_sync_time : opt_time
×
60
  }
61
[@@deriving to_yojson]
62

63
let time_deferred deferred =
UNCOV
64
  let start_time = Time.now () in
×
65
  let%map result = deferred in
UNCOV
66
  let end_time = Time.now () in
×
UNCOV
67
  (Time.diff end_time start_time, result)
×
68

69
let worth_getting_root ({ context = (module Context); _ } as t) candidate =
UNCOV
70
  let module Consensus_context = struct
×
71
    include Context
72

73
    let logger =
UNCOV
74
      Logger.extend logger
×
75
        [ ( "selection_context"
76
          , `String "Bootstrap_controller.worth_getting_root" )
77
        ]
78
  end in
79
  Consensus.Hooks.equal_select_status `Take
80
  @@ Consensus.Hooks.select
81
       ~context:(module Consensus_context)
82
       ~existing:
UNCOV
83
         ( t.best_seen_transition |> Mina_block.Validation.block_with_hash
×
UNCOV
84
         |> With_hash.map ~f:Mina_block.consensus_state )
×
85
       ~candidate
86

87
let received_bad_proof ({ context = (module Context); _ } as t) host e =
88
  let open Context in
×
89
  Trust_system.(
90
    record t.trust_system logger host
91
      Actions.
92
        ( Violated_protocol
93
        , Some
94
            ( "Bad ancestor proof: $error"
95
            , [ ("error", Error_json.error_to_yojson e) ] ) ))
×
96

97
let done_syncing_root root_sync_ledger =
UNCOV
98
  Option.is_some (Sync_ledger.Db.peek_valid_tree root_sync_ledger)
×
99

100
let should_sync ~root_sync_ledger t candidate_state =
UNCOV
101
  (not @@ done_syncing_root root_sync_ledger)
×
UNCOV
102
  && worth_getting_root t candidate_state
×
103

104
(** Update [Synced_ledger]'s target and [best_seen_transition] and [current_root] accordingly. *)
105
let start_sync_job_with_peer ~sender ~root_sync_ledger
106
    ({ context = (module Context); _ } as t) peer_best_tip peer_root =
UNCOV
107
  let open Context in
×
108
  let%bind () =
109
    Trust_system.(
UNCOV
110
      record t.trust_system logger sender
×
111
        Actions.
112
          ( Fulfilled_request
113
          , Some ("Received verified peer root and best tip", []) ))
114
  in
UNCOV
115
  t.best_seen_transition <- peer_best_tip ;
×
116
  t.current_root <- peer_root ;
117
  let blockchain_state =
UNCOV
118
    t.current_root |> Mina_block.Validation.block |> Mina_block.header
×
UNCOV
119
    |> Mina_block.Header.protocol_state |> Protocol_state.blockchain_state
×
120
  in
UNCOV
121
  let expected_staged_ledger_hash =
×
122
    blockchain_state |> Blockchain_state.staged_ledger_hash
123
  in
UNCOV
124
  let snarked_ledger_hash =
×
125
    blockchain_state |> Blockchain_state.snarked_ledger_hash
126
  in
UNCOV
127
  return
×
128
  @@
129
  match
130
    Sync_ledger.Db.new_goal root_sync_ledger
UNCOV
131
      (Frozen_ledger_hash.to_ledger_hash snarked_ledger_hash)
×
132
      ~data:
UNCOV
133
        ( State_hash.With_state_hashes.state_hash
×
UNCOV
134
          @@ Mina_block.Validation.block_with_hash t.current_root
×
135
        , sender
136
        , expected_staged_ledger_hash )
137
      ~equal:(fun (hash1, _, _) (hash2, _, _) -> State_hash.equal hash1 hash2)
×
138
  with
UNCOV
139
  | `New ->
×
140
      t.num_of_root_snarked_ledger_retargeted <-
141
        t.num_of_root_snarked_ledger_retargeted + 1 ;
142
      `Syncing_new_snarked_ledger
143
  | `Update_data ->
×
144
      `Updating_root_transition
145
  | `Repeat ->
×
146
      `Ignored
147

148
let to_consensus_state h =
UNCOV
149
  Mina_block.Header.protocol_state h |> Protocol_state.consensus_state
×
150

151
(** For each transition, this function would compare it with the existing one.
152
    If the incoming transition is better, then download the merkle list from
153
    that transition to its root and verify it. If we get a better root than
154
    the existing one, then reset the Sync_ledger's target by calling
155
    [start_sync_job_with_peer] function. *)
156
let on_transition ({ context = (module Context); _ } as t) ~sender
157
    ~root_sync_ledger candidate_header =
UNCOV
158
  let open Context in
×
159
  let candidate_consensus_state =
160
    With_hash.map ~f:to_consensus_state candidate_header
161
  in
UNCOV
162
  if not @@ should_sync ~root_sync_ledger t candidate_consensus_state then
×
163
    Deferred.return `Ignored
×
164
  else
165
    match%bind
UNCOV
166
      Mina_networking.get_ancestry t.network sender.Peer.peer_id
×
UNCOV
167
        (With_hash.map_hash candidate_consensus_state
×
168
           ~f:State_hash.State_hashes.state_hash )
169
    with
UNCOV
170
    | Error e ->
×
UNCOV
171
        [%log error]
×
UNCOV
172
          ~metadata:[ ("error", Error_json.error_to_yojson e) ]
×
173
          !"Could not get the proof of the root transition from the network: \
174
            $error" ;
UNCOV
175
        Deferred.return `Ignored
×
UNCOV
176
    | Ok peer_root_with_proof -> (
×
177
        let pcd =
178
          peer_root_with_proof.data
UNCOV
179
          |> Proof_carrying_data.map
×
180
               ~f:(Mina_block.write_all_proofs_to_disk ~proof_cache_db)
181
          |> Proof_carrying_data.map_proof
182
               ~f:
183
                 (Tuple2.map_snd
184
                    ~f:(Mina_block.write_all_proofs_to_disk ~proof_cache_db) )
185
        in
186
        match%bind
UNCOV
187
          Mina_block.verify_on_header
×
188
            ~verify:
UNCOV
189
              (Sync_handler.Root.verify
×
190
                 ~context:(module Context)
191
                 ~verifier:t.verifier candidate_consensus_state )
192
            pcd
193
        with
UNCOV
194
        | Ok (`Root root, `Best_tip best_tip) ->
×
195
            if done_syncing_root root_sync_ledger then return `Ignored
×
196
            else
UNCOV
197
              start_sync_job_with_peer ~sender ~root_sync_ledger t best_tip root
×
198
        | Error e ->
×
199
            return (received_bad_proof t sender e |> Fn.const `Ignored) )
×
200

201
(** A helper function that wraps the calls to Sync_ledger and iterate through
202
    incoming transitions, add those to the transition_cache and calls
203
    [on_transition] function. *)
204
let sync_ledger ({ context = (module Context); _ } as t) ~preferred
205
    ~root_sync_ledger ~transition_graph ~sync_ledger_reader =
UNCOV
206
  let open Context in
×
207
  let query_reader = Sync_ledger.Db.query_reader root_sync_ledger in
UNCOV
208
  let response_writer = Sync_ledger.Db.answer_writer root_sync_ledger in
×
UNCOV
209
  Mina_networking.glue_sync_ledger ~preferred t.network query_reader
×
210
    response_writer ;
UNCOV
211
  Reader.iter sync_ledger_reader ~f:(fun (b_or_h, `Valid_cb vc) ->
×
UNCOV
212
      let header_with_hash, sender, transition_cache_element =
×
213
        match b_or_h with
UNCOV
214
        | `Block b_env ->
×
UNCOV
215
            ( Envelope.Incoming.data b_env
×
UNCOV
216
              |> Mina_block.Validation.block_with_hash
×
UNCOV
217
              |> With_hash.map ~f:Mina_block.header
×
UNCOV
218
            , Envelope.Incoming.remote_sender_exn b_env
×
UNCOV
219
            , Envelope.Incoming.map ~f:(fun x -> `Block x) b_env )
×
220
        | `Header h_env ->
×
221
            ( Envelope.Incoming.data h_env
×
222
              |> Mina_block.Validation.header_with_hash
×
223
            , Envelope.Incoming.remote_sender_exn h_env
×
224
            , Envelope.Incoming.map ~f:(fun x -> `Header x) h_env )
×
225
      in
226
      let previous_state_hash =
UNCOV
227
        With_hash.data header_with_hash
×
UNCOV
228
        |> Mina_block.Header.protocol_state
×
229
        |> Protocol_state.previous_state_hash
230
      in
UNCOV
231
      Transition_cache.add transition_graph ~parent:previous_state_hash
×
232
        (transition_cache_element, vc) ;
233
      (* TODO: Efficiently limiting the number of green threads in #1337 *)
UNCOV
234
      if
×
235
        worth_getting_root t
UNCOV
236
          (With_hash.map ~f:to_consensus_state header_with_hash)
×
UNCOV
237
      then (
×
UNCOV
238
        [%log trace] "Added the transition from sync_ledger_reader into cache"
×
239
          ~metadata:
240
            [ ( "state_hash"
UNCOV
241
              , State_hash.to_yojson
×
UNCOV
242
                  (State_hash.With_state_hashes.state_hash header_with_hash) )
×
243
            ; ( "header"
UNCOV
244
              , Mina_block.Header.to_yojson (With_hash.data header_with_hash) )
×
245
            ] ;
246

UNCOV
247
        Deferred.ignore_m
×
UNCOV
248
        @@ on_transition t ~sender ~root_sync_ledger header_with_hash )
×
249
      else Deferred.unit )
×
250

251
let external_transition_compare ~context:(module Context : CONTEXT) =
UNCOV
252
  let get_consensus_state =
×
253
    Fn.compose Protocol_state.consensus_state Mina_block.Header.protocol_state
254
  in
UNCOV
255
  Comparable.lift
×
256
    (fun existing candidate ->
257
      (* To prevent the logger to spam a lot of messsages, the logger input is set to null *)
UNCOV
258
      if
×
259
        State_hash.equal
UNCOV
260
          (State_hash.With_state_hashes.state_hash existing)
×
UNCOV
261
          (State_hash.With_state_hashes.state_hash candidate)
×
UNCOV
262
      then 0
×
UNCOV
263
      else if
×
264
        Consensus.Hooks.equal_select_status `Keep
265
        @@ Consensus.Hooks.select ~context:(module Context) ~existing ~candidate
UNCOV
266
      then -1
×
UNCOV
267
      else 1 )
×
268
    ~f:(With_hash.map ~f:get_consensus_state)
269

270
(** The entry point function for bootstrap controller. When bootstrap finished
271
    it would return a transition frontier with the root breadcrumb and a list
272
    of transitions collected during bootstrap.
273

274
    Bootstrap controller would do the following steps to contrust the
275
    transition frontier:
276
    1. Download the root snarked_ledger.
277
    2. Download the scan state and pending coinbases.
278
    3. Construct the staged ledger from the snarked ledger, scan state and
279
       pending coinbases.
280
    4. Synchronize the consensus local state if necessary.
281
    5. Close the old frontier and reload a new one from disk.
282
 *)
283
let run ~context:(module Context : CONTEXT) ~trust_system ~verifier ~network
284
    ~consensus_local_state ~transition_reader ~preferred_peers ~persistent_root
285
    ~persistent_frontier ~initial_root_transition ~catchup_mode =
UNCOV
286
  let open Context in
×
287
  O1trace.thread "bootstrap" (fun () ->
UNCOV
288
      let rec loop previous_cycles =
×
UNCOV
289
        let sync_ledger_pipe = "sync ledger pipe" in
×
290
        let sync_ledger_reader, sync_ledger_writer =
291
          create ~name:sync_ledger_pipe
292
            (Buffered
293
               ( `Capacity 50
294
               , `Overflow
295
                   (Drop_head
296
                      (fun (b_or_h, `Valid_cb valid_cb) ->
297
                        let hash =
×
298
                          match b_or_h with
299
                          | `Block b_env ->
×
300
                              Envelope.Incoming.data b_env
×
301
                              |> Mina_block.Validation.block_with_hash
×
302
                              |> With_hash.hash
×
303
                          | `Header h_env ->
×
304
                              Envelope.Incoming.data h_env
×
305
                              |> Mina_block.Validation.header_with_hash
×
306
                              |> With_hash.hash
×
307
                        in
308
                        Mina_metrics.(
309
                          Counter.inc_one
×
310
                            Pipe.Drop_on_overflow.bootstrap_sync_ledger) ;
311
                        Mina_block.handle_dropped_transition ?valid_cb hash
312
                          ~pipe_name:sync_ledger_pipe ~logger ) ) ) )
313
        in
UNCOV
314
        don't_wait_for
×
UNCOV
315
          (transfer_while_writer_alive transition_reader sync_ledger_writer
×
316
             ~f:Fn.id ) ;
UNCOV
317
        let initial_root_transition =
×
UNCOV
318
          initial_root_transition |> Mina_block.Validated.remember
×
UNCOV
319
          |> Mina_block.Validation.reset_frontier_dependencies_validation
×
320
          |> Mina_block.Validation.reset_staged_ledger_diff_validation
321
        in
UNCOV
322
        let t =
×
323
          { network
324
          ; context = (module Context)
325
          ; trust_system
326
          ; verifier
327
          ; best_seen_transition = initial_root_transition
328
          ; current_root = initial_root_transition
329
          ; num_of_root_snarked_ledger_retargeted = 0
330
          }
331
        in
332
        let transition_graph = Transition_cache.create () in
UNCOV
333
        let temp_persistent_root_instance =
×
334
          Transition_frontier.Persistent_root.create_instance_exn
335
            persistent_root
336
        in
UNCOV
337
        let temp_snarked_ledger =
×
338
          Transition_frontier.Persistent_root.Instance.snarked_ledger
339
            temp_persistent_root_instance
340
        in
341
        (* step 1. download snarked_ledger *)
342
        let%bind sync_ledger_time, (hash, sender, expected_staged_ledger_hash) =
UNCOV
343
          time_deferred
×
344
            (let root_sync_ledger =
345
               Sync_ledger.Db.create temp_snarked_ledger
346
                 ~context:(module Context)
347
                 ~trust_system
348
             in
UNCOV
349
             don't_wait_for
×
UNCOV
350
               (sync_ledger t ~preferred:preferred_peers ~root_sync_ledger
×
351
                  ~transition_graph ~sync_ledger_reader ) ;
352
             (* We ignore the resulting ledger returned here since it will always
353
                * be the same as the ledger we started with because we are syncing
354
                * a db ledger. *)
UNCOV
355
             let%map _, data = Sync_ledger.Db.valid_tree root_sync_ledger in
×
UNCOV
356
             Sync_ledger.Db.destroy root_sync_ledger ;
×
UNCOV
357
             data )
×
358
        in
UNCOV
359
        Mina_metrics.(
×
UNCOV
360
          Counter.inc Bootstrap.root_snarked_ledger_sync_ms
×
UNCOV
361
            Time.Span.(to_ms sync_ledger_time)) ;
×
362
        Mina_metrics.(
UNCOV
363
          Gauge.set Bootstrap.num_of_root_snarked_ledger_retargeted
×
UNCOV
364
            (Float.of_int t.num_of_root_snarked_ledger_retargeted)) ;
×
365
        (* step 2. Download scan state and pending coinbases. *)
366
        let%bind ( staged_ledger_data_download_time
367
                 , staged_ledger_construction_time
368
                 , staged_ledger_aux_result ) =
369
          let%bind ( staged_ledger_data_download_time
370
                   , staged_ledger_data_download_result ) =
UNCOV
371
            time_deferred
×
372
              (Mina_networking
UNCOV
373
               .get_staged_ledger_aux_and_pending_coinbases_at_hash t.network
×
374
                 sender.peer_id hash )
375
          in
UNCOV
376
          match staged_ledger_data_download_result with
×
377
          | Error err ->
×
378
              Deferred.return (staged_ledger_data_download_time, None, Error err)
UNCOV
379
          | Ok
×
380
              ( scan_state_uncached
381
              , expected_merkle_root
382
              , pending_coinbases
383
              , protocol_states ) -> (
384
              let%map staged_ledger_construction_result =
UNCOV
385
                O1trace.thread "construct_root_staged_ledger" (fun () ->
×
UNCOV
386
                    let open Deferred.Or_error.Let_syntax in
×
387
                    let received_staged_ledger_hash =
388
                      Staged_ledger_hash.of_aux_ledger_and_coinbase_hash
UNCOV
389
                        (Staged_ledger.Scan_state.Stable.Latest.hash
×
390
                           scan_state_uncached )
391
                        expected_merkle_root pending_coinbases
392
                    in
UNCOV
393
                    [%log debug]
×
394
                      ~metadata:
395
                        [ ( "expected_staged_ledger_hash"
UNCOV
396
                          , Staged_ledger_hash.to_yojson
×
397
                              expected_staged_ledger_hash )
398
                        ; ( "received_staged_ledger_hash"
UNCOV
399
                          , Staged_ledger_hash.to_yojson
×
400
                              received_staged_ledger_hash )
401
                        ]
402
                      "Comparing $expected_staged_ledger_hash to \
403
                       $received_staged_ledger_hash" ;
404
                    let%bind new_root =
405
                      t.current_root
406
                      |> Mina_block.Validation
UNCOV
407
                         .skip_frontier_dependencies_validation
×
408
                           `This_block_belongs_to_a_detached_subtree
UNCOV
409
                      |> Mina_block.Validation.validate_staged_ledger_hash
×
410
                           (`Staged_ledger_already_materialized
411
                             received_staged_ledger_hash )
UNCOV
412
                      |> Result.map_error ~f:(fun _ ->
×
413
                             Error.of_string
×
414
                               "received faulty scan state from peer" )
UNCOV
415
                      |> Deferred.return
×
416
                    in
UNCOV
417
                    let protocol_states =
×
418
                      List.map protocol_states
419
                        ~f:(With_hash.of_data ~hash_data:Protocol_state.hashes)
420
                    in
UNCOV
421
                    let scan_state =
×
422
                      Staged_ledger.Scan_state.write_all_proofs_to_disk
423
                        ~proof_cache_db scan_state_uncached
424
                    in
425
                    let%bind protocol_states =
UNCOV
426
                      Staged_ledger.Scan_state.check_required_protocol_states
×
427
                        scan_state ~protocol_states
UNCOV
428
                      |> Deferred.return
×
429
                    in
UNCOV
430
                    let protocol_states_map =
×
431
                      protocol_states
UNCOV
432
                      |> List.map ~f:(fun ps ->
×
UNCOV
433
                             (State_hash.With_state_hashes.state_hash ps, ps) )
×
434
                      |> State_hash.Map.of_alist_exn
435
                    in
UNCOV
436
                    let get_state hash =
×
UNCOV
437
                      match Map.find protocol_states_map hash with
×
438
                      | None ->
×
439
                          let new_state_hash =
440
                            State_hash.With_state_hashes.state_hash
441
                              (fst new_root)
×
442
                          in
443
                          [%log error]
×
444
                            ~metadata:
445
                              [ ("new_root", State_hash.to_yojson new_state_hash)
×
446
                              ; ("state_hash", State_hash.to_yojson hash)
×
447
                              ]
448
                            "Protocol state (for scan state transactions) for \
449
                             $state_hash not found when bootstrapping to the \
450
                             new root $new_root" ;
451
                          Or_error.errorf
×
452
                            !"Protocol state (for scan state transactions) for \
×
453
                              %{sexp:State_hash.t} not found when \
454
                              bootstrapping to the new root \
455
                              %{sexp:State_hash.t}"
456
                            hash new_state_hash
UNCOV
457
                      | Some protocol_state ->
×
UNCOV
458
                          Ok (With_hash.data protocol_state)
×
459
                    in
460
                    (* step 3. Construct staged ledger from snarked ledger, scan state
461
                       and pending coinbases. *)
462
                    (* Construct the staged ledger before constructing the transition
463
                     * frontier in order to verify the scan state we received.
464
                     * TODO: reorganize the code to avoid doing this twice (#3480) *)
465
                    let open Deferred.Let_syntax in
466
                    let%map staged_ledger_construction_time, construction_result
467
                        =
UNCOV
468
                      time_deferred
×
469
                        (let open Deferred.Let_syntax in
470
                        let temp_mask =
471
                          Ledger.of_database temp_snarked_ledger
472
                        in
473
                        let%map result =
474
                          Staged_ledger
475
                          .of_scan_state_pending_coinbases_and_snarked_ledger
476
                            ~logger
477
                            ~snarked_local_state:
478
                              Mina_block.(
UNCOV
479
                                t.current_root |> Validation.block |> header
×
UNCOV
480
                                |> Header.protocol_state
×
UNCOV
481
                                |> Protocol_state.blockchain_state
×
UNCOV
482
                                |> Blockchain_state.snarked_local_state)
×
483
                            ~verifier ~constraint_constants ~scan_state
484
                            ~snarked_ledger:temp_mask ~expected_merkle_root
485
                            ~pending_coinbases ~get_state
486
                        in
UNCOV
487
                        ignore
×
UNCOV
488
                          ( Ledger.Maskable.unregister_mask_exn ~loc:__LOC__
×
489
                              temp_mask
490
                            : Ledger.unattached_mask ) ;
491
                        Result.map result
492
                          ~f:
UNCOV
493
                            (const
×
494
                               ( scan_state
495
                               , pending_coinbases
496
                               , new_root
497
                               , protocol_states ) ))
498
                    in
UNCOV
499
                    Ok (staged_ledger_construction_time, construction_result) )
×
500
              in
UNCOV
501
              match staged_ledger_construction_result with
×
502
              | Error err ->
×
503
                  (staged_ledger_data_download_time, None, Error err)
UNCOV
504
              | Ok (staged_ledger_construction_time, result) ->
×
505
                  ( staged_ledger_data_download_time
506
                  , Some staged_ledger_construction_time
507
                  , result ) )
508
        in
UNCOV
509
        Transition_frontier.Persistent_root.Instance.close
×
510
          temp_persistent_root_instance ;
UNCOV
511
        match staged_ledger_aux_result with
×
512
        | Error e ->
×
513
            let%bind () =
514
              Trust_system.(
515
                record t.trust_system logger sender
×
516
                  Actions.
517
                    ( Outgoing_connection_error
518
                    , Some
519
                        ( "Can't find scan state from the peer or received \
520
                           faulty scan state from the peer."
521
                        , [] ) ))
522
            in
523
            [%log error]
×
524
              ~metadata:
525
                [ ("error", Error_json.error_to_yojson e)
×
526
                ; ("state_hash", State_hash.to_yojson hash)
×
527
                ; ( "expected_staged_ledger_hash"
528
                  , Staged_ledger_hash.to_yojson expected_staged_ledger_hash )
×
529
                ]
530
              "Failed to find scan state for the transition with hash \
531
               $state_hash from the peer or received faulty scan state: \
532
               $error. Retry bootstrap" ;
533
            Writer.close sync_ledger_writer ;
×
534
            let this_cycle =
×
535
              { cycle_result = "failed to download and construct scan state"
536
              ; sync_ledger_time
537
              ; staged_ledger_data_download_time
538
              ; staged_ledger_construction_time
539
              ; local_state_sync_required = false
540
              ; local_state_sync_time = None
541
              }
542
            in
543
            loop (this_cycle :: previous_cycles)
UNCOV
544
        | Ok (scan_state, pending_coinbase, new_root, protocol_states) -> (
×
545
            let%bind () =
546
              Trust_system.(
UNCOV
547
                record t.trust_system logger sender
×
548
                  Actions.
549
                    ( Fulfilled_request
550
                    , Some ("Received valid scan state from peer", []) ))
551
            in
UNCOV
552
            let best_seen_block_with_hash, _ = t.best_seen_transition in
×
553
            let consensus_state =
UNCOV
554
              With_hash.data best_seen_block_with_hash
×
UNCOV
555
              |> Mina_block.header |> Mina_block.Header.protocol_state
×
556
              |> Protocol_state.consensus_state
557
            in
558
            (* step 4. Synchronize consensus local state if necessary *)
559
            let%bind ( local_state_sync_time
560
                     , (local_state_sync_required, local_state_sync_result) ) =
UNCOV
561
              time_deferred
×
562
                ( match
563
                    Consensus.Hooks.required_local_state_sync
564
                      ~constants:precomputed_values.consensus_constants
565
                      ~consensus_state ~local_state:consensus_local_state
566
                  with
UNCOV
567
                | None ->
×
UNCOV
568
                    [%log debug]
×
569
                      ~metadata:
570
                        [ ( "local_state"
UNCOV
571
                          , Consensus.Data.Local_state.to_yojson
×
572
                              consensus_local_state )
573
                        ; ( "consensus_state"
UNCOV
574
                          , Consensus.Data.Consensus_state.Value.to_yojson
×
575
                              consensus_state )
576
                        ]
577
                      "Not synchronizing consensus local state" ;
UNCOV
578
                    Deferred.return (false, Or_error.return ())
×
579
                | Some sync_jobs ->
×
580
                    [%log info] "Synchronizing consensus local state" ;
×
581
                    let%map result =
582
                      Consensus.Hooks.sync_local_state
×
583
                        ~context:(module Context)
584
                        ~local_state:consensus_local_state ~trust_system
585
                        ~glue_sync_ledger:
586
                          (Mina_networking.glue_sync_ledger t.network)
×
587
                        sync_jobs
588
                    in
589
                    (true, result) )
×
590
            in
UNCOV
591
            match local_state_sync_result with
×
592
            | Error e ->
×
593
                [%log error]
×
594
                  ~metadata:[ ("error", Error_json.error_to_yojson e) ]
×
595
                  "Local state sync failed: $error. Retry bootstrap" ;
596
                Writer.close sync_ledger_writer ;
×
597
                let this_cycle =
×
598
                  { cycle_result = "failed to synchronize local state"
599
                  ; sync_ledger_time
600
                  ; staged_ledger_data_download_time
601
                  ; staged_ledger_construction_time
602
                  ; local_state_sync_required
603
                  ; local_state_sync_time = Some local_state_sync_time
604
                  }
605
                in
606
                loop (this_cycle :: previous_cycles)
UNCOV
607
            | Ok () ->
×
608
                (* step 5. Close the old frontier and reload a new one from disk. *)
609
                let new_root_data : Transition_frontier.Root_data.Limited.t =
610
                  Transition_frontier.Root_data.Limited.create
UNCOV
611
                    ~transition:(Mina_block.Validated.lift new_root)
×
612
                    ~scan_state ~pending_coinbase ~protocol_states
613
                in
614
                let%bind () =
UNCOV
615
                  Transition_frontier.Persistent_frontier.reset_database_exn
×
616
                    persistent_frontier ~root_data:new_root_data
617
                    ~genesis_state_hash:
UNCOV
618
                      (State_hash.With_state_hashes.state_hash
×
619
                         precomputed_values.protocol_state_with_hashes )
620
                in
621
                (* TODO: lazy load db in persistent root to avoid unecessary opens like this *)
UNCOV
622
                Transition_frontier.Persistent_root.(
×
UNCOV
623
                  with_instance_exn persistent_root ~f:(fun instance ->
×
UNCOV
624
                      Instance.set_root_state_hash instance
×
UNCOV
625
                      @@ Mina_block.Validated.state_hash
×
UNCOV
626
                      @@ Mina_block.Validated.lift new_root )) ;
×
627
                let%map new_frontier =
628
                  let fail msg =
629
                    failwith
×
630
                      ( "failed to initialize transition frontier after \
631
                         bootstrapping: " ^ msg )
632
                  in
UNCOV
633
                  Transition_frontier.load
×
634
                    ~context:(module Context)
635
                    ~retry_with_fresh_db:false ~verifier ~consensus_local_state
636
                    ~persistent_root ~persistent_frontier ~catchup_mode ()
UNCOV
637
                  >>| function
×
UNCOV
638
                  | Ok frontier ->
×
639
                      frontier
640
                  | Error (`Failure msg) ->
×
641
                      fail msg
642
                  | Error `Bootstrap_required ->
×
643
                      fail
644
                        "bootstrap still required (indicates logical error in \
645
                         code)"
646
                  | Error `Persistent_frontier_malformed ->
×
647
                      fail "persistent frontier was malformed"
648
                  | Error `Snarked_ledger_mismatch ->
×
649
                      fail
650
                        "this should not happen, because we just reset the \
651
                         snarked_ledger"
652
                in
UNCOV
653
                [%str_log info] Bootstrap_complete ;
×
UNCOV
654
                let collected_transitions =
×
655
                  Transition_cache.data transition_graph
656
                in
UNCOV
657
                let logger =
×
658
                  Logger.extend logger
659
                    [ ( "context"
660
                      , `String "Filter collected transitions in bootstrap" )
661
                    ]
662
                in
UNCOV
663
                let root_consensus_state =
×
664
                  Transition_frontier.(
UNCOV
665
                    Breadcrumb.consensus_state_with_hashes (root new_frontier))
×
666
                in
667
                let filtered_collected_transitions =
668
                  List.filter collected_transitions
669
                    ~f:(fun (incoming_transition, _) ->
UNCOV
670
                      let transition =
×
UNCOV
671
                        Envelope.Incoming.data incoming_transition
×
672
                        |> Transition_cache.header_with_hash
673
                      in
UNCOV
674
                      Consensus.Hooks.equal_select_status `Take
×
675
                      @@ Consensus.Hooks.select
676
                           ~context:(module Context)
677
                           ~existing:root_consensus_state
678
                           ~candidate:
UNCOV
679
                             (With_hash.map
×
680
                                ~f:
UNCOV
681
                                  (Fn.compose Protocol_state.consensus_state
×
682
                                     Mina_block.Header.protocol_state )
683
                                transition ) )
684
                in
UNCOV
685
                [%log debug] "Sorting filtered transitions by consensus state"
×
686
                  ~metadata:[] ;
UNCOV
687
                let sorted_filtered_collected_transitions =
×
688
                  O1trace.sync_thread "sorting_collected_transitions" (fun () ->
UNCOV
689
                      List.sort filtered_collected_transitions
×
690
                        ~compare:
UNCOV
691
                          (Comparable.lift
×
692
                             ~f:(fun (x, _) ->
693
                               Transition_cache.header_with_hash
×
694
                               @@ Envelope.Incoming.data x )
×
695
                             (external_transition_compare
696
                                ~context:(module Context) ) ) )
697
                in
UNCOV
698
                let this_cycle =
×
699
                  { cycle_result = "success"
700
                  ; sync_ledger_time
701
                  ; staged_ledger_data_download_time
702
                  ; staged_ledger_construction_time
703
                  ; local_state_sync_required
704
                  ; local_state_sync_time = Some local_state_sync_time
705
                  }
706
                in
707
                ( this_cycle :: previous_cycles
708
                , (new_frontier, sorted_filtered_collected_transitions) ) )
709
      in
UNCOV
710
      let%map time_elapsed, (cycles, result) = time_deferred (loop []) in
×
UNCOV
711
      [%log info] "Bootstrap completed in $time_elapsed: $bootstrap_stats"
×
712
        ~metadata:
UNCOV
713
          [ ("time_elapsed", time_to_yojson time_elapsed)
×
714
          ; ( "bootstrap_stats"
UNCOV
715
            , `List (List.map ~f:bootstrap_cycle_stats_to_yojson cycles) )
×
716
          ] ;
UNCOV
717
      Mina_metrics.(
×
UNCOV
718
        Gauge.set Bootstrap.bootstrap_time_ms
×
UNCOV
719
          Core.Time.(Span.to_ms @@ time_elapsed)) ;
×
720
      result )
721

722
let%test_module "Bootstrap_controller tests" =
723
  ( module struct
724
    open Pipe_lib
725

726
    let max_frontier_length =
UNCOV
727
      Transition_frontier.global_max_length Genesis_constants.For_unit_tests.t
×
728

UNCOV
729
    let logger = Logger.null ()
×
730

731
    let () =
732
      (* Disable log messages from best_tip_diff logger. *)
UNCOV
733
      Logger.Consumer_registry.register ~commit_id:""
×
UNCOV
734
        ~id:Logger.Logger_id.best_tip_diff ~processor:(Logger.Processor.raw ())
×
735
        ~transport:
UNCOV
736
          (Logger.Transport.create
×
737
             ( module struct
738
               type t = unit
739

UNCOV
740
               let transport () _ = ()
×
741
             end )
742
             () )
743
        ()
744

745
    let trust_system =
746
      let s = Trust_system.null () in
UNCOV
747
      don't_wait_for
×
UNCOV
748
        (Pipe_lib.Strict_pipe.Reader.iter
×
UNCOV
749
           (Trust_system.upcall_pipe s)
×
UNCOV
750
           ~f:(const Deferred.unit) ) ;
×
UNCOV
751
      s
×
752

UNCOV
753
    let precomputed_values = Lazy.force Precomputed_values.for_unit_tests
×
754

755
    let proof_level = precomputed_values.proof_level
756

757
    let constraint_constants = precomputed_values.constraint_constants
758

759
    let ledger_sync_config =
UNCOV
760
      Syncable_ledger.create_config
×
761
        ~compile_config:Mina_compile_config.For_unit_tests.t
762
        ~max_subtree_depth:None ~default_subtree_depth:None ()
763

764
    module Context = struct
765
      let logger = logger
766

767
      let precomputed_values = precomputed_values
768

769
      let constraint_constants =
770
        Genesis_constants.For_unit_tests.Constraint_constants.t
771

772
      let consensus_constants = precomputed_values.consensus_constants
773

774
      let ledger_sync_config =
UNCOV
775
        Syncable_ledger.create_config
×
776
          ~compile_config:Mina_compile_config.For_unit_tests.t
777
          ~max_subtree_depth:None ~default_subtree_depth:None ()
778

UNCOV
779
      let proof_cache_db = Proof_cache_tag.For_tests.create_db ()
×
780
    end
781

782
    let verifier =
UNCOV
783
      Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
784
          Verifier.For_tests.default ~constraint_constants ~logger ~proof_level
×
785
            () )
786

787
    module Genesis_ledger = (val precomputed_values.genesis_ledger)
788

789
    let downcast_transition ~sender transition =
UNCOV
790
      let transition =
×
UNCOV
791
        transition |> Mina_block.Validated.remember
×
UNCOV
792
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
793
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
794
      in
UNCOV
795
      Envelope.Incoming.wrap ~data:transition
×
796
        ~sender:(Envelope.Sender.Remote sender)
797

798
    let downcast_breadcrumb ~sender breadcrumb =
UNCOV
799
      downcast_transition ~sender
×
UNCOV
800
        (Transition_frontier.Breadcrumb.validated_transition breadcrumb)
×
801

802
    let make_non_running_bootstrap ~genesis_root ~network =
UNCOV
803
      let transition =
×
804
        genesis_root
UNCOV
805
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
806
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
807
      in
UNCOV
808
      { context = (module Context)
×
809
      ; trust_system
810
      ; verifier
811
      ; best_seen_transition = transition
812
      ; current_root = transition
813
      ; network
814
      ; num_of_root_snarked_ledger_retargeted = 0
815
      }
816

817
    let%test_unit "Bootstrap controller caches all transitions it is passed \
818
                   through the transition_reader" =
UNCOV
819
      let branch_size = (max_frontier_length * 2) + 2 in
×
820
      Quickcheck.test ~trials:1
821
        (let open Quickcheck.Generator.Let_syntax in
822
        (* we only need one node for this test, but we need more than one peer so that mina_networking does not throw an error *)
823
        let%bind fake_network =
824
          Fake_network.Generator.(
UNCOV
825
            gen ~precomputed_values ~verifier ~max_frontier_length
×
826
              ~ledger_sync_config [ fresh_peer; fresh_peer ]
827
              ~use_super_catchup:false)
828
        in
829
        let%map make_branch =
UNCOV
830
          Transition_frontier.Breadcrumb.For_tests.gen_seq ~precomputed_values
×
831
            ~verifier
UNCOV
832
            ~accounts_with_secret_keys:(Lazy.force Genesis_ledger.accounts)
×
833
            branch_size
834
        in
UNCOV
835
        let [ me; _ ] = fake_network.peer_networks in
×
836
        let branch =
837
          Async.Thread_safe.block_on_async_exn (fun () ->
UNCOV
838
              make_branch (Transition_frontier.root me.state.frontier) )
×
839
        in
UNCOV
840
        (fake_network, branch))
×
841
        ~f:(fun (fake_network, branch) ->
UNCOV
842
          let [ me; other ] = fake_network.peer_networks in
×
843
          let genesis_root =
844
            Transition_frontier.(
UNCOV
845
              Breadcrumb.validated_transition @@ root me.state.frontier)
×
846
            |> Mina_block.Validated.remember
847
          in
UNCOV
848
          let transition_graph = Transition_cache.create () in
×
UNCOV
849
          let sync_ledger_reader, sync_ledger_writer =
×
850
            Pipe_lib.Strict_pipe.create ~name:"sync_ledger_reader" Synchronous
851
          in
UNCOV
852
          let bootstrap =
×
853
            make_non_running_bootstrap ~genesis_root ~network:me.network
854
          in
855
          let root_sync_ledger =
856
            Sync_ledger.Db.create
UNCOV
857
              (Transition_frontier.root_snarked_ledger me.state.frontier)
×
858
              ~context:(module Context)
859
              ~trust_system
860
          in
UNCOV
861
          Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
862
              let sync_deferred =
×
863
                sync_ledger bootstrap ~root_sync_ledger ~transition_graph
864
                  ~preferred:[] ~sync_ledger_reader
865
              in
866
              let%bind () =
UNCOV
867
                Deferred.List.iter branch ~f:(fun breadcrumb ->
×
UNCOV
868
                    Strict_pipe.Writer.write sync_ledger_writer
×
869
                      ( `Block
UNCOV
870
                          (downcast_breadcrumb ~sender:other.peer breadcrumb)
×
871
                      , `Valid_cb None ) )
872
              in
UNCOV
873
              Strict_pipe.Writer.close sync_ledger_writer ;
×
UNCOV
874
              sync_deferred ) ;
×
UNCOV
875
          let expected_transitions =
×
876
            List.map branch
877
              ~f:
UNCOV
878
                (Fn.compose
×
879
                   (With_hash.map ~f:Mina_block.header)
UNCOV
880
                   (Fn.compose Mina_block.Validation.block_with_hash
×
UNCOV
881
                      (Fn.compose Mina_block.Validated.remember
×
882
                         Transition_frontier.Breadcrumb.validated_transition ) ) )
883
          in
UNCOV
884
          let saved_transitions =
×
UNCOV
885
            Transition_cache.data transition_graph
×
886
            |> List.map ~f:(fun (x, _) ->
UNCOV
887
                   Transition_cache.header_with_hash @@ Envelope.Incoming.data x )
×
888
          in
UNCOV
889
          let module E = struct
×
890
            module T = struct
891
              type t = Mina_block.Header.t State_hash.With_state_hashes.t
×
892
              [@@deriving sexp]
893

894
              let compare = external_transition_compare ~context:(module Context)
895
            end
896

897
            include Comparable.Make (T)
898
          end in
UNCOV
899
          [%test_result: E.Set.t]
×
UNCOV
900
            (E.Set.of_list saved_transitions)
×
UNCOV
901
            ~expect:(E.Set.of_list expected_transitions) )
×
902

903
    let run_bootstrap ~timeout_duration ~my_net ~transition_reader =
UNCOV
904
      let open Fake_network in
×
905
      let time_controller = Block_time.Controller.basic ~logger in
906
      let persistent_root =
907
        Transition_frontier.persistent_root my_net.state.frontier
908
      in
UNCOV
909
      let persistent_frontier =
×
910
        Transition_frontier.persistent_frontier my_net.state.frontier
911
      in
UNCOV
912
      let initial_root_transition =
×
913
        Transition_frontier.(
UNCOV
914
          Breadcrumb.validated_transition (root my_net.state.frontier))
×
915
      in
916
      let%bind () =
UNCOV
917
        Transition_frontier.close ~loc:__LOC__ my_net.state.frontier
×
918
      in
UNCOV
919
      [%log info] "bootstrap begin" ;
×
UNCOV
920
      Block_time.Timeout.await_exn time_controller ~timeout_duration
×
921
        (run
922
           ~context:(module Context)
923
           ~trust_system ~verifier ~network:my_net.network ~preferred_peers:[]
924
           ~consensus_local_state:my_net.state.consensus_local_state
925
           ~transition_reader ~persistent_root ~persistent_frontier
926
           ~catchup_mode:`Normal ~initial_root_transition )
927

928
    let assert_transitions_increasingly_sorted ~root
929
        (incoming_transitions : Transition_cache.element list) =
UNCOV
930
      let root =
×
UNCOV
931
        Transition_frontier.Breadcrumb.block root |> Mina_block.header
×
932
      in
UNCOV
933
      ignore
×
UNCOV
934
        ( List.fold_result ~init:root incoming_transitions
×
935
            ~f:(fun max_acc incoming_transition ->
UNCOV
936
              let With_hash.{ data = header; _ } =
×
937
                Transition_cache.header_with_hash
UNCOV
938
                  (Envelope.Incoming.data @@ fst incoming_transition)
×
939
              in
UNCOV
940
              let header_len h =
×
UNCOV
941
                Mina_block.Header.protocol_state h
×
UNCOV
942
                |> Protocol_state.consensus_state
×
943
                |> Consensus.Data.Consensus_state.blockchain_length
944
              in
945
              let open Result.Let_syntax in
946
              let%map () =
UNCOV
947
                Result.ok_if_true
×
UNCOV
948
                  Mina_numbers.Length.(header_len max_acc <= header_len header)
×
949
                  ~error:
UNCOV
950
                    (Error.of_string
×
951
                       "The blocks are not sorted in increasing order" )
952
              in
UNCOV
953
              header )
×
UNCOV
954
          |> Or_error.ok_exn
×
955
          : Mina_block.Header.t )
956

957
    let%test_unit "sync with one node after receiving a transition" =
UNCOV
958
      Quickcheck.test ~trials:1
×
959
        Fake_network.Generator.(
UNCOV
960
          gen ~precomputed_values ~verifier ~max_frontier_length
×
961
            ~use_super_catchup:false ~ledger_sync_config
962
            [ fresh_peer
963
            ; peer_with_branch
964
                ~frontier_branch_size:((max_frontier_length * 2) + 2)
965
            ])
966
        ~f:(fun fake_network ->
UNCOV
967
          let [ my_net; peer_net ] = fake_network.peer_networks in
×
968
          let transition_reader, transition_writer =
969
            Pipe_lib.Strict_pipe.create ~name:(__MODULE__ ^ __LOC__)
970
              (Buffered (`Capacity 10, `Overflow (Drop_head ignore)))
971
          in
UNCOV
972
          let block =
×
973
            Envelope.Incoming.wrap
974
              ~data:
UNCOV
975
                ( Transition_frontier.best_tip peer_net.state.frontier
×
UNCOV
976
                |> Transition_frontier.Breadcrumb.validated_transition
×
UNCOV
977
                |> Mina_block.Validated.remember
×
UNCOV
978
                |> Mina_block.Validation.reset_frontier_dependencies_validation
×
UNCOV
979
                |> Mina_block.Validation.reset_staged_ledger_diff_validation )
×
980
              ~sender:(Envelope.Sender.Remote peer_net.peer)
981
          in
982
          Pipe_lib.Strict_pipe.Writer.write transition_writer
983
            (`Block block, `Valid_cb None) ;
UNCOV
984
          let new_frontier, sorted_external_transitions =
×
985
            Async.Thread_safe.block_on_async_exn (fun () ->
UNCOV
986
                run_bootstrap
×
UNCOV
987
                  ~timeout_duration:(Block_time.Span.of_ms 30_000L)
×
988
                  ~my_net ~transition_reader )
989
          in
UNCOV
990
          assert_transitions_increasingly_sorted
×
UNCOV
991
            ~root:(Transition_frontier.root new_frontier)
×
992
            sorted_external_transitions ;
UNCOV
993
          [%test_result: Ledger_hash.t]
×
UNCOV
994
            ( Ledger.Db.merkle_root
×
UNCOV
995
            @@ Transition_frontier.root_snarked_ledger new_frontier )
×
996
            ~expect:
UNCOV
997
              ( Ledger.Db.merkle_root
×
UNCOV
998
              @@ Transition_frontier.root_snarked_ledger peer_net.state.frontier
×
999
              ) )
1000

1001
    let%test_unit "reconstruct staged_ledgers using \
1002
                   of_scan_state_and_snarked_ledger" =
UNCOV
1003
      Quickcheck.test ~trials:1
×
UNCOV
1004
        (Transition_frontier.For_tests.gen ~precomputed_values ~verifier
×
1005
           ~max_length:max_frontier_length ~size:max_frontier_length () )
1006
        ~f:(fun frontier ->
UNCOV
1007
          Thread_safe.block_on_async_exn
×
1008
          @@ fun () ->
UNCOV
1009
          Deferred.List.iter (Transition_frontier.all_breadcrumbs frontier)
×
1010
            ~f:(fun breadcrumb ->
UNCOV
1011
              let staged_ledger =
×
1012
                Transition_frontier.Breadcrumb.staged_ledger breadcrumb
1013
              in
UNCOV
1014
              let expected_merkle_root =
×
UNCOV
1015
                Staged_ledger.ledger staged_ledger |> Ledger.merkle_root
×
1016
              in
UNCOV
1017
              let snarked_ledger =
×
UNCOV
1018
                Transition_frontier.root_snarked_ledger frontier
×
1019
                |> Ledger.of_database
1020
              in
UNCOV
1021
              let snarked_local_state =
×
UNCOV
1022
                Transition_frontier.root frontier
×
UNCOV
1023
                |> Transition_frontier.Breadcrumb.protocol_state
×
UNCOV
1024
                |> Protocol_state.blockchain_state
×
1025
                |> Blockchain_state.snarked_local_state
1026
              in
UNCOV
1027
              let scan_state = Staged_ledger.scan_state staged_ledger in
×
UNCOV
1028
              let get_state hash =
×
UNCOV
1029
                match Transition_frontier.find_protocol_state frontier hash with
×
UNCOV
1030
                | Some protocol_state ->
×
1031
                    Ok protocol_state
1032
                | None ->
×
1033
                    Or_error.errorf
1034
                      !"Protocol state (for scan state transactions) for \
×
1035
                        %{sexp:State_hash.t} not found"
1036
                      hash
1037
              in
1038
              let pending_coinbases =
1039
                Staged_ledger.pending_coinbase_collection staged_ledger
1040
              in
1041
              let%map actual_staged_ledger =
1042
                Staged_ledger.of_scan_state_pending_coinbases_and_snarked_ledger
1043
                  ~scan_state ~logger ~verifier ~constraint_constants
1044
                  ~snarked_ledger ~snarked_local_state ~expected_merkle_root
1045
                  ~pending_coinbases ~get_state
UNCOV
1046
                |> Deferred.Or_error.ok_exn
×
1047
              in
UNCOV
1048
              let height =
×
UNCOV
1049
                Transition_frontier.Breadcrumb.consensus_state breadcrumb
×
UNCOV
1050
                |> Consensus.Data.Consensus_state.blockchain_length
×
1051
                |> Mina_numbers.Length.to_int
1052
              in
UNCOV
1053
              [%test_eq: Staged_ledger_hash.t]
×
1054
                ~message:
UNCOV
1055
                  (sprintf "mismatch of staged ledger hash height %d" height)
×
UNCOV
1056
                (Transition_frontier.Breadcrumb.staged_ledger_hash breadcrumb)
×
UNCOV
1057
                (Staged_ledger.hash actual_staged_ledger) ) )
×
1058

1059
    (*
1060
    let%test_unit "if we see a new transition that is better than the \
1061
                   transition that we are syncing from, than we should \
1062
                   retarget our root" =
1063
      Quickcheck.test ~trials:1
1064
        Fake_network.Generator.(
1065
          gen ~max_frontier_length
1066
            [ fresh_peer
1067
            ; peer_with_branch ~frontier_branch_size:max_frontier_length
1068
            ; peer_with_branch
1069
                ~frontier_branch_size:((max_frontier_length * 2) + 2) ])
1070
        ~f:(fun fake_network ->
1071
          let [me; weaker_chain; stronger_chain] =
1072
            fake_network.peer_networks
1073
          in
1074
          let transition_reader, transition_writer =
1075
            Pipe_lib.Strict_pipe.create ~name:(__MODULE__ ^ __LOC__)
1076
              (Buffered (`Capacity 10, `Overflow Drop_head))
1077
          in
1078
          Envelope.Incoming.wrap
1079
            ~data:
1080
              ( Transition_frontier.best_tip weaker_chain.state.frontier
1081
              |> Transition_frontier.Breadcrumb.validated_transition
1082
              |> Mina_block.Validated.to_initial_validated )
1083
            ~sender:
1084
              (Envelope.Sender.Remote
1085
                 (weaker_chain.peer.host, weaker_chain.peer.peer_id))
1086
          |> Pipe_lib.Strict_pipe.Writer.write transition_writer ;
1087
          Envelope.Incoming.wrap
1088
            ~data:
1089
              ( Transition_frontier.best_tip stronger_chain.state.frontier
1090
              |> Transition_frontier.Breadcrumb.validated_transition
1091
              |> Mina_block.Validated.to_initial_validated )
1092
            ~sender:
1093
              (Envelope.Sender.Remote
1094
                 (stronger_chain.peer.host, stronger_chain.peer.peer_id))
1095
          |> Pipe_lib.Strict_pipe.Writer.write transition_writer ;
1096
          let new_frontier, sorted_external_transitions =
1097
            Async.Thread_safe.block_on_async_exn (fun () ->
1098
                run_bootstrap
1099
                  ~timeout_duration:(Block_time.Span.of_ms 60_000L)
1100
                  ~my_net:me ~transition_reader )
1101
          in
1102
          assert_transitions_increasingly_sorted
1103
            ~root:(Transition_frontier.root new_frontier)
1104
            sorted_external_transitions ;
1105
          [%test_result: Ledger_hash.t]
1106
            ( Ledger.Db.merkle_root
1107
            @@ Transition_frontier.root_snarked_ledger new_frontier )
1108
            ~expect:
1109
              ( Ledger.Db.merkle_root
1110
              @@ Transition_frontier.root_snarked_ledger
1111
                   stronger_chain.state.frontier ) )
1112
*)
1113
  end )
16✔
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