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

MinaProtocol / mina / 1239

31 Mar 2026 12:24PM UTC coverage: 38.104% (-3.7%) from 41.817%
1239

push

buildkite

web-flow
Merge pull request #18591 from MinaProtocol/copilot/fix-error-message-blockchain-verification

0 of 1 new or added line in 1 file covered. (0.0%)

2995 existing lines in 128 files now uncovered.

28619 of 75108 relevant lines covered (38.1%)

51610.03 hits per line

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

0.8
/src/lib/transition_handler/processor.ml
1
(** This module contains the transition processor. The transition processor is
2
 *  the thread in which transitions are attached the to the transition frontier.
3
 *
4
 *  Two types of data are handled by the transition processor: validated external transitions
5
 *  with precomputed state hashes (via the block producer and validator pipes)
6
 *  and breadcrumb rose trees (via the catchup pipe).
7
 *)
8

142✔
9
open Core_kernel
10
open Async_kernel
11
open Pipe_lib.Strict_pipe
12
open Mina_base
13
open Mina_state
14
open Cache_lib
15
open Mina_block
16
open Network_peer
17

18
module type CONTEXT = sig
19
  val logger : Logger.t
20

21
  val precomputed_values : Precomputed_values.t
22

23
  val constraint_constants : Genesis_constants.Constraint_constants.t
24

25
  val consensus_constants : Consensus.Constants.t
26
end
27

28
(* TODO: calculate a sensible value from postake consensus arguments *)
29
let catchup_timeout_duration (precomputed_values : Precomputed_values.t) =
30
  Block_time.Span.of_ms
×
31
    ( (precomputed_values.genesis_constants.protocol.delta + 1)
32
      * precomputed_values.constraint_constants.block_window_duration_ms
33
    |> Int64.of_int )
×
34
  |> Block_time.Span.min (Block_time.Span.of_ms (Int64.of_int 5000))
×
35

36
let cached_transform_deferred_result ~transform_cached ~transform_result cached
37
    =
38
  Cached.transform cached ~f:transform_cached
×
39
  |> Cached.sequence_deferred
×
40
  >>= Fn.compose transform_result Cached.sequence_result
×
41

42
(* add a breadcrumb and perform post processing *)
43
let add_and_finalize ~logger ~frontier ~catchup_scheduler
44
    ~processed_transition_writer ~only_if_present ~time_controller ~source
45
    ~valid_cb cached_breadcrumb ~(precomputed_values : Precomputed_values.t) =
46
  let module Inclusion_time = Mina_metrics.Block_latency.Inclusion_time in
×
47
  let breadcrumb =
48
    if Cached.is_pure cached_breadcrumb then Cached.peek cached_breadcrumb
×
49
    else Cached.invalidate_with_success cached_breadcrumb
×
50
  in
51
  let consensus_constants = precomputed_values.consensus_constants in
52
  let transition =
53
    Transition_frontier.Breadcrumb.validated_transition breadcrumb
54
  in
55
  [%log debug] "add_and_finalize $state_hash %s callback"
×
56
    ~metadata:
57
      [ ( "state_hash"
58
        , Transition_frontier.Breadcrumb.state_hash breadcrumb
×
59
          |> State_hash.to_yojson )
×
60
      ]
61
    (Option.value_map valid_cb ~default:"without" ~f:(const "with")) ;
×
62
  let state_hash = Transition_frontier.Breadcrumb.state_hash breadcrumb in
×
63
  Internal_tracing.with_state_hash state_hash
×
64
  @@ fun () ->
65
  [%log internal] "Add_and_finalize" ;
×
66
  let%map () =
67
    if only_if_present then (
×
68
      let parent_hash = Transition_frontier.Breadcrumb.parent_hash breadcrumb in
69
      match Transition_frontier.find frontier parent_hash with
×
70
      | Some _ ->
×
71
          Transition_frontier.add_breadcrumb_exn frontier breadcrumb
×
72
      | None ->
×
73
          [%log internal] "Parent_breadcrumb_not_found" ;
×
74
          [%log warn]
×
75
            !"When trying to add breadcrumb, its parent had been removed from \
×
76
              transition frontier: %{sexp: State_hash.t}"
77
            parent_hash ;
78
          Deferred.unit )
×
79
    else Transition_frontier.add_breadcrumb_exn frontier breadcrumb
×
80
  in
81
  ( match source with
×
82
  | `Internal ->
×
83
      ()
84
  | _ ->
×
85
      let transition_time =
86
        transition |> Mina_block.Validated.header
×
87
        |> Mina_block.Header.protocol_state |> Protocol_state.consensus_state
×
88
        |> Consensus.Data.Consensus_state.consensus_time
89
      in
90
      let time_elapsed =
×
91
        Block_time.diff
92
          (Block_time.now time_controller)
×
93
          (Consensus.Data.Consensus_time.to_time ~constants:consensus_constants
×
94
             transition_time )
95
      in
96
      Inclusion_time.update (Block_time.Span.to_time_span time_elapsed) ) ;
×
97
  [%log internal] "Add_and_finalize_done" ;
×
98
  if Writer.is_closed processed_transition_writer then
×
99
    Or_error.error_string "processed transitions closed"
×
100
  else (
×
101
    Writer.write processed_transition_writer
102
      (`Transition transition, `Source source, `Valid_cb valid_cb) ;
103
    Catchup_scheduler.notify catchup_scheduler
×
104
      ~hash:(Mina_block.Validated.state_hash transition) )
×
105

106
let process_transition ~context:(module Context : CONTEXT) ~trust_system
107
    ~verifier ~get_completed_work ~frontier ~catchup_scheduler
108
    ~processed_transition_writer ~time_controller ~block_or_header ~valid_cb
109
    ?transaction_pool_proxy =
UNCOV
110
  let is_block_in_frontier =
×
UNCOV
111
    Fn.compose Option.is_some @@ Transition_frontier.find frontier
×
112
  in
UNCOV
113
  let open Context in
×
114
  let header, transition_hash, transition_receipt_time, sender, validation =
115
    match block_or_header with
UNCOV
116
    | `Block cached_env ->
×
117
        let env = Cached.peek cached_env in
UNCOV
118
        let block, v = Envelope.Incoming.data env in
×
UNCOV
119
        ( Mina_block.header @@ With_hash.data block
×
UNCOV
120
        , State_hash.With_state_hashes.state_hash block
×
UNCOV
121
        , Some (Envelope.Incoming.received_at env)
×
UNCOV
122
        , Envelope.Incoming.sender env
×
123
        , v )
124
    | `Header env ->
×
125
        let h, v = Envelope.Incoming.data env in
126
        ( With_hash.data h
×
127
        , State_hash.With_state_hashes.state_hash h
×
128
        , Some (Envelope.Incoming.received_at env)
×
129
        , Envelope.Incoming.sender env
×
130
        , v )
131
  in
132
  let parent_hash =
UNCOV
133
    Protocol_state.previous_state_hash (Header.protocol_state header)
×
134
  in
UNCOV
135
  let root_consensus_state =
×
136
    Transition_frontier.(
UNCOV
137
      Breadcrumb.consensus_state_with_hashes @@ root frontier)
×
138
  in
UNCOV
139
  let metadata = [ ("state_hash", State_hash.to_yojson transition_hash) ] in
×
140
  let state_hash = transition_hash in
141
  Internal_tracing.with_state_hash state_hash
142
  @@ fun () ->
UNCOV
143
  [%log internal] "@block_metadata"
×
144
    ~metadata:
145
      [ ( "blockchain_length"
UNCOV
146
        , Mina_numbers.Length.to_yojson (Header.blockchain_length header) )
×
147
      ] ;
UNCOV
148
  [%log internal] "Begin_external_block_processing" ;
×
UNCOV
149
  let handle_not_selected () =
×
150
    [%log internal] "Failure"
×
151
      ~metadata:[ ("reason", `String "Not_selected_over_frontier_root") ] ;
152
    Trust_system.record_envelope_sender trust_system logger sender
×
153
      ( Trust_system.Actions.Gossiped_invalid_transition
154
      , Some
155
          ( "The transition with hash $state_hash was not selected over the \
156
             transition frontier root"
157
          , metadata ) )
158
  in
159
  match block_or_header with
160
  | `Header env -> (
×
161
      let header_with_hash, _ = Envelope.Incoming.data env in
162
      [%log internal] "Validate_frontier_dependencies" ;
×
163
      match
×
164
        Mina_block.Validation.validate_frontier_dependencies
165
          ~context:(module Context)
166
          ~root_consensus_state ~is_block_in_frontier ~to_header:ident
167
          (Envelope.Incoming.data env)
×
168
      with
169
      | Ok _ | Error `Parent_missing_from_frontier ->
×
170
          [%log internal] "Schedule_catchup" ;
×
171
          Catchup_scheduler.watch_header catchup_scheduler ~valid_cb
×
172
            ~header_with_hash ;
173
          return ()
×
174
      | Error `Not_selected_over_frontier_root ->
×
175
          handle_not_selected ()
176
      | Error `Already_in_frontier ->
×
177
          [%log internal] "Failure"
×
178
            ~metadata:[ ("reason", `String "Already_in_frontier") ] ;
179
          [%log warn] ~metadata
×
180
            "Refusing to process the transition with hash $state_hash because \
181
             it is already in the transition frontier" ;
182
          return () )
×
UNCOV
183
  | `Block cached_initially_validated_transition ->
×
184
      Deferred.ignore_m
185
      @@
186
      let open Deferred.Result.Let_syntax in
187
      let%bind mostly_validated_transition =
188
        let open Deferred.Let_syntax in
189
        let initially_validated_transition =
UNCOV
190
          Cached.peek cached_initially_validated_transition
×
191
          |> Envelope.Incoming.data
192
        in
UNCOV
193
        [%log internal] "Validate_frontier_dependencies" ;
×
UNCOV
194
        match
×
195
          Mina_block.Validation.validate_frontier_dependencies
196
            ~context:(module Context)
197
            ~root_consensus_state ~is_block_in_frontier
198
            ~to_header:Mina_block.header initially_validated_transition
199
        with
200
        | Ok t ->
×
201
            return (Ok t)
×
202
        | Error `Not_selected_over_frontier_root ->
×
203
            let (_ : Mina_block.initial_valid_block Envelope.Incoming.t) =
204
              Cached.invalidate_with_failure
205
                cached_initially_validated_transition
206
            in
207
            let%map () = handle_not_selected () in
×
208
            Error ()
×
UNCOV
209
        | Error `Already_in_frontier ->
×
UNCOV
210
            [%log internal] "Failure"
×
211
              ~metadata:[ ("reason", `String "Already_in_frontier") ] ;
UNCOV
212
            [%log warn] ~metadata
×
213
              "Refusing to process the transition with hash $state_hash \
214
               because is is already in the transition frontier" ;
UNCOV
215
            let (_ : Mina_block.initial_valid_block Envelope.Incoming.t) =
×
216
              Cached.invalidate_with_failure
217
                cached_initially_validated_transition
218
            in
UNCOV
219
            return (Error ())
×
220
        | Error `Parent_missing_from_frontier -> (
×
221
            [%log internal] "Schedule_catchup" ;
×
222
            match validation with
×
223
            | ( _
×
224
              , _
225
              , _
226
              , (`Delta_block_chain, Mina_stdlib.Truth.True delta_state_hashes)
227
              , _
228
              , _
229
              , _ ) ->
230
                let timeout_duration =
231
                  Option.fold
232
                    (Transition_frontier.find frontier
×
233
                       (Mina_stdlib.Nonempty_list.head delta_state_hashes) )
×
234
                    ~init:(Block_time.Span.of_ms 0L)
×
235
                    ~f:(fun _ _ -> catchup_timeout_duration precomputed_values)
×
236
                in
237
                Catchup_scheduler.watch catchup_scheduler ~timeout_duration
×
238
                  ~cached_transition:cached_initially_validated_transition
239
                  ~valid_cb ;
240
                return (Error ()) )
×
241
      in
242
      (* TODO: only access parent in transition frontier once (already done in call to validate dependencies) #2485 *)
243
      [%log internal] "Find_parent_breadcrumb" ;
×
244
      let%bind parent_breadcrumb =
245
        match Transition_frontier.find frontier parent_hash with
246
        | None ->
×
247
            (* Unexpected case: if it happens, there is a bug somewhere. Still,
248
               we should attempt to handle it gracefully. *)
249
            [%log internal] "Failure"
×
250
              ~metadata:[ ("reason", `String "Parent_missing_from_frontier") ] ;
251
            [%log error] ~metadata
×
252
              "Refusing to process the transition with hash $state_hash \
253
               because parent is missing from the transition frontier \
254
               (unexpected case, there is likely a bug somewhere)" ;
255
            let (_ : Mina_block.initial_valid_block Envelope.Incoming.t) =
×
256
              Cached.invalidate_with_failure
257
                cached_initially_validated_transition
258
            in
259
            Deferred.return (Error ())
×
260
        | Some x ->
×
261
            return x
×
262
      in
263
      let%bind breadcrumb =
264
        cached_transform_deferred_result cached_initially_validated_transition
×
265
          ~transform_cached:(fun _ ->
266
            Transition_frontier.Breadcrumb.build ~logger ~precomputed_values
×
267
              ~verifier ~get_completed_work ~trust_system
268
              ~transition_receipt_time ~sender:(Some sender)
269
              ~parent:parent_breadcrumb ~transition:mostly_validated_transition
270
              ?transaction_pool_proxy (* TODO: Can we skip here? *) () )
271
          ~transform_result:(function
272
            | Error (`Invalid_staged_ledger_hash error)
×
273
            | Error (`Invalid_staged_ledger_diff error) ->
×
274
                Internal_tracing.with_state_hash state_hash
275
                @@ fun () ->
276
                [%log internal] "Failure"
×
277
                  ~metadata:[ ("reason", `String (Error.to_string_hum error)) ] ;
×
278
                [%log error]
×
279
                  ~metadata:
280
                    (metadata @ [ ("error", Error_json.error_to_yojson error) ])
×
281
                  "Error while building breadcrumb in the transition handler \
282
                   processor: $error" ;
283
                Deferred.return (Error ())
×
284
            | Error (`Fatal_error exn) ->
×
285
                Internal_tracing.with_state_hash state_hash
286
                @@ fun () ->
287
                [%log internal] "Failure"
×
288
                  ~metadata:[ ("reason", `String "Fatal error") ] ;
289
                raise exn
×
290
            | Ok breadcrumb ->
×
291
                Deferred.return (Ok breadcrumb) )
292
      in
293
      Mina_metrics.(
×
294
        Counter.inc_one
×
295
          Transition_frontier_controller.breadcrumbs_built_by_processor) ;
296
      let%map.Deferred result =
297
        add_and_finalize ~logger ~frontier ~catchup_scheduler
×
298
          ~processed_transition_writer ~only_if_present:false ~time_controller
299
          ~source:`Gossip breadcrumb ~precomputed_values ~valid_cb
300
      in
301
      ( match result with
×
302
      | Ok () ->
×
303
          [%log internal] "Breadcrumb_integrated"
×
304
      | Error err ->
×
305
          [%log internal] "Failure"
×
306
            ~metadata:[ ("reason", `String (Error.to_string_hum err)) ] ) ;
×
307
      Result.return result
308

309
let run ~context:(module Context : CONTEXT) ~verifier ~trust_system
310
    ~time_controller ~frontier ~get_completed_work
311
    ~(primary_transition_reader :
312
       ( [ `Block of
313
           ( Mina_block.initial_valid_block Envelope.Incoming.t
314
           , State_hash.t )
315
           Cached.t
316
         | `Header of Mina_block.initial_valid_header Envelope.Incoming.t ]
317
       * [ `Valid_cb of Mina_net2.Validation_callback.t option ] )
318
       Reader.t )
319
    ~(producer_transition_reader : Transition_frontier.Breadcrumb.t Reader.t)
320
    ~(clean_up_catchup_scheduler : unit Ivar.t) ~catchup_job_writer
321
    ~(catchup_breadcrumbs_reader :
322
       ( ( (Transition_frontier.Breadcrumb.t, State_hash.t) Cached.t
323
         * Mina_net2.Validation_callback.t option )
324
         Mina_stdlib.Rose_tree.t
325
         list
326
       * [ `Ledger_catchup of unit Ivar.t | `Catchup_scheduler ] )
327
       Reader.t )
328
    ~(catchup_breadcrumbs_writer :
329
       ( ( (Transition_frontier.Breadcrumb.t, State_hash.t) Cached.t
330
         * Mina_net2.Validation_callback.t option )
331
         Mina_stdlib.Rose_tree.t
332
         list
333
         * [ `Ledger_catchup of unit Ivar.t | `Catchup_scheduler ]
334
       , crash buffered
335
       , unit )
336
       Writer.t ) ~processed_transition_writer ?transaction_pool_proxy =
UNCOV
337
  let open Context in
×
338
  let catchup_scheduler =
339
    Catchup_scheduler.create ~logger ~precomputed_values ~verifier ~trust_system
340
      ~frontier ~time_controller ~catchup_job_writer ~catchup_breadcrumbs_writer
341
      ~clean_up_signal:clean_up_catchup_scheduler
342
  in
343
  let add_and_finalize =
344
    add_and_finalize ~frontier ~catchup_scheduler ~processed_transition_writer
345
      ~time_controller ~precomputed_values
346
  in
347
  let process_transition =
348
    process_transition
349
      ~context:(module Context)
350
      ~get_completed_work ~trust_system ~verifier ~frontier ~catchup_scheduler
351
      ~processed_transition_writer ~time_controller
352
  in
353
  O1trace.background_thread "process_blocks" (fun () ->
UNCOV
354
      Reader.Merge.iter
×
355
        (* It is fine to skip the cache layer on blocks produced by this node
356
           * because it is extraordinarily unlikely we would write an internal bug
357
           * triggering this case, and the external case (where we received an
358
           * identical external transition from the network) can happen iff there
359
           * is another node with the exact same private key and view of the
360
           * transaction pool. *)
UNCOV
361
        [ Reader.map producer_transition_reader ~f:(fun breadcrumb ->
×
362
              Mina_metrics.(
×
363
                Gauge.inc_one
×
364
                  Transition_frontier_controller.transitions_being_processed) ;
365
              `Local_breadcrumb (Cached.pure breadcrumb) )
×
UNCOV
366
        ; Reader.map catchup_breadcrumbs_reader
×
367
            ~f:(fun (cb, catchup_breadcrumbs_callback) ->
368
              `Catchup_breadcrumbs (cb, catchup_breadcrumbs_callback) )
×
UNCOV
369
        ; Reader.map primary_transition_reader ~f:(fun vt ->
×
UNCOV
370
              `Partially_valid_transition vt )
×
371
        ]
372
        ~f:(fun msg ->
UNCOV
373
          let open Deferred.Let_syntax in
×
374
          O1trace.thread "transition_handler_processor" (fun () ->
UNCOV
375
              match msg with
×
376
              | `Catchup_breadcrumbs
×
377
                  (breadcrumb_subtrees, subsequent_callback_action) -> (
378
                  ( match%map
379
                      Deferred.Or_error.List.iter breadcrumb_subtrees
×
380
                        ~f:(fun subtree ->
381
                          Mina_stdlib.Rose_tree.Deferred.Or_error.iter
×
382
                            subtree
383
                            (* It could be the case that by the time we try and
384
                               * add the breadcrumb, it's no longer relevant when
385
                               * we're catching up *) ~f:(fun (b, valid_cb) ->
386
                              let state_hash =
×
387
                                Frontier_base.Breadcrumb.state_hash
388
                                  (Cached.peek b)
×
389
                              in
390
                              let%map result =
391
                                add_and_finalize ~logger ~only_if_present:true
×
392
                                  ~source:`Catchup ~valid_cb b
393
                              in
394
                              Internal_tracing.with_state_hash state_hash
×
395
                              @@ fun () ->
396
                              ( match result with
×
397
                              | Error err ->
×
398
                                  [%log internal] "Failure"
×
399
                                    ~metadata:
400
                                      [ ( "reason"
401
                                        , `String (Error.to_string_hum err) )
×
402
                                      ]
403
                              | Ok () ->
×
404
                                  [%log internal] "Breadcrumb_integrated" ) ;
×
405
                              result ) )
406
                    with
407
                  | Ok () ->
×
408
                      ()
409
                  | Error err ->
×
410
                      List.iter breadcrumb_subtrees ~f:(fun tree ->
411
                          Mina_stdlib.Rose_tree.iter tree
×
412
                            ~f:(fun (cached_breadcrumb, _vc) ->
413
                              let (_ : Transition_frontier.Breadcrumb.t) =
×
414
                                Cached.invalidate_with_failure cached_breadcrumb
415
                              in
416
                              () ) ) ;
×
417
                      [%log error]
×
418
                        "Error, failed to attach all catchup breadcrumbs to \
419
                         transition frontier: $error"
420
                        ~metadata:[ ("error", Error_json.error_to_yojson err) ]
×
421
                  )
422
                  >>| fun () ->
423
                  match subsequent_callback_action with
×
424
                  | `Ledger_catchup decrement_signal ->
×
425
                      if Ivar.is_full decrement_signal then
426
                        [%log error] "Ivar.fill bug is here!" ;
×
427
                      Ivar.fill decrement_signal ()
×
428
                  | `Catchup_scheduler ->
×
429
                      () )
430
              | `Local_breadcrumb breadcrumb ->
×
431
                  let state_hash =
432
                    Transition_frontier.Breadcrumb.validated_transition
×
433
                      (Cached.peek breadcrumb)
×
434
                    |> Mina_block.Validated.state_hash
435
                  in
436
                  Internal_tracing.with_state_hash state_hash
×
437
                  @@ fun () ->
438
                  [%log internal] "Begin_local_block_processing" ;
×
439
                  let transition_time =
×
440
                    Transition_frontier.Breadcrumb.validated_transition
×
441
                      (Cached.peek breadcrumb)
×
442
                    |> Mina_block.Validated.header
×
443
                    |> Mina_block.Header.protocol_state
×
444
                    |> Protocol_state.blockchain_state
×
445
                    |> Blockchain_state.timestamp |> Block_time.to_time_exn
×
446
                  in
447
                  Perf_histograms.add_span
×
448
                    ~name:"accepted_transition_local_latency"
449
                    (Core_kernel.Time.diff
×
450
                       Block_time.(now time_controller |> to_time_exn)
×
451
                       transition_time ) ;
452
                  let%map () =
453
                    match%map
454
                      add_and_finalize ~logger ~only_if_present:false
×
455
                        ~source:`Internal breadcrumb ~valid_cb:None
456
                    with
457
                    | Ok () ->
×
458
                        [%log internal] "Breadcrumb_integrated" ;
×
459
                        ()
×
460
                    | Error err ->
×
461
                        [%log internal] "Failure"
×
462
                          ~metadata:
463
                            [ ("reason", `String (Error.to_string_hum err)) ] ;
×
464
                        [%log error]
×
465
                          ~metadata:
466
                            [ ("error", Error_json.error_to_yojson err) ]
×
467
                          "Error, failed to attach produced breadcrumb to \
468
                           transition frontier: $error" ;
469
                        let (_ : Transition_frontier.Breadcrumb.t) =
×
470
                          Cached.invalidate_with_failure breadcrumb
471
                        in
472
                        ()
×
473
                  in
474
                  Mina_metrics.(
×
475
                    Gauge.dec_one
476
                      Transition_frontier_controller.transitions_being_processed)
UNCOV
477
              | `Partially_valid_transition (block_or_header, `Valid_cb valid_cb)
×
478
                ->
479
                  process_transition ~block_or_header ~valid_cb
480
                    ?transaction_pool_proxy ) ) )
481

482
let%test_module "Transition_handler.Processor tests" =
483
  ( module struct
484
    open Async
485
    open Pipe_lib
486

487
    let () =
488
      Backtrace.elide := false ;
489
      Printexc.record_backtrace true ;
490
      Async.Scheduler.set_record_backtraces true
×
491

492
    let logger = Logger.null ()
×
493

494
    let () =
495
      (* Disable log messages from best_tip_diff logger. *)
496
      Logger.Consumer_registry.register ~commit_id:""
×
497
        ~id:Logger.Logger_id.best_tip_diff ~processor:(Logger.Processor.raw ())
×
498
        ~transport:
499
          (Logger.Transport.create
×
500
             ( module struct
501
               type t = unit
502

503
               let transport () _ = ()
×
504
             end )
505
             () )
506
        ()
507

508
    let precomputed_values = Lazy.force Precomputed_values.for_unit_tests
×
509

510
    let proof_level = precomputed_values.proof_level
511

512
    let constraint_constants = precomputed_values.constraint_constants
513

514
    let time_controller = Block_time.Controller.basic ~logger
515

516
    let trust_system = Trust_system.null ()
×
517

518
    let verifier =
519
      Async.Thread_safe.block_on_async_exn (fun () ->
×
520
          Verifier.For_tests.default ~constraint_constants ~logger ~proof_level
×
521
            () )
522

523
    module Context = struct
524
      let logger = logger
525

526
      let precomputed_values = precomputed_values
527

528
      let constraint_constants = constraint_constants
529

530
      let consensus_constants = precomputed_values.consensus_constants
531
    end
532

533
    let downcast_breadcrumb breadcrumb =
534
      let transition =
×
535
        Transition_frontier.Breadcrumb.validated_transition breadcrumb
×
536
        |> Mina_block.Validated.remember
×
537
        |> Mina_block.Validation.reset_frontier_dependencies_validation
×
538
        |> Mina_block.Validation.reset_staged_ledger_diff_validation
539
      in
540
      Envelope.Incoming.wrap ~data:transition ~sender:Envelope.Sender.Local
×
541

542
    let%test_unit "adding transitions whose parents are in the frontier" =
543
      let frontier_size = 1 in
×
544
      let branch_size = 10 in
545
      let max_length = frontier_size + branch_size in
546
      Quickcheck.test ~trials:4
547
        (Transition_frontier.For_tests.gen_with_branch ~precomputed_values
×
548
           ~verifier ~max_length ~frontier_size ~branch_size () )
549
        ~f:(fun (frontier, branch) ->
550
          assert (
×
551
            Thread_safe.block_on_async_exn (fun () ->
×
552
                let valid_transition_reader, valid_transition_writer =
×
553
                  Strict_pipe.create
554
                    (Buffered
555
                       (`Capacity branch_size, `Overflow (Drop_head ignore)) )
556
                in
557
                let producer_transition_reader, _ =
×
558
                  Strict_pipe.create
559
                    (Buffered
560
                       (`Capacity branch_size, `Overflow (Drop_head ignore)) )
561
                in
562
                let _, catchup_job_writer =
×
563
                  Strict_pipe.create (Buffered (`Capacity 1, `Overflow Crash))
564
                in
565
                let catchup_breadcrumbs_reader, catchup_breadcrumbs_writer =
×
566
                  Strict_pipe.create (Buffered (`Capacity 1, `Overflow Crash))
567
                in
568
                let processed_transition_reader, processed_transition_writer =
×
569
                  Strict_pipe.create
570
                    (Buffered
571
                       (`Capacity branch_size, `Overflow (Drop_head ignore)) )
572
                in
573
                let clean_up_catchup_scheduler = Ivar.create () in
×
574
                let cache =
×
575
                  Unprocessed_transition_cache.create ~logger
576
                    ~cache_exceptions:true
577
                in
578
                run
579
                  ~context:(module Context)
580
                  ~time_controller ~verifier ~get_completed_work:(Fn.const None)
×
581
                  ~trust_system ~clean_up_catchup_scheduler ~frontier
582
                  ~primary_transition_reader:valid_transition_reader
583
                  ~producer_transition_reader ~catchup_job_writer
584
                  ~catchup_breadcrumbs_reader ~catchup_breadcrumbs_writer
585
                  ~processed_transition_writer ?transaction_pool_proxy:None ;
586
                List.iter branch ~f:(fun breadcrumb ->
587
                    let b =
×
588
                      downcast_breadcrumb breadcrumb
×
589
                      |> Unprocessed_transition_cache.register_exn cache
590
                    in
591
                    Strict_pipe.Writer.write valid_transition_writer
×
592
                      (`Block b, `Valid_cb None) ) ;
593
                match%map
594
                  Block_time.Timeout.await
×
595
                    ~timeout_duration:(Block_time.Span.of_ms 30000L)
×
596
                    time_controller
597
                    (Strict_pipe.Reader.fold_until processed_transition_reader
×
598
                       ~init:branch
599
                       ~f:(fun
600
                            remaining_breadcrumbs
601
                            (`Transition newly_added_transition, _, _)
602
                          ->
603
                         Deferred.return
×
604
                           ( match remaining_breadcrumbs with
605
                           | next_expected_breadcrumb :: tail ->
×
606
                               [%test_eq: State_hash.t]
×
607
                                 (Transition_frontier.Breadcrumb.state_hash
×
608
                                    next_expected_breadcrumb )
609
                                 (Mina_block.Validated.state_hash
×
610
                                    newly_added_transition ) ;
611
                               [%log info]
×
612
                                 ~metadata:
613
                                   [ ( "height"
614
                                     , `Int
615
                                         ( newly_added_transition
616
                                         |> Mina_block.Validated.forget
×
617
                                         |> With_hash.data |> Mina_block.header
×
618
                                         |> Mina_block.Header.protocol_state
×
619
                                         |> Protocol_state.consensus_state
×
620
                                         |> Consensus.Data.Consensus_state
621
                                            .blockchain_length
×
622
                                         |> Mina_numbers.Length.to_uint32
×
623
                                         |> Unsigned.UInt32.to_int ) )
×
624
                                   ]
625
                                 "transition of $height passed processor" ;
626
                               if List.is_empty tail then `Stop true
×
627
                               else `Continue tail
×
628
                           | [] ->
×
629
                               `Stop false ) ) )
630
                with
631
                | `Timeout ->
×
632
                    failwith "test timed out"
633
                | `Ok (`Eof _) ->
×
634
                    failwith "pipe closed unexpectedly"
635
                | `Ok (`Terminated x) ->
×
636
                    x ) ) )
637
  end )
284✔
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