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

MinaProtocol / mina / 2920

12 Nov 2024 12:30PM UTC coverage: 33.072% (-3.7%) from 36.73%
2920

push

buildkite

web-flow
Merge pull request #16333 from MinaProtocol/dkijania/port_new_deb_s3_dev

[DEV] Use new version of deb-s3 for validating job publishing

22178 of 67059 relevant lines covered (33.07%)

10229.22 hits per line

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

58.67
/src/app/missing_blocks_auditor/missing_blocks_auditor.ml
1
(* missing_blocks_auditor.ml *)
2

3
open Core_kernel
4
open Async
5

6
(* bits in error code *)
7

8
let missing_blocks_error = 0
9

10
let pending_blocks_error = 1
11

12
let chain_length_error = 2
13

14
let chain_status_error = 3
15

16
let add_error, get_exit_code =
17
  let exit_code = ref 0 in
18
  let add_error n = exit_code := !exit_code lor (1 lsl n) in
54✔
19
  let get_exit_code () = !exit_code in
28✔
20
  (add_error, get_exit_code)
21

22
let main ~archive_uri () =
23
  let logger = Logger.create () in
28✔
24
  let archive_uri = Uri.of_string archive_uri in
28✔
25
  match Caqti_async.connect_pool ~max_size:128 archive_uri with
28✔
26
  | Error e ->
×
27
      [%log fatal]
×
28
        ~metadata:[ ("error", `String (Caqti_error.show e)) ]
×
29
        "Failed to create a Caqti pool for Postgresql" ;
30
      exit 1
×
31
  | Ok pool ->
28✔
32
      [%log info] "Successfully created Caqti pool for Postgresql" ;
28✔
33
      [%log info] "Querying missing blocks" ;
28✔
34
      let%bind missing_blocks_raw =
35
        match%bind
36
          Caqti_async.Pool.use (fun db -> Sql.Unparented_blocks.run db ()) pool
28✔
37
        with
38
        | Ok blocks ->
28✔
39
            return blocks
40
        | Error msg ->
×
41
            [%log error] "Error getting missing blocks"
×
42
              ~metadata:[ ("error", `String (Caqti_error.show msg)) ] ;
×
43
            exit 1
×
44
      in
45
      (* filter out genesis block *)
46
      let missing_blocks =
28✔
47
        List.filter missing_blocks_raw ~f:(fun (_, _, height, _) -> height <> 1)
223✔
48
      in
49
      let%bind () =
50
        if List.is_empty missing_blocks then
51
          return @@ [%log info] "There are no missing blocks in the archive db"
1✔
52
        else (
27✔
53
          add_error missing_blocks_error ;
54
          Deferred.List.iter missing_blocks
27✔
55
            ~f:(fun (block_id, state_hash, height, parent_hash) ->
56
              match%map
57
                Caqti_async.Pool.use
195✔
58
                  (fun db -> Sql.Missing_blocks_gap.run db height)
195✔
59
                  pool
60
              with
61
              | Ok gap_size ->
195✔
62
                  [%log info] "Block has no parent in archive db"
195✔
63
                    ~metadata:
64
                      [ ("block_id", `Int block_id)
65
                      ; ("state_hash", `String state_hash)
66
                      ; ("height", `Int height)
67
                      ; ("parent_hash", `String parent_hash)
68
                      ; ("parent_height", `Int (height - 1))
69
                      ; ("missing_blocks_gap", `Int gap_size)
70
                      ]
71
              | Error msg ->
×
72
                  [%log error] "Error getting missing blocks gap"
×
73
                    ~metadata:[ ("error", `String (Caqti_error.show msg)) ] ;
×
74
                  Core_kernel.exit 1 ) )
×
75
      in
76
      [%log info] "Querying for gaps in chain statuses" ;
28✔
77
      let%bind highest_canonical =
78
        match%bind
79
          Caqti_async.Pool.use
28✔
80
            (fun db -> Sql.Chain_status.run_highest_canonical db ())
28✔
81
            pool
82
        with
83
        | Ok height ->
28✔
84
            return height
85
        | Error msg ->
×
86
            [%log error] "Error getting greatest height of canonical blocks"
×
87
              ~metadata:[ ("error", `String (Caqti_error.show msg)) ] ;
×
88
            exit 1
×
89
      in
90
      let%bind pending_below =
91
        match%bind
92
          Caqti_async.Pool.use
28✔
93
            (fun db ->
94
              Sql.Chain_status.run_count_pending_below db highest_canonical )
28✔
95
            pool
96
        with
97
        | Ok count ->
28✔
98
            return count
99
        | Error msg ->
×
100
            [%log error]
×
101
              "Error getting number of pending blocks below highest canonical \
102
               block"
103
              ~metadata:[ ("error", `String (Caqti_error.show msg)) ] ;
×
104
            exit 1
×
105
      in
106
      if Int64.equal pending_below Int64.zero then
28✔
107
        [%log info] "There are no gaps in the chain statuses"
28✔
108
      else (
×
109
        add_error pending_blocks_error ;
110
        [%log info]
×
111
          "There are $num_pending_blocks_below pending blocks lower than the \
112
           highest canonical block"
113
          ~metadata:
114
            [ ( "max_height_canonical_block"
115
              , `String (Int64.to_string highest_canonical) )
×
116
            ; ( "num_pending_blocks_below"
117
              , `String (Int64.to_string pending_below) )
×
118
            ] ) ;
119
      let%bind canonical_chain =
120
        match%bind
121
          Caqti_async.Pool.use
28✔
122
            (fun db -> Sql.Chain_status.run_canonical_chain db highest_canonical)
28✔
123
            pool
124
        with
125
        | Ok chain ->
28✔
126
            return chain
127
        | Error msg ->
×
128
            [%log error] "Error getting canonical chain"
×
129
              ~metadata:[ ("error", `String (Caqti_error.show msg)) ] ;
×
130
            exit 1
×
131
      in
132
      let chain_len = List.length canonical_chain |> Int64.of_int in
28✔
133
      if Int64.equal chain_len highest_canonical then
28✔
134
        [%log info] "Length of canonical chain is %Ld blocks" chain_len
1✔
135
      else (
27✔
136
        add_error chain_length_error ;
137
        [%log info] "Length of canonical chain is %Ld blocks, expected: %Ld"
27✔
138
          chain_len highest_canonical ) ;
139
      let invalid_chain =
140
        List.filter canonical_chain
141
          ~f:(fun (_block_id, _state_hash, chain_status) ->
142
            not (String.equal chain_status "canonical") )
103✔
143
      in
144
      if List.is_empty invalid_chain then
28✔
145
        [%log info]
28✔
146
          "All blocks along the canonical chain have a valid chain status"
147
      else add_error chain_status_error ;
×
148
      List.iter invalid_chain ~f:(fun (block_id, state_hash, chain_status) ->
149
          [%log info]
×
150
            "Canonical block has a chain_status other than \"canonical\""
151
            ~metadata:
152
              [ ("block_id", `Int block_id)
153
              ; ("state_hash", `String state_hash)
154
              ; ("chain_status", `String chain_status)
155
              ] ) ;
156
      Core.exit (get_exit_code ())
28✔
157

158
let () =
159
  Command.(
160
    run
×
161
      (let open Let_syntax in
162
      Command.async
28✔
163
        ~summary:"Report state hashes of blocks missing from archive database"
164
        (let%map archive_uri =
165
           Param.flag "--archive-uri"
28✔
166
             ~doc:
167
               "URI URI for connecting to the archive database (e.g., \
168
                postgres://$USER@localhost:5432/archiver)"
169
             Param.(required string)
28✔
170
         in
171
         main ~archive_uri )))
28✔
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