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

MinaProtocol / mina / 3001

01 Dec 2024 06:25PM UTC coverage: 36.257% (-24.4%) from 60.697%
3001

push

buildkite

web-flow
Merge pull request #16393 from leopardracer/patch-1

fix: typos in documentation files

25609 of 70631 relevant lines covered (36.26%)

27168.12 hits per line

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

3.08
/src/lib/transition_handler/validator.ml
1
open Async_kernel
5✔
2
open Core_kernel
3
open Pipe_lib.Strict_pipe
4
open Mina_base
5
open Mina_state
6
open Mina_block
7
open Network_peer
8

9
module type CONTEXT = sig
10
  val logger : Logger.t
11

12
  val precomputed_values : Precomputed_values.t
13

14
  val constraint_constants : Genesis_constants.Constraint_constants.t
15

16
  val consensus_constants : Consensus.Constants.t
17
end
18

19
let validate_header_is_relevant ~context:(module Context : CONTEXT) ~frontier
20
    ~slot_chain_end header_with_hash =
21
  let open Result.Let_syntax in
×
22
  let module Context = struct
23
    include Context
24

25
    let compile_config = precomputed_values.compile_config
26

27
    let logger =
28
      Logger.extend logger
×
29
        [ ("selection_context", `String "Transition_handler.Validator") ]
30
  end in
31
  let transition_hash =
32
    State_hash.With_state_hashes.state_hash header_with_hash
33
  in
34
  [%log' internal Context.logger] "Validate_transition" ;
×
35
  let get_consensus_constants h =
×
36
    Mina_block.Header.protocol_state h |> Protocol_state.consensus_state
×
37
  in
38
  let header = With_hash.data header_with_hash in
39
  let block_slot =
×
40
    Consensus.Data.Consensus_state.curr_global_slot
41
    @@ Protocol_state.consensus_state
×
42
    @@ Header.protocol_state header
×
43
  in
44
  let%bind () =
45
    match slot_chain_end with
46
    | Some slot_chain_end
×
47
      when Mina_numbers.Global_slot_since_hard_fork.(
48
             block_slot >= slot_chain_end) ->
49
        [%log' internal Context.logger] "Block after slot_chain_end, rejecting" ;
×
50
        Result.fail `Block_after_after_stop_slot
×
51
    | None | Some _ ->
×
52
        Result.return ()
×
53
  in
54
  let blockchain_length = Mina_block.Header.blockchain_length header in
×
55
  let root_breadcrumb = Transition_frontier.root frontier in
×
56
  [%log' internal Context.logger] "@block_metadata"
×
57
    ~metadata:
58
      [ ("blockchain_length", Mina_numbers.Length.to_yojson blockchain_length) ] ;
×
59
  [%log' internal Context.logger] "Check_transition_not_in_frontier" ;
×
60
  let open Result.Let_syntax in
×
61
  let%bind () =
62
    Option.fold
×
63
      (Transition_frontier.find frontier transition_hash)
×
64
      ~init:Result.(Ok ())
65
      ~f:(fun _ _ -> Result.Error (`In_frontier transition_hash))
×
66
  in
67
  [%log' internal Context.logger] "Check_transition_can_be_connected" ;
×
68
  Result.ok_if_true
×
69
    (Consensus.Hooks.equal_select_status `Take
×
70
       (Consensus.Hooks.select
71
          ~context:(module Context)
72
          ~existing:
73
            (Transition_frontier.Breadcrumb.consensus_state_with_hashes
×
74
               root_breadcrumb )
75
          ~candidate:(With_hash.map ~f:get_consensus_constants header_with_hash) ) )
×
76
    ~error:`Disconnected
77

78
let validate_transition_is_relevant ~context:(module Context : CONTEXT)
79
    ~frontier ~unprocessed_transition_cache ~slot_tx_end ~slot_chain_end
80
    enveloped_transition =
81
  let open Result.Let_syntax in
×
82
  [%log' internal Context.logger] "Validate_transition" ;
×
83
  let transition =
×
84
    Envelope.Incoming.data enveloped_transition
×
85
    |> Mina_block.Validation.block_with_hash
86
  in
87
  let transition_data = With_hash.data transition in
×
88
  let block_slot =
×
89
    Consensus.Data.Consensus_state.curr_global_slot
90
    @@ Protocol_state.consensus_state @@ Header.protocol_state
×
91
    @@ Mina_block.header transition_data
×
92
  in
93
  let%bind () =
94
    match slot_tx_end with
95
    | Some slot_tx_end
×
96
      when Mina_numbers.Global_slot_since_hard_fork.(block_slot >= slot_tx_end)
97
      ->
98
        [%log' internal Context.logger]
×
99
          "Block after slot_tx_end, validating it is empty" ;
100
        let staged_ledger_diff =
×
101
          Body.staged_ledger_diff @@ body transition_data
×
102
        in
103
        Result.ok_if_true
×
104
          ( Staged_ledger_diff.compare Staged_ledger_diff.empty_diff
×
105
              staged_ledger_diff
106
          = 0 )
107
          ~error:`Non_empty_staged_ledger_diff_after_stop_slot
108
    | None | Some _ ->
×
109
        Result.(Ok ())
110
  in
111
  [%log' internal Context.logger] "Check_transition_not_in_process" ;
×
112
  let%bind () =
113
    Option.fold
×
114
      (Unprocessed_transition_cache.final_state unprocessed_transition_cache
×
115
         enveloped_transition )
116
      ~init:Result.(Ok ())
117
      ~f:(fun _ final_state -> Result.Error (`In_process final_state))
×
118
  in
119
  let header_with_hash = With_hash.map ~f:Mina_block.header transition in
×
120
  let%map () =
121
    validate_header_is_relevant
×
122
      ~context:(module Context)
123
      ~frontier ~slot_chain_end header_with_hash
124
  in
125
  [%log' internal Context.logger] "Register_transition_for_processing" ;
×
126
  (* we expect this to be Ok since we just checked the cache *)
127
  Unprocessed_transition_cache.register_exn unprocessed_transition_cache
×
128
    enveloped_transition
129

130
let validate_transition_or_header_is_relevant
131
    ~context:(module Context : CONTEXT) ~slot_tx_end ~slot_chain_end ~frontier
132
    ~unprocessed_transition_cache b_or_h =
133
  match b_or_h with
×
134
  | `Block b ->
×
135
      Result.map ~f:(fun cached_block -> `Block cached_block)
×
136
      @@ validate_transition_is_relevant
×
137
           ~context:(module Context)
138
           ~slot_tx_end ~slot_chain_end ~frontier ~unprocessed_transition_cache
139
           b
140
  | `Header h ->
×
141
      let header_with_hash, _ = Envelope.Incoming.data h in
142
      Result.map ~f:(fun () -> `Header h)
×
143
      @@ validate_header_is_relevant
×
144
           ~context:(module Context)
145
           ~slot_chain_end ~frontier header_with_hash
146

147
let run ~context:(module Context : CONTEXT) ~trust_system ~time_controller
148
    ~frontier ~transition_reader ~valid_transition_writer
149
    ~unprocessed_transition_cache =
150
  let open Context in
6✔
151
  let module Lru = Core_extended_cache.Lru in
152
  let outdated_root_cache = Lru.create ~destruct:None 1000 in
153
  O1trace.background_thread "validate_blocks_against_frontier" (fun () ->
6✔
154
      Reader.iter transition_reader ~f:(fun (b_or_h, `Valid_cb vc) ->
6✔
155
          let header_with_hash, sender =
×
156
            match b_or_h with
157
            | `Block b ->
×
158
                let block_with_hash, _ = Envelope.Incoming.data b in
159
                ( With_hash.map ~f:Mina_block.header block_with_hash
×
160
                , Envelope.Incoming.sender b )
×
161
            | `Header h ->
×
162
                let header_with_hash, _ = Envelope.Incoming.data h in
163
                (header_with_hash, Envelope.Incoming.sender h)
×
164
          in
165
          let header = With_hash.data header_with_hash in
166
          let transition_hash =
×
167
            State_hash.With_state_hashes.state_hash header_with_hash
168
          in
169
          Internal_tracing.Context_call.with_call_id
×
170
            ~tag:"transition_handler_validator"
171
          @@ fun () ->
172
          Internal_tracing.with_state_hash transition_hash
×
173
          @@ fun () ->
174
          let slot_tx_end =
×
175
            Runtime_config.slot_tx_end
176
              precomputed_values.Precomputed_values.runtime_config
177
          in
178
          let slot_chain_end =
×
179
            Runtime_config.slot_chain_end precomputed_values.runtime_config
180
          in
181
          match
×
182
            validate_transition_or_header_is_relevant
183
              ~context:(module Context)
184
              ~frontier ~unprocessed_transition_cache ~slot_tx_end
185
              ~slot_chain_end b_or_h
186
          with
187
          | Ok b_or_h' ->
×
188
              let%map () =
189
                Trust_system.record_envelope_sender trust_system logger sender
×
190
                  ( Trust_system.Actions.Sent_useful_gossip
191
                  , Some
192
                      ( "external transition $state_hash"
193
                      , [ ("state_hash", State_hash.to_yojson transition_hash)
×
194
                        ; ("header", Mina_block.Header.to_yojson header)
×
195
                        ] ) )
196
              in
197
              let transition_time =
×
198
                Mina_block.Header.protocol_state header
×
199
                |> Protocol_state.blockchain_state |> Blockchain_state.timestamp
×
200
                |> Block_time.to_time_exn
201
              in
202
              Perf_histograms.add_span
×
203
                ~name:"accepted_transition_remote_latency"
204
                (Core_kernel.Time.diff
×
205
                   Block_time.(now time_controller |> to_time_exn)
×
206
                   transition_time ) ;
207
              [%log internal] "Validate_transition_done" ;
×
208
              Writer.write valid_transition_writer (b_or_h', `Valid_cb vc)
×
209
          | Error (`In_frontier _) | Error (`In_process _) ->
×
210
              [%log internal] "Failure"
×
211
                ~metadata:[ ("reason", `String "In_frontier or In_process") ] ;
212
              Trust_system.record_envelope_sender trust_system logger sender
×
213
                ( Trust_system.Actions.Sent_old_gossip
214
                , Some
215
                    ( "external transition with state hash $state_hash"
216
                    , [ ("state_hash", State_hash.to_yojson transition_hash)
×
217
                      ; ("header", Mina_block.Header.to_yojson header)
×
218
                      ] ) )
219
          | Error `Disconnected ->
×
220
              [%log internal] "Failure"
×
221
                ~metadata:[ ("reason", `String "Disconnected") ] ;
222
              Mina_metrics.(Counter.inc_one Rejected_blocks.worse_than_root) ;
×
223
              let protocol_state = Mina_block.Header.protocol_state header in
224
              [%log error]
×
225
                ~metadata:
226
                  [ ("state_hash", State_hash.to_yojson transition_hash)
×
227
                  ; ("reason", `String "not selected over current root")
228
                  ; ( "protocol_state"
229
                    , Mina_block.Header.protocol_state header
×
230
                      |> Protocol_state.value_to_yojson )
×
231
                  ]
232
                "Validation error: external transition with state hash \
233
                 $state_hash was rejected for reason $reason" ;
234
              let is_in_root_history =
×
235
                let open Transition_frontier.Extensions in
236
                get_extension
×
237
                  (Transition_frontier.extensions frontier)
×
238
                  Root_history
239
                |> Root_history.mem
×
240
              in
241
              let parent_hash =
242
                Protocol_state.previous_state_hash protocol_state
243
              in
244
              let action =
×
245
                if
246
                  is_in_root_history transition_hash
×
247
                  || Option.is_some
×
248
                       (Lru.find outdated_root_cache transition_hash)
×
249
                then Trust_system.Actions.Sent_old_gossip
×
250
                else if
×
251
                  is_in_root_history parent_hash
×
252
                  || Option.is_some (Lru.find outdated_root_cache parent_hash)
×
253
                then (
×
254
                  Lru.add outdated_root_cache ~key:transition_hash ~data:() ;
255
                  Sent_useless_gossip )
×
256
                else Disconnected_chain
×
257
              in
258
              Trust_system.record_envelope_sender trust_system logger sender
259
                ( action
260
                , Some
261
                    ( "received transition that was not connected to our chain \
262
                       from $sender"
263
                    , [ ("sender", Envelope.Sender.to_yojson sender)
×
264
                      ; ("header", Mina_block.Header.to_yojson header)
×
265
                      ] ) )
266
          | Error `Non_empty_staged_ledger_diff_after_stop_slot ->
×
267
              [%log error]
×
268
                ~metadata:
269
                  [ ("state_hash", State_hash.to_yojson transition_hash)
×
270
                  ; ( "reason"
271
                    , `String "not empty staged ledger diff after slot_tx_end"
272
                    )
273
                  ; ( "block_slot"
274
                    , Mina_numbers.Global_slot_since_hard_fork.to_yojson
×
275
                      @@ Consensus.Data.Consensus_state.curr_global_slot
×
276
                      @@ Protocol_state.consensus_state
×
277
                      @@ Header.protocol_state header )
×
278
                  ]
279
                "Validation error: external transition with state hash \
280
                 $state_hash was rejected for reason $reason" ;
281
              Deferred.unit
×
282
          | Error `Block_after_after_stop_slot ->
×
283
              [%log error]
×
284
                ~metadata:
285
                  [ ("state_hash", State_hash.to_yojson transition_hash)
×
286
                  ; ("reason", `String "block after slot_chain_end")
287
                  ; ( "block_slot"
288
                    , Mina_numbers.Global_slot_since_hard_fork.to_yojson
×
289
                      @@ Consensus.Data.Consensus_state.curr_global_slot
×
290
                      @@ Protocol_state.consensus_state
×
291
                      @@ Header.protocol_state header )
×
292
                  ]
293
                "Validation error: external transition with state hash \
294
                 $state_hash was rejected for reason $reason" ;
295
              Deferred.unit ) )
×
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