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

MinaProtocol / mina / 2910

16 Nov 2024 09:13AM UTC coverage: 38.876% (+2.1%) from 36.73%
2910

Pull #16345

buildkite

dkijania
Merge branch 'compatible' into dkijania/merge/compatible_to_develop_16_11_24
Pull Request #16345: merge compatible to develop 16 11 24

15 of 40 new or added lines in 14 files covered. (37.5%)

9 existing lines in 5 files now uncovered.

26157 of 67283 relevant lines covered (38.88%)

20732.42 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
34✔
19
  let get_exit_code () = !exit_code in
18✔
20
  (add_error, get_exit_code)
21

22
let main ~archive_uri () =
23
  let logger = Logger.create () in
18✔
24
  let archive_uri = Uri.of_string archive_uri in
18✔
25
  match Caqti_async.connect_pool ~max_size:128 archive_uri with
18✔
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 ->
18✔
32
      [%log info] "Successfully created Caqti pool for Postgresql" ;
18✔
33
      [%log info] "Querying missing blocks" ;
18✔
34
      let%bind missing_blocks_raw =
35
        match%bind
36
          Caqti_async.Pool.use (fun db -> Sql.Unparented_blocks.run db ()) pool
18✔
37
        with
38
        | Ok blocks ->
18✔
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 =
18✔
47
        List.filter missing_blocks_raw ~f:(fun (_, _, height, _) -> height <> 1)
98✔
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 (
17✔
53
          add_error missing_blocks_error ;
54
          Deferred.List.iter missing_blocks
17✔
55
            ~f:(fun (block_id, state_hash, height, parent_hash) ->
56
              match%map
57
                Caqti_async.Pool.use
80✔
58
                  (fun db -> Sql.Missing_blocks_gap.run db height)
80✔
59
                  pool
60
              with
61
              | Ok gap_size ->
80✔
62
                  [%log info] "Block has no parent in archive db"
80✔
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" ;
18✔
77
      let%bind highest_canonical =
78
        match%bind
79
          Caqti_async.Pool.use
18✔
80
            (fun db -> Sql.Chain_status.run_highest_canonical db ())
18✔
81
            pool
82
        with
83
        | Ok height ->
18✔
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
18✔
93
            (fun db ->
94
              Sql.Chain_status.run_count_pending_below db highest_canonical )
18✔
95
            pool
96
        with
97
        | Ok count ->
18✔
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
18✔
107
        [%log info] "There are no gaps in the chain statuses"
18✔
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
18✔
122
            (fun db -> Sql.Chain_status.run_canonical_chain db highest_canonical)
18✔
123
            pool
124
        with
125
        | Ok chain ->
18✔
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
18✔
133
      if Int64.equal chain_len highest_canonical then
18✔
134
        [%log info] "Length of canonical chain is %Ld blocks" chain_len
1✔
135
      else (
17✔
136
        add_error chain_length_error ;
137
        [%log info] "Length of canonical chain is %Ld blocks, expected: %Ld"
17✔
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") )
57✔
143
      in
144
      if List.is_empty invalid_chain then
18✔
145
        [%log info]
18✔
146
          "All blocks along the canonical chain have a valid chain status"
UNCOV
147
      else add_error chain_status_error ;
×
148
      List.iter invalid_chain ~f:(fun (block_id, state_hash, chain_status) ->
UNCOV
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 ())
18✔
157

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