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

MinaProtocol / mina / 596

18 Sep 2025 12:10AM UTC coverage: 32.297% (-29.1%) from 61.359%
596

push

buildkite

web-flow
Merge pull request #17790 from MinaProtocol/lyh/various-sig-kind-push-sep15

Various sig kind pushing

1 of 7 new or added lines in 3 files covered. (14.29%)

19286 existing lines in 393 files now uncovered.

23363 of 72339 relevant lines covered (32.3%)

23562.61 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
module Ledger = Mina_ledger.Ledger
6
module Sync_ledger = Mina_ledger.Sync_ledger
7
open Mina_state
8
open Pipe_lib.Strict_pipe
9
open Network_peer
10
module Transition_cache = Transition_cache
11

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

15
  val precomputed_values : Precomputed_values.t
16

17
  val constraint_constants : Genesis_constants.Constraint_constants.t
18

19
  val consensus_constants : Consensus.Constants.t
20

21
  val ledger_sync_config : Syncable_ledger.daemon_config
22

23
  val proof_cache_db : Proof_cache_tag.cache_db
24
end
25

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

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

39
type time = Time.Span.t
40

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

44
type opt_time = time option
45

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

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

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

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

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

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

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

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

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

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

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

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

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

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

271
let download_snarked_ledger ~trust_system ~preferred_peers ~transition_graph
272
    ~sync_ledger_reader ~context t temp_snarked_ledger =
UNCOV
273
  time_deferred
×
274
    (let root_sync_ledger =
275
       Sync_ledger.Root.create temp_snarked_ledger ~context ~trust_system
276
     in
UNCOV
277
     don't_wait_for
×
UNCOV
278
       (sync_ledger t ~preferred:preferred_peers ~root_sync_ledger
×
279
          ~transition_graph ~sync_ledger_reader ) ;
280
     (* We ignore the resulting ledger returned here since it will always
281
        * be the same as the ledger we started with because we are syncing
282
        * a db ledger. *)
UNCOV
283
     let%map _, data = Sync_ledger.Root.valid_tree root_sync_ledger in
×
UNCOV
284
     Sync_ledger.Root.destroy root_sync_ledger ;
×
UNCOV
285
     data )
×
286

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

665
(** The entry point function for bootstrap controller. When bootstrap finished
666
    it would return a transition frontier with the root breadcrumb and a list
667
    of transitions collected during bootstrap.
668

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

706
let%test_module "Bootstrap_controller tests" =
707
  ( module struct
708
    let max_frontier_length =
UNCOV
709
      Transition_frontier.global_max_length Genesis_constants.For_unit_tests.t
×
710

UNCOV
711
    let logger = Logger.null ()
×
712

713
    let () =
714
      (* Disable log messages from best_tip_diff logger. *)
UNCOV
715
      Logger.Consumer_registry.register ~commit_id:""
×
UNCOV
716
        ~id:Logger.Logger_id.best_tip_diff ~processor:(Logger.Processor.raw ())
×
717
        ~transport:
UNCOV
718
          (Logger.Transport.create
×
719
             ( module struct
720
               type t = unit
721

UNCOV
722
               let transport () _ = ()
×
723
             end )
724
             () )
725
        ()
726

727
    let trust_system =
728
      let s = Trust_system.null () in
UNCOV
729
      don't_wait_for
×
UNCOV
730
        (Pipe_lib.Strict_pipe.Reader.iter
×
UNCOV
731
           (Trust_system.upcall_pipe s)
×
UNCOV
732
           ~f:(const Deferred.unit) ) ;
×
UNCOV
733
      s
×
734

UNCOV
735
    let precomputed_values = Lazy.force Precomputed_values.for_unit_tests
×
736

737
    let proof_level = precomputed_values.proof_level
738

739
    let constraint_constants = precomputed_values.constraint_constants
740

741
    let ledger_sync_config =
UNCOV
742
      Syncable_ledger.create_config
×
743
        ~compile_config:Mina_compile_config.For_unit_tests.t
744
        ~max_subtree_depth:None ~default_subtree_depth:None ()
745

746
    module Context = struct
747
      let logger = logger
748

749
      let precomputed_values = precomputed_values
750

751
      let constraint_constants =
752
        Genesis_constants.For_unit_tests.Constraint_constants.t
753

754
      let consensus_constants = precomputed_values.consensus_constants
755

756
      let ledger_sync_config =
UNCOV
757
        Syncable_ledger.create_config
×
758
          ~compile_config:Mina_compile_config.For_unit_tests.t
759
          ~max_subtree_depth:None ~default_subtree_depth:None ()
760

UNCOV
761
      let proof_cache_db = Proof_cache_tag.For_tests.create_db ()
×
762
    end
763

764
    let verifier =
UNCOV
765
      Async.Thread_safe.block_on_async_exn (fun () ->
×
UNCOV
766
          Verifier.For_tests.default ~constraint_constants ~logger ~proof_level
×
767
            () )
768

769
    module Genesis_ledger = (val precomputed_values.genesis_ledger)
770

771
    let downcast_transition ~sender transition =
UNCOV
772
      let transition =
×
UNCOV
773
        transition |> Mina_block.Validated.remember
×
UNCOV
774
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
775
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
776
      in
UNCOV
777
      Envelope.Incoming.wrap ~data:transition
×
778
        ~sender:(Envelope.Sender.Remote sender)
779

780
    let downcast_breadcrumb ~sender breadcrumb =
UNCOV
781
      downcast_transition ~sender
×
UNCOV
782
        (Transition_frontier.Breadcrumb.validated_transition breadcrumb)
×
783

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

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

876
              let compare = external_transition_compare ~context:(module Context)
877
            end
878

879
            include Comparable.Make (T)
880
          end in
UNCOV
881
          [%test_result: E.Set.t]
×
UNCOV
882
            (E.Set.of_list saved_transitions)
×
UNCOV
883
            ~expect:(E.Set.of_list expected_transitions) )
×
884

885
    let run_bootstrap ~timeout_duration ~my_net ~network_transition_pipe =
UNCOV
886
      let open Fake_network in
×
887
      let time_controller = Block_time.Controller.basic ~logger in
888
      let persistent_root =
889
        Transition_frontier.persistent_root my_net.state.frontier
890
      in
UNCOV
891
      let persistent_frontier =
×
892
        Transition_frontier.persistent_frontier my_net.state.frontier
893
      in
UNCOV
894
      let initial_root_transition =
×
895
        Transition_frontier.(
UNCOV
896
          Breadcrumb.validated_transition (root my_net.state.frontier))
×
897
      in
898
      let%bind () =
UNCOV
899
        Transition_frontier.close ~loc:__LOC__ my_net.state.frontier
×
900
      in
UNCOV
901
      [%log info] "bootstrap begin" ;
×
UNCOV
902
      Block_time.Timeout.await_exn time_controller ~timeout_duration
×
903
        (run
904
           ~context:(module Context)
905
           ~trust_system ~verifier ~network:my_net.network ~preferred_peers:[]
906
           ~consensus_local_state:my_net.state.consensus_local_state
907
           ~network_transition_pipe ~persistent_root ~persistent_frontier
908
           ~catchup_mode:`Super ~initial_root_transition
909
           ~signature_kind:Mina_signature_kind.t_DEPRECATED )
910

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

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

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

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