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

MinaProtocol / mina / 641

30 Sep 2025 02:39AM UTC coverage: 32.179% (-29.2%) from 61.353%
641

push

buildkite

web-flow
Merge pull request #17874 from MinaProtocol/cjjdespres/rework-genesis-population

Rework, speed up root ledger population from genesis

0 of 32 new or added lines in 5 files covered. (0.0%)

20703 existing lines in 409 files now uncovered.

23281 of 72349 relevant lines covered (32.18%)

23480.06 hits per line

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

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

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

16
  val precomputed_values : Precomputed_values.t
17

18
  val constraint_constants : Genesis_constants.Constraint_constants.t
19

20
  val consensus_constants : Consensus.Constants.t
21

22
  val ledger_sync_config : Syncable_ledger.daemon_config
23

24
  val proof_cache_db : Proof_cache_tag.cache_db
25
end
26

27
type Structured_log_events.t += Bootstrap_complete
UNCOV
28
  [@@deriving register_event { msg = "Bootstrap state: complete." }]
×
29

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

40
(** An auxiliary data structure for collecting various metrics for bootstrap controller. *)
UNCOV
41
type bootstrap_cycle_stats =
×
UNCOV
42
  { cycle_result : string
×
UNCOV
43
  ; sync_ledger_time : Time.Span.t
×
UNCOV
44
  ; staged_ledger_data_download_time : Time.Span.t
×
UNCOV
45
  ; staged_ledger_construction_time : Time.Span.t option
×
UNCOV
46
  ; local_state_sync_required : bool
×
UNCOV
47
  ; local_state_sync_time : Time.Span.t option
×
48
  }
49
[@@deriving to_yojson]
50

51
let time_deferred deferred =
UNCOV
52
  let start_time = Time.now () in
×
53
  let%map result = deferred in
UNCOV
54
  let end_time = Time.now () in
×
UNCOV
55
  (Time.diff end_time start_time, result)
×
56

57
let worth_getting_root ({ context = (module Context); _ } as t) candidate =
UNCOV
58
  let module Consensus_context = struct
×
59
    include Context
60

61
    let logger =
UNCOV
62
      Logger.extend logger
×
63
        [ ( "selection_context"
64
          , `String "Bootstrap_controller.worth_getting_root" )
65
        ]
66
  end in
67
  Consensus.Hooks.equal_select_status `Take
68
  @@ Consensus.Hooks.select
69
       ~context:(module Consensus_context)
70
       ~existing:
UNCOV
71
         ( t.best_seen_transition |> Mina_block.Validation.block_with_hash
×
UNCOV
72
         |> With_hash.map ~f:Mina_block.consensus_state )
×
73
       ~candidate
74

75
let received_bad_proof ({ context = (module Context); _ } as t) host e =
UNCOV
76
  let open Context in
×
77
  Trust_system.(
78
    record t.trust_system logger host
79
      Actions.
80
        ( Violated_protocol
81
        , Some
82
            ( "Bad ancestor proof: $error"
UNCOV
83
            , [ ("error", Error_json.error_to_yojson e) ] ) ))
×
84

85
let done_syncing_root root_sync_ledger =
UNCOV
86
  Option.is_some (Sync_ledger.Root.peek_valid_tree root_sync_ledger)
×
87

88
let should_sync ~root_sync_ledger t candidate_state =
UNCOV
89
  (not @@ done_syncing_root root_sync_ledger)
×
UNCOV
90
  && worth_getting_root t candidate_state
×
91

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

136
let to_consensus_state h =
137
  Mina_block.Header.protocol_state h |> Protocol_state.consensus_state
×
138

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

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

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

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

259
let download_snarked_ledger ~trust_system ~preferred_peers ~transition_graph
260
    ~sync_ledger_reader ~context t temp_snarked_ledger =
UNCOV
261
  time_deferred
×
262
    (let root_sync_ledger =
263
       Sync_ledger.Root.create temp_snarked_ledger ~context ~trust_system
264
     in
UNCOV
265
     don't_wait_for
×
UNCOV
266
       (sync_ledger t ~preferred:preferred_peers ~root_sync_ledger
×
267
          ~transition_graph ~sync_ledger_reader ) ;
268
     (* We ignore the resulting ledger returned here since it will always
269
        * be the same as the ledger we started with because we are syncing
270
        * a db ledger. *)
UNCOV
271
     let%map _, data = Sync_ledger.Root.valid_tree root_sync_ledger in
×
UNCOV
272
     Sync_ledger.Root.destroy root_sync_ledger ;
×
UNCOV
273
     data )
×
274

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

653
(** The entry point function for bootstrap controller. When bootstrap finished
654
    it would return a transition frontier with the root breadcrumb and a list
655
    of transitions collected during bootstrap.
656

657
    Bootstrap controller would do the following steps to contrust the
658
    transition frontier:
659
    1. Download the root snarked_ledger.
660
    2. Download the scan state and pending coinbases.
661
    3. Construct the staged ledger from the snarked ledger, scan state and
662
       pending coinbases.
663
    4. Synchronize the consensus local state if necessary.
664
    5. Close the old frontier and reload a new one from disk.
665
 *)
666
let run ~context:(module Context : CONTEXT) ~trust_system ~verifier ~network
667
    ~consensus_local_state ~network_transition_pipe ~preferred_peers
668
    ~persistent_root ~persistent_frontier ~initial_root_transition ~catchup_mode
669
    ~signature_kind =
UNCOV
670
  let open Context in
×
671
  let run_cycle =
672
    run_cycle
673
      ~context:(module Context : CONTEXT)
674
      ~trust_system ~verifier ~network ~consensus_local_state
675
      ~network_transition_pipe ~preferred_peers ~persistent_root
676
      ~persistent_frontier ~initial_root_transition ~catchup_mode
677
      ~signature_kind
678
  in
679
  O1trace.thread "bootstrap"
680
  @@ fun () ->
681
  let%map time_elapsed, (cycles, result) =
UNCOV
682
    time_deferred @@ Deferred.repeat_until_finished [] run_cycle
×
683
  in
UNCOV
684
  [%log info] "Bootstrap completed in $time_elapsed: $bootstrap_stats"
×
685
    ~metadata:
UNCOV
686
      [ ("time_elapsed", Time.Span.to_yojson_hum time_elapsed)
×
687
      ; ( "bootstrap_stats"
UNCOV
688
        , `List (List.map ~f:bootstrap_cycle_stats_to_yojson cycles) )
×
689
      ] ;
UNCOV
690
  Mina_metrics.(
×
UNCOV
691
    Gauge.set Bootstrap.bootstrap_time_ms Core.Time.(Span.to_ms @@ time_elapsed)) ;
×
692
  result
693

694
let%test_module "Bootstrap_controller tests" =
695
  ( module struct
696
    let max_frontier_length =
UNCOV
697
      Transition_frontier.global_max_length Genesis_constants.For_unit_tests.t
×
698

UNCOV
699
    let logger = Logger.null ()
×
700

701
    let () =
702
      (* Disable log messages from best_tip_diff logger. *)
UNCOV
703
      Logger.Consumer_registry.register ~commit_id:""
×
UNCOV
704
        ~id:Logger.Logger_id.best_tip_diff ~processor:(Logger.Processor.raw ())
×
705
        ~transport:
UNCOV
706
          (Logger.Transport.create
×
707
             ( module struct
708
               type t = unit
709

UNCOV
710
               let transport () _ = ()
×
711
             end )
712
             () )
713
        ()
714

715
    let trust_system =
716
      let s = Trust_system.null () in
UNCOV
717
      don't_wait_for
×
UNCOV
718
        (Pipe_lib.Strict_pipe.Reader.iter
×
UNCOV
719
           (Trust_system.upcall_pipe s)
×
UNCOV
720
           ~f:(const Deferred.unit) ) ;
×
UNCOV
721
      s
×
722

UNCOV
723
    let precomputed_values = Lazy.force Precomputed_values.for_unit_tests
×
724

725
    let proof_level = precomputed_values.proof_level
726

727
    let constraint_constants = precomputed_values.constraint_constants
728

729
    let ledger_sync_config =
UNCOV
730
      Syncable_ledger.create_config
×
731
        ~compile_config:Mina_compile_config.For_unit_tests.t
732
        ~max_subtree_depth:None ~default_subtree_depth:None ()
733

734
    module Context = struct
735
      let logger = logger
736

737
      let precomputed_values = precomputed_values
738

739
      let constraint_constants =
740
        Genesis_constants.For_unit_tests.Constraint_constants.t
741

742
      let consensus_constants = precomputed_values.consensus_constants
743

744
      let ledger_sync_config =
UNCOV
745
        Syncable_ledger.create_config
×
746
          ~compile_config:Mina_compile_config.For_unit_tests.t
747
          ~max_subtree_depth:None ~default_subtree_depth:None ()
748

UNCOV
749
      let proof_cache_db = Proof_cache_tag.For_tests.create_db ()
×
750
    end
751

752
    let verifier =
UNCOV
753
      Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
754
          Verifier.For_tests.default ~constraint_constants ~logger ~proof_level
×
755
            () )
756

757
    module Genesis_ledger = (val precomputed_values.genesis_ledger)
758

759
    let downcast_transition ~sender transition =
UNCOV
760
      let transition =
×
UNCOV
761
        transition |> Mina_block.Validated.remember
×
UNCOV
762
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
763
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
764
      in
UNCOV
765
      Envelope.Incoming.wrap ~data:transition
×
766
        ~sender:(Envelope.Sender.Remote sender)
767

768
    let downcast_breadcrumb ~sender breadcrumb =
UNCOV
769
      downcast_transition ~sender
×
UNCOV
770
        (Transition_frontier.Breadcrumb.validated_transition breadcrumb)
×
771

772
    let make_non_running_bootstrap ~genesis_root ~network =
UNCOV
773
      let transition =
×
774
        genesis_root
UNCOV
775
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
776
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
777
      in
UNCOV
778
      { context = (module Context)
×
779
      ; trust_system
780
      ; verifier
781
      ; best_seen_transition = transition
782
      ; current_root = transition
783
      ; network
784
      ; num_of_root_snarked_ledger_retargeted = 0
785
      }
786

787
    let%test_unit "Bootstrap controller caches all transitions it is passed \
788
                   through the transition_reader" =
UNCOV
789
      let branch_size = (max_frontier_length * 2) + 2 in
×
790
      Quickcheck.test ~trials:1
791
        (let open Quickcheck.Generator.Let_syntax in
792
        (* we only need one node for this test, but we need more than one peer so that mina_networking does not throw an error *)
793
        let%bind fake_network =
794
          Fake_network.Generator.(
UNCOV
795
            gen ~precomputed_values ~verifier ~max_frontier_length
×
796
              ~ledger_sync_config [ fresh_peer; fresh_peer ])
797
        in
798
        let%map make_branch =
UNCOV
799
          Transition_frontier.Breadcrumb.For_tests.gen_seq ~precomputed_values
×
800
            ~verifier
UNCOV
801
            ~accounts_with_secret_keys:(Lazy.force Genesis_ledger.accounts)
×
802
            branch_size
803
        in
UNCOV
804
        let [ me; _ ] = fake_network.peer_networks in
×
805
        let branch =
806
          Async.Thread_safe.block_on_async_exn (fun () ->
UNCOV
807
              make_branch (Transition_frontier.root me.state.frontier) )
×
808
        in
UNCOV
809
        (fake_network, branch))
×
810
        ~f:(fun (fake_network, branch) ->
UNCOV
811
          let [ me; other ] = fake_network.peer_networks in
×
812
          let genesis_root =
813
            Transition_frontier.(
UNCOV
814
              Breadcrumb.validated_transition @@ root me.state.frontier)
×
815
            |> Mina_block.Validated.remember
816
          in
UNCOV
817
          let transition_graph = Transition_cache.create () in
×
UNCOV
818
          let sync_ledger_reader, sync_ledger_writer =
×
819
            Pipe_lib.Choosable_synchronous_pipe.create ()
820
          in
UNCOV
821
          let bootstrap =
×
822
            make_non_running_bootstrap ~genesis_root ~network:me.network
823
          in
824
          let root_sync_ledger =
825
            Sync_ledger.Root.create
UNCOV
826
              (Transition_frontier.root_snarked_ledger me.state.frontier)
×
827
              ~context:(module Context)
828
              ~trust_system
829
          in
UNCOV
830
          Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
831
              let sync_deferred =
×
832
                sync_ledger bootstrap ~root_sync_ledger ~transition_graph
833
                  ~preferred:[] ~sync_ledger_reader
834
              in
835
              let%bind sync_ledger_writer' =
UNCOV
836
                Deferred.List.fold ~init:sync_ledger_writer branch
×
837
                  ~f:(fun sync_ledger_writer breadcrumb ->
UNCOV
838
                    Pipe_lib.Choosable_synchronous_pipe.write sync_ledger_writer
×
839
                      ( `Block
UNCOV
840
                          (downcast_breadcrumb ~sender:other.peer breadcrumb)
×
841
                      , `Valid_cb None ) )
842
              in
UNCOV
843
              Pipe_lib.Choosable_synchronous_pipe.close sync_ledger_writer' ;
×
UNCOV
844
              sync_deferred ) ;
×
UNCOV
845
          let expected_transitions =
×
846
            List.map branch
847
              ~f:
UNCOV
848
                (Fn.compose
×
849
                   (With_hash.map ~f:Mina_block.header)
UNCOV
850
                   (Fn.compose Mina_block.Validation.block_with_hash
×
UNCOV
851
                      (Fn.compose Mina_block.Validated.remember
×
852
                         Transition_frontier.Breadcrumb.validated_transition ) ) )
853
          in
UNCOV
854
          let saved_transitions =
×
UNCOV
855
            Transition_cache.data transition_graph
×
856
            |> List.map ~f:(fun (x, _) ->
UNCOV
857
                   Transition_cache.header_with_hash @@ Envelope.Incoming.data x )
×
858
          in
UNCOV
859
          let module E = struct
×
860
            module T = struct
UNCOV
861
              type t = Mina_block.Header.t State_hash.With_state_hashes.t
×
862
              [@@deriving sexp]
863

864
              let compare = external_transition_compare ~context:(module Context)
865
            end
866

867
            include Comparable.Make (T)
868
          end in
UNCOV
869
          [%test_result: E.Set.t]
×
UNCOV
870
            (E.Set.of_list saved_transitions)
×
UNCOV
871
            ~expect:(E.Set.of_list expected_transitions) )
×
872

873
    let run_bootstrap ~timeout_duration ~my_net ~network_transition_pipe =
UNCOV
874
      let open Fake_network in
×
875
      let time_controller = Block_time.Controller.basic ~logger in
876
      let persistent_root =
877
        Transition_frontier.persistent_root my_net.state.frontier
878
      in
UNCOV
879
      let persistent_frontier =
×
880
        Transition_frontier.persistent_frontier my_net.state.frontier
881
      in
UNCOV
882
      let initial_root_transition =
×
883
        Transition_frontier.(
UNCOV
884
          Breadcrumb.validated_transition (root my_net.state.frontier))
×
885
      in
886
      let%bind () =
UNCOV
887
        Transition_frontier.close ~loc:__LOC__ my_net.state.frontier
×
888
      in
UNCOV
889
      [%log info] "bootstrap begin" ;
×
UNCOV
890
      Block_time.Timeout.await_exn time_controller ~timeout_duration
×
891
        (run
892
           ~context:(module Context)
893
           ~trust_system ~verifier ~network:my_net.network ~preferred_peers:[]
894
           ~consensus_local_state:my_net.state.consensus_local_state
895
           ~network_transition_pipe ~persistent_root ~persistent_frontier
896
           ~catchup_mode:`Super ~initial_root_transition
897
           ~signature_kind:Mina_signature_kind.t_DEPRECATED )
898

899
    let assert_transitions_increasingly_sorted ~root
900
        (incoming_transitions : Transition_cache.element list) =
UNCOV
901
      let root =
×
UNCOV
902
        Transition_frontier.Breadcrumb.block root |> Mina_block.header
×
903
      in
UNCOV
904
      ignore
×
UNCOV
905
        ( List.fold_result ~init:root incoming_transitions
×
906
            ~f:(fun max_acc incoming_transition ->
UNCOV
907
              let With_hash.{ data = header; _ } =
×
908
                Transition_cache.header_with_hash
UNCOV
909
                  (Envelope.Incoming.data @@ fst incoming_transition)
×
910
              in
UNCOV
911
              let header_len h =
×
UNCOV
912
                Mina_block.Header.protocol_state h
×
UNCOV
913
                |> Protocol_state.consensus_state
×
914
                |> Consensus.Data.Consensus_state.blockchain_length
915
              in
916
              let open Result.Let_syntax in
917
              let%map () =
UNCOV
918
                Result.ok_if_true
×
UNCOV
919
                  Mina_numbers.Length.(header_len max_acc <= header_len header)
×
920
                  ~error:
UNCOV
921
                    (Error.of_string
×
922
                       "The blocks are not sorted in increasing order" )
923
              in
UNCOV
924
              header )
×
UNCOV
925
          |> Or_error.ok_exn
×
926
          : Mina_block.Header.t )
927

928
    let%test_unit "sync with one node after receiving a transition" =
UNCOV
929
      Quickcheck.test ~trials:1
×
930
        Fake_network.Generator.(
UNCOV
931
          gen ~precomputed_values ~verifier ~max_frontier_length
×
932
            ~ledger_sync_config
933
            [ fresh_peer
934
            ; peer_with_branch
935
                ~frontier_branch_size:((max_frontier_length * 2) + 2)
936
            ])
937
        ~f:(fun fake_network ->
UNCOV
938
          let [ my_net; peer_net ] = fake_network.peer_networks in
×
939
          let block =
940
            Envelope.Incoming.wrap
941
              ~data:
UNCOV
942
                ( Transition_frontier.best_tip peer_net.state.frontier
×
UNCOV
943
                |> Transition_frontier.Breadcrumb.validated_transition
×
UNCOV
944
                |> Mina_block.Validated.remember
×
UNCOV
945
                |> Mina_block.Validation.reset_frontier_dependencies_validation
×
UNCOV
946
                |> Mina_block.Validation.reset_staged_ledger_diff_validation )
×
947
              ~sender:(Envelope.Sender.Remote peer_net.peer)
948
          in
949
          let network_transition_pipe =
950
            Swappable.create ~name:(__MODULE__ ^ __LOC__)
951
              (Buffered (`Capacity 10, `Overflow (Drop_head ignore)))
952
          in
UNCOV
953
          Swappable.write network_transition_pipe (`Block block, `Valid_cb None) ;
×
UNCOV
954
          let new_frontier, sorted_external_transitions =
×
955
            Async.Thread_safe.block_on_async_exn (fun () ->
UNCOV
956
                run_bootstrap
×
UNCOV
957
                  ~timeout_duration:(Block_time.Span.of_ms 30_000L)
×
958
                  ~my_net ~network_transition_pipe )
959
          in
UNCOV
960
          assert_transitions_increasingly_sorted
×
UNCOV
961
            ~root:(Transition_frontier.root new_frontier)
×
962
            sorted_external_transitions ;
UNCOV
963
          [%test_result: Ledger_hash.t]
×
UNCOV
964
            ( Ledger.Root.merkle_root
×
UNCOV
965
            @@ Transition_frontier.root_snarked_ledger new_frontier )
×
966
            ~expect:
UNCOV
967
              ( Ledger.Root.merkle_root
×
UNCOV
968
              @@ Transition_frontier.root_snarked_ledger peer_net.state.frontier
×
969
              ) )
970

971
    let%test_unit "reconstruct staged_ledgers using \
972
                   of_scan_state_and_snarked_ledger" =
UNCOV
973
      Quickcheck.test ~trials:1
×
UNCOV
974
        (Transition_frontier.For_tests.gen ~precomputed_values ~verifier
×
975
           ~max_length:max_frontier_length ~size:max_frontier_length () )
976
        ~f:(fun frontier ->
UNCOV
977
          Thread_safe.block_on_async_exn
×
978
          @@ fun () ->
UNCOV
979
          Deferred.List.iter (Transition_frontier.all_breadcrumbs frontier)
×
980
            ~f:(fun breadcrumb ->
UNCOV
981
              let staged_ledger =
×
982
                Transition_frontier.Breadcrumb.staged_ledger breadcrumb
983
              in
UNCOV
984
              let expected_merkle_root =
×
UNCOV
985
                Staged_ledger.ledger staged_ledger |> Ledger.merkle_root
×
986
              in
UNCOV
987
              let snarked_ledger =
×
UNCOV
988
                Transition_frontier.root_snarked_ledger frontier
×
989
                |> Ledger.Root.as_masked
990
              in
UNCOV
991
              let snarked_local_state =
×
UNCOV
992
                Transition_frontier.root frontier
×
UNCOV
993
                |> Transition_frontier.Breadcrumb.protocol_state
×
UNCOV
994
                |> Protocol_state.blockchain_state
×
995
                |> Blockchain_state.snarked_local_state
996
              in
UNCOV
997
              let scan_state = Staged_ledger.scan_state staged_ledger in
×
UNCOV
998
              let get_state hash =
×
UNCOV
999
                match Transition_frontier.find_protocol_state frontier hash with
×
UNCOV
1000
                | Some protocol_state ->
×
1001
                    Ok protocol_state
UNCOV
1002
                | None ->
×
1003
                    Or_error.errorf
UNCOV
1004
                      !"Protocol state (for scan state transactions) for \
×
1005
                        %{sexp:State_hash.t} not found"
1006
                      hash
1007
              in
1008
              let pending_coinbases =
1009
                Staged_ledger.pending_coinbase_collection staged_ledger
1010
              in
1011
              let%map actual_staged_ledger =
1012
                Staged_ledger.of_scan_state_pending_coinbases_and_snarked_ledger
1013
                  ~scan_state ~logger ~verifier ~constraint_constants
1014
                  ~snarked_ledger ~snarked_local_state ~expected_merkle_root
1015
                  ~pending_coinbases ~get_state
1016
                  ~signature_kind:Mina_signature_kind.t_DEPRECATED
UNCOV
1017
                |> Deferred.Or_error.ok_exn
×
1018
              in
UNCOV
1019
              let height =
×
UNCOV
1020
                Transition_frontier.Breadcrumb.consensus_state breadcrumb
×
UNCOV
1021
                |> Consensus.Data.Consensus_state.blockchain_length
×
1022
                |> Mina_numbers.Length.to_int
1023
              in
UNCOV
1024
              [%test_eq: Staged_ledger_hash.t]
×
1025
                ~message:
UNCOV
1026
                  (sprintf "mismatch of staged ledger hash height %d" height)
×
UNCOV
1027
                (Transition_frontier.Breadcrumb.staged_ledger_hash breadcrumb)
×
UNCOV
1028
                (Staged_ledger.hash actual_staged_ledger) ) )
×
1029

1030
    (*
1031
    let%test_unit "if we see a new transition that is better than the \
1032
                   transition that we are syncing from, than we should \
1033
                   retarget our root" =
1034
      Quickcheck.test ~trials:1
1035
        Fake_network.Generator.(
1036
          gen ~max_frontier_length
1037
            [ fresh_peer
1038
            ; peer_with_branch ~frontier_branch_size:max_frontier_length
1039
            ; peer_with_branch
1040
                ~frontier_branch_size:((max_frontier_length * 2) + 2) ])
1041
        ~f:(fun fake_network ->
1042
          let [me; weaker_chain; stronger_chain] =
1043
            fake_network.peer_networks
1044
          in
1045
          let transition_reader, transition_writer =
1046
            Pipe_lib.Strict_pipe.create ~name:(__MODULE__ ^ __LOC__)
1047
              (Buffered (`Capacity 10, `Overflow Drop_head))
1048
          in
1049
          Envelope.Incoming.wrap
1050
            ~data:
1051
              ( Transition_frontier.best_tip weaker_chain.state.frontier
1052
              |> Transition_frontier.Breadcrumb.validated_transition
1053
              |> Mina_block.Validated.to_initial_validated )
1054
            ~sender:
1055
              (Envelope.Sender.Remote
1056
                 (weaker_chain.peer.host, weaker_chain.peer.peer_id))
1057
          |> Pipe_lib.Strict_pipe.Writer.write transition_writer ;
1058
          Envelope.Incoming.wrap
1059
            ~data:
1060
              ( Transition_frontier.best_tip stronger_chain.state.frontier
1061
              |> Transition_frontier.Breadcrumb.validated_transition
1062
              |> Mina_block.Validated.to_initial_validated )
1063
            ~sender:
1064
              (Envelope.Sender.Remote
1065
                 (stronger_chain.peer.host, stronger_chain.peer.peer_id))
1066
          |> Pipe_lib.Strict_pipe.Writer.write transition_writer ;
1067
          let new_frontier, sorted_external_transitions =
1068
            Async.Thread_safe.block_on_async_exn (fun () ->
1069
                run_bootstrap
1070
                  ~timeout_duration:(Block_time.Span.of_ms 60_000L)
1071
                  ~my_net:me ~transition_reader )
1072
          in
1073
          assert_transitions_increasingly_sorted
1074
            ~root:(Transition_frontier.root new_frontier)
1075
            sorted_external_transitions ;
1076
          [%test_result: Ledger_hash.t]
1077
            ( Ledger.Db.merkle_root
1078
            @@ Transition_frontier.root_snarked_ledger new_frontier )
1079
            ~expect:
1080
              ( Ledger.Db.merkle_root
1081
              @@ Transition_frontier.root_snarked_ledger
1082
                   stronger_chain.state.frontier ) )
1083
*)
1084
  end )
192✔
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