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

MinaProtocol / mina / 3311

08 Feb 2025 09:10PM UTC coverage: 36.017% (-24.8%) from 60.828%
3311

push

buildkite

web-flow
Merge pull request #16591 from MinaProtocol/feature/stop-unknown-stream_idx

Stop sending data on libp2p streams after the first error

7 of 14 new or added lines in 1 file covered. (50.0%)

16388 existing lines in 340 files now uncovered.

25649 of 71214 relevant lines covered (36.02%)

26723.4 hits per line

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

0.81
/src/lib/bootstrap_controller/bootstrap_controller.ml
1
(* Only show stdout for failed inline tests. *)
5✔
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
end
21

22
type Structured_log_events.t += Bootstrap_complete
23
  [@@deriving register_event { msg = "Bootstrap state: complete." }]
3✔
24

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

35
type time = Time.Span.t
36

37
let time_to_yojson span =
UNCOV
38
  `String (Printf.sprintf "%f seconds" (Time.Span.to_sec span))
×
39

40
type opt_time = time option
41

42
let opt_time_to_yojson = function
UNCOV
43
  | Some time ->
×
44
      time_to_yojson time
45
  | None ->
×
46
      `Null
47

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

59
let time_deferred deferred =
UNCOV
60
  let start_time = Time.now () in
×
61
  let%map result = deferred in
UNCOV
62
  let end_time = Time.now () in
×
UNCOV
63
  (Time.diff end_time start_time, result)
×
64

65
let worth_getting_root ({ context = (module Context); _ } as t) candidate =
UNCOV
66
  let module Consensus_context = struct
×
67
    include Context
68

69
    let compile_config = precomputed_values.compile_config
70

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

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

95
let done_syncing_root root_sync_ledger =
UNCOV
96
  Option.is_some (Sync_ledger.Db.peek_valid_tree root_sync_ledger)
×
97

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

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

146
let to_consensus_state h =
UNCOV
147
  Mina_block.Header.protocol_state h |> Protocol_state.consensus_state
×
148

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

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

UNCOV
234
        Deferred.ignore_m
×
UNCOV
235
        @@ on_transition t ~sender ~root_sync_ledger header_with_hash )
×
236
      else Deferred.unit )
×
237

238
let external_transition_compare ~context:(module Context : CONTEXT) =
UNCOV
239
  let module Consensus_context = struct
×
240
    include Context
241

242
    let compile_config = precomputed_values.compile_config
243
  end in
244
  let get_consensus_state =
245
    Fn.compose Protocol_state.consensus_state Mina_block.Header.protocol_state
246
  in
UNCOV
247
  Comparable.lift
×
248
    (fun existing candidate ->
249
      (* To prevent the logger to spam a lot of messsages, the logger input is set to null *)
UNCOV
250
      if
×
251
        State_hash.equal
UNCOV
252
          (State_hash.With_state_hashes.state_hash existing)
×
UNCOV
253
          (State_hash.With_state_hashes.state_hash candidate)
×
UNCOV
254
      then 0
×
UNCOV
255
      else if
×
256
        Consensus.Hooks.equal_select_status `Keep
257
        @@ Consensus.Hooks.select
258
             ~context:(module Consensus_context)
259
             ~existing ~candidate
UNCOV
260
      then -1
×
UNCOV
261
      else 1 )
×
262
    ~f:(With_hash.map ~f:get_consensus_state)
263

264
(** The entry point function for bootstrap controller. When bootstrap finished
265
    it would return a transition frontier with the root breadcrumb and a list
266
    of transitions collected during bootstrap.
267

268
    Bootstrap controller would do the following steps to contrust the
269
    transition frontier:
270
    1. Download the root snarked_ledger.
271
    2. Download the scan state and pending coinbases.
272
    3. Construct the staged ledger from the snarked ledger, scan state and
273
       pending coinbases.
274
    4. Synchronize the consensus local state if necessary.
275
    5. Close the old frontier and reload a new one from disk.
276
 *)
277
let run ~context:(module Context : CONTEXT) ~trust_system ~verifier ~network
278
    ~consensus_local_state ~transition_reader ~preferred_peers ~persistent_root
279
    ~persistent_frontier ~initial_root_transition ~catchup_mode =
UNCOV
280
  let open Context in
×
281
  O1trace.thread "bootstrap" (fun () ->
UNCOV
282
      let rec loop previous_cycles =
×
UNCOV
283
        let sync_ledger_pipe = "sync ledger pipe" in
×
284
        let sync_ledger_reader, sync_ledger_writer =
285
          create ~name:sync_ledger_pipe
286
            (Buffered
287
               ( `Capacity 50
288
               , `Overflow
289
                   (Drop_head
290
                      (fun (b_or_h, `Valid_cb valid_cb) ->
291
                        let hash =
×
292
                          match b_or_h with
293
                          | `Block b_env ->
×
294
                              Envelope.Incoming.data b_env
×
295
                              |> Mina_block.Validation.block_with_hash
×
296
                              |> With_hash.hash
×
297
                          | `Header h_env ->
×
298
                              Envelope.Incoming.data h_env
×
299
                              |> Mina_block.Validation.header_with_hash
×
300
                              |> With_hash.hash
×
301
                        in
302
                        Mina_metrics.(
303
                          Counter.inc_one
×
304
                            Pipe.Drop_on_overflow.bootstrap_sync_ledger) ;
305
                        Mina_block.handle_dropped_transition ?valid_cb hash
306
                          ~pipe_name:sync_ledger_pipe ~logger ) ) ) )
307
        in
UNCOV
308
        don't_wait_for
×
UNCOV
309
          (transfer_while_writer_alive transition_reader sync_ledger_writer
×
310
             ~f:Fn.id ) ;
UNCOV
311
        let initial_root_transition =
×
UNCOV
312
          initial_root_transition |> Mina_block.Validated.remember
×
UNCOV
313
          |> Mina_block.Validation.reset_frontier_dependencies_validation
×
314
          |> Mina_block.Validation.reset_staged_ledger_diff_validation
315
        in
UNCOV
316
        let t =
×
317
          { network
318
          ; context = (module Context)
319
          ; trust_system
320
          ; verifier
321
          ; best_seen_transition = initial_root_transition
322
          ; current_root = initial_root_transition
323
          ; num_of_root_snarked_ledger_retargeted = 0
324
          }
325
        in
326
        let transition_graph = Transition_cache.create () in
UNCOV
327
        let temp_persistent_root_instance =
×
328
          Transition_frontier.Persistent_root.create_instance_exn
329
            persistent_root
330
        in
UNCOV
331
        let temp_snarked_ledger =
×
332
          Transition_frontier.Persistent_root.Instance.snarked_ledger
333
            temp_persistent_root_instance
334
        in
335
        (* step 1. download snarked_ledger *)
UNCOV
336
        let module Consensus_context = struct
×
337
          include Context
338

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

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

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

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

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

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

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

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

754
    let proof_level = precomputed_values.proof_level
755

756
    let constraint_constants = precomputed_values.constraint_constants
757

758
    module Context = struct
759
      let logger = logger
760

761
      let precomputed_values = precomputed_values
762

763
      let constraint_constants =
764
        Genesis_constants.For_unit_tests.Constraint_constants.t
765

766
      let consensus_constants = precomputed_values.consensus_constants
767
    end
768

769
    let verifier =
UNCOV
770
      Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
771
          Verifier.For_tests.default ~constraint_constants ~logger ~proof_level
×
772
            () )
773

774
    module Genesis_ledger = (val precomputed_values.genesis_ledger)
775

776
    let downcast_transition ~sender transition =
UNCOV
777
      let transition =
×
UNCOV
778
        transition |> Mina_block.Validated.remember
×
UNCOV
779
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
780
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
781
      in
UNCOV
782
      Envelope.Incoming.wrap ~data:transition
×
783
        ~sender:(Envelope.Sender.Remote sender)
784

785
    let downcast_breadcrumb ~sender breadcrumb =
UNCOV
786
      downcast_transition ~sender
×
UNCOV
787
        (Transition_frontier.Breadcrumb.validated_transition breadcrumb)
×
788

789
    let make_non_running_bootstrap ~genesis_root ~network =
UNCOV
790
      let transition =
×
791
        genesis_root
UNCOV
792
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
793
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
794
      in
UNCOV
795
      { context = (module Context)
×
796
      ; trust_system
797
      ; verifier
798
      ; best_seen_transition = transition
799
      ; current_root = transition
800
      ; network
801
      ; num_of_root_snarked_ledger_retargeted = 0
802
      }
803

804
    let%test_unit "Bootstrap controller caches all transitions it is passed \
805
                   through the transition_reader" =
UNCOV
806
      let branch_size = (max_frontier_length * 2) + 2 in
×
807
      Quickcheck.test ~trials:1
808
        (let open Quickcheck.Generator.Let_syntax in
809
        (* we only need one node for this test, but we need more than one peer so that mina_networking does not throw an error *)
810
        let%bind fake_network =
811
          Fake_network.Generator.(
UNCOV
812
            gen ~precomputed_values ~verifier ~max_frontier_length
×
813
              [ fresh_peer; fresh_peer ] ~use_super_catchup:false)
814
        in
815
        let%map make_branch =
UNCOV
816
          Transition_frontier.Breadcrumb.For_tests.gen_seq ~precomputed_values
×
817
            ~verifier
UNCOV
818
            ~accounts_with_secret_keys:(Lazy.force Genesis_ledger.accounts)
×
819
            branch_size
820
        in
UNCOV
821
        let [ me; _ ] = fake_network.peer_networks in
×
822
        let branch =
823
          Async.Thread_safe.block_on_async_exn (fun () ->
UNCOV
824
              make_branch (Transition_frontier.root me.state.frontier) )
×
825
        in
UNCOV
826
        (fake_network, branch))
×
827
        ~f:(fun (fake_network, branch) ->
UNCOV
828
          let [ me; other ] = fake_network.peer_networks in
×
829
          let genesis_root =
830
            Transition_frontier.(
UNCOV
831
              Breadcrumb.validated_transition @@ root me.state.frontier)
×
832
            |> Mina_block.Validated.remember
833
          in
UNCOV
834
          let transition_graph = Transition_cache.create () in
×
UNCOV
835
          let sync_ledger_reader, sync_ledger_writer =
×
836
            Pipe_lib.Strict_pipe.create ~name:"sync_ledger_reader" Synchronous
837
          in
UNCOV
838
          let bootstrap =
×
839
            make_non_running_bootstrap ~genesis_root ~network:me.network
840
          in
841
          let module Consensus_context = struct
842
            include Context
843

844
            let compile_config = precomputed_values.compile_config
845
          end in
846
          let root_sync_ledger =
847
            Sync_ledger.Db.create
UNCOV
848
              (Transition_frontier.root_snarked_ledger me.state.frontier)
×
849
              ~context:(module Consensus_context)
850
              ~trust_system
851
          in
UNCOV
852
          Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
853
              let sync_deferred =
×
854
                sync_ledger bootstrap ~root_sync_ledger ~transition_graph
855
                  ~preferred:[] ~sync_ledger_reader
856
              in
857
              let%bind () =
UNCOV
858
                Deferred.List.iter branch ~f:(fun breadcrumb ->
×
UNCOV
859
                    Strict_pipe.Writer.write sync_ledger_writer
×
860
                      ( `Block
UNCOV
861
                          (downcast_breadcrumb ~sender:other.peer breadcrumb)
×
862
                      , `Valid_cb None ) )
863
              in
UNCOV
864
              Strict_pipe.Writer.close sync_ledger_writer ;
×
UNCOV
865
              sync_deferred ) ;
×
UNCOV
866
          let expected_transitions =
×
867
            List.map branch
868
              ~f:
UNCOV
869
                (Fn.compose
×
870
                   (With_hash.map ~f:Mina_block.header)
UNCOV
871
                   (Fn.compose Mina_block.Validation.block_with_hash
×
UNCOV
872
                      (Fn.compose Mina_block.Validated.remember
×
873
                         Transition_frontier.Breadcrumb.validated_transition ) ) )
874
          in
UNCOV
875
          let saved_transitions =
×
UNCOV
876
            Transition_cache.data transition_graph
×
877
            |> List.map ~f:(fun (x, _) ->
UNCOV
878
                   Transition_cache.header_with_hash @@ Envelope.Incoming.data x )
×
879
          in
UNCOV
880
          let module E = struct
×
881
            module T = struct
882
              type t = Mina_block.Header.t State_hash.With_state_hashes.t
×
883
              [@@deriving sexp]
884

885
              let compare = external_transition_compare ~context:(module Context)
886
            end
887

888
            include Comparable.Make (T)
889
          end in
UNCOV
890
          [%test_result: E.Set.t]
×
UNCOV
891
            (E.Set.of_list saved_transitions)
×
UNCOV
892
            ~expect:(E.Set.of_list expected_transitions) )
×
893

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

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

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

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

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