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

MinaProtocol / mina / 1612

21 Oct 2024 08:28AM UTC coverage: 61.111% (+0.02%) from 61.093%
1612

push

buildkite

web-flow
Merge pull request #16255 from MinaProtocol/release/3.0.2

682 of 1335 new or added lines in 129 files covered. (51.09%)

148 existing lines in 47 files now uncovered.

47180 of 77204 relevant lines covered (61.11%)

555482.14 hits per line

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

74.63
/src/lib/cli_lib/flag.ml
1
open Core
10✔
2

3
let json =
4
  Command.Param.(
5
    flag "--json" ~aliases:[ "json" ] no_arg
10✔
6
      ~doc:"Use JSON output (default: plaintext)")
7

8
let plaintext =
9
  Command.Param.(
10
    flag "--plaintext" ~aliases:[ "plaintext" ] no_arg
10✔
11
      ~doc:"Use plaintext input or output (default: JSON)")
12

13
let performance =
14
  Command.Param.(
15
    flag "--performance" ~aliases:[ "performance" ] no_arg
10✔
16
      ~doc:
17
        "Include performance histograms in status output (default: don't \
18
         include)")
19

20
let privkey_write_path =
21
  let open Command.Param in
22
  flag "--privkey-path" ~aliases:[ "privkey-path" ]
10✔
23
    ~doc:"FILE File to write private key into (public key will be FILE.pub)"
24
    (required string)
10✔
25

26
let privkey_read_path =
27
  let open Command.Param in
28
  flag "--privkey-path" ~aliases:[ "privkey-path" ]
10✔
29
    ~doc:"FILE File to read private key from" (required string)
10✔
30

31
let conf_dir =
32
  let open Command.Param in
33
  flag "--config-directory" ~aliases:[ "config-directory" ]
10✔
34
    ~doc:"DIR Configuration directory" (optional string)
10✔
35

36
module Doc_builder = struct
37
  type 'value t =
38
    { type_name : string
39
    ; description : string
40
    ; examples : 'value list
41
    ; display : 'value -> string
42
    }
43

44
  let create ~display ?(examples = []) type_name description =
50✔
45
    { type_name; description; examples; display }
90✔
46

47
  let display ~default { type_name; description; examples; display } =
48
    let open Printf in
100✔
49
    let example_text =
50
      if List.is_empty examples then ""
50✔
51
      else
52
        sprintf "(examples: %s)"
50✔
53
          (String.concat ~sep:", " @@ List.map examples ~f:display)
50✔
54
    in
55
    let default_text =
56
      Option.value_map ~default:"" default
57
        ~f:(Fn.compose (sprintf !" (default: %s)") display)
100✔
58
    in
59
    sprintf !"%s %s %s%s" type_name description example_text default_text
100✔
60
end
61

62
module Types = struct
63
  type 'a with_name = { name : string; value : 'a }
64

65
  type 'a with_name_and_displayed_default =
66
    { name : string; value : 'a option; default : 'a }
67

68
  (*Difference between Optional and Optional_value is that the name is still accessible if the value is None*)
69
  type ('value, 'output) t =
70
    | Optional : ('value, 'value with_name option) t
71
    | Optional_value : ('value, 'value option with_name) t
72
    | Optional_with_displayed_default :
73
        'value
74
        -> ('value, 'value with_name_and_displayed_default) t
75
    | Resolve_with_default : 'value -> ('value, 'value with_name) t
76
end
77

78
let setup_flag ~arg_type ~name ?aliases doc =
79
  let open Command.Let_syntax in
100✔
80
  Command.Param.flag name ?aliases ~doc (Command.Param.optional arg_type)
100✔
81
  >>| Option.map ~f:(fun value -> { Types.name; value })
×
82

83
let create (type value output) :
84
       name:string
85
    -> ?aliases:string list
86
    -> arg_type:value Command.Arg_type.t
87
    -> value Doc_builder.t
88
    -> (value, output) Types.t
89
    -> output Command.Param.t =
90
  let open Command.Let_syntax in
91
  fun ~name ?aliases ~arg_type doc_builder -> function
92
    | Optional ->
20✔
93
        setup_flag ~arg_type ~name ?aliases
94
          (Doc_builder.display ~default:None doc_builder)
20✔
95
    | Optional_value -> (
10✔
96
        setup_flag ~arg_type ~name ?aliases
10✔
97
          (Doc_builder.display ~default:None doc_builder)
10✔
98
        >>| function
99
        | Some { name; value } ->
×
100
            { Types.name; value = Some value }
101
        | None ->
×
102
            { name; value = None } )
103
    | Optional_with_displayed_default default -> (
40✔
104
        setup_flag ~arg_type ~name ?aliases
40✔
105
          (Doc_builder.display ~default:(Some default) doc_builder)
40✔
106
        >>| function
107
        | Some { name; value } ->
×
108
            { Types.name; value = Some value; default }
109
        | None ->
×
110
            { name; value = None; default } )
111
    | Resolve_with_default default ->
30✔
112
        setup_flag ~arg_type ~name ?aliases
30✔
113
          (Doc_builder.display ~default:(Some default) doc_builder)
30✔
114
        >>| Option.value ~default:{ Types.name; value = default }
115

116
module Port = struct
117
  let to_string = Int.to_string
118

119
  let doc_builder description =
120
    Doc_builder.create ~display:to_string "PORT" description
50✔
121

122
  let create_optional ~name ?aliases description =
123
    create ~name ?aliases (doc_builder description) Optional_value
10✔
124
      ~arg_type:Arg_type.int16
125

126
  let create ~name ?aliases ~default description =
127
    create ~name ?aliases (doc_builder description)
40✔
128
      (Optional_with_displayed_default default) ~arg_type:Arg_type.int16
129

130
  let default_client = 8301
131

132
  let default_rest = 0xc0d
133

134
  let default_archive = default_rest + 1
135

136
  let default_libp2p = 8302
137

138
  let of_raw raw =
139
    let open Or_error.Let_syntax in
×
140
    let%bind () =
141
      Result.ok_if_true
×
142
        (String.for_all raw ~f:Char.is_digit)
×
143
        ~error:(Error.of_string "Not a number")
×
144
    in
145
    Arg_type.validate_int16 (Int.of_string raw)
×
146

147
  let to_host_and_port port = Host_and_port.create ~host:"127.0.0.1" ~port
30✔
148

149
  let to_uri ~path port =
150
    Uri.of_string ("http://localhost:" ^ string_of_int port ^/ path)
20✔
151

152
  module Daemon = struct
153
    let external_ =
154
      create ~name:"--external-port" ~aliases:[ "external-port" ]
10✔
155
        ~default:default_libp2p
156
        "Port to use for all libp2p communications (gossip and RPC)"
157

158
    let client =
159
      create ~name:"--client-port" ~aliases:[ "client-port" ]
10✔
160
        ~default:default_client
161
        "local RPC-server for clients to interact with the daemon"
162

163
    let rest_server =
164
      create ~name:"--rest-port" ~aliases:[ "rest-port" ] ~default:default_rest
10✔
165
        "local REST-server for daemon interaction"
166

167
    let limited_graphql_server =
168
      create_optional ~name:"--limited-graphql-port"
10✔
169
        ~aliases:[ "limited-graphql-port" ]
170
        "GraphQL-server for limited daemon interaction"
171
  end
172

173
  module Archive = struct
174
    let server =
175
      create ~name:"--server-port" ~aliases:[ "server-port" ]
10✔
176
        ~default:default_archive "port to launch the archive server"
177
  end
178
end
179

180
module Host = struct
181
  let localhost = Core.Unix.Host.getbyname_exn "localhost"
10✔
182

183
  let is_localhost host =
184
    Option.value_map ~default:false (Unix.Host.getbyname host) ~f:(fun host ->
100✔
185
        Core.Unix.Host.have_address_in_common host localhost )
80✔
186
end
187

188
let example_host = "154.97.53.97"
189

190
module Host_and_port = struct
191
  let parse_host_and_port raw =
192
    match Port.of_raw raw with
×
193
    | Ok port ->
×
194
        Port.to_host_and_port port
195
    | Error _ ->
×
196
        Host_and_port.of_string raw
197

198
  let arg_type : Host_and_port.t Command.Arg_type.t =
199
    Command.Arg_type.map Command.Param.string ~f:parse_host_and_port
10✔
200

201
  let is_localhost (host_and_port : Host_and_port.t) =
202
    Host.is_localhost (Host_and_port.host host_and_port)
50✔
203

204
  let to_string host_and_port =
205
    if is_localhost host_and_port then
50✔
206
      Int.to_string @@ Host_and_port.port host_and_port
30✔
207
    else Host_and_port.to_string host_and_port
20✔
208

209
  let create_examples port =
210
    [ Port.to_host_and_port port
20✔
211
    ; Host_and_port.create ~host:example_host ~port
212
    ]
213

214
  let make_doc_builder description example_port =
215
    Doc_builder.create ~display:to_string
20✔
216
      ~examples:(create_examples example_port)
20✔
217
      "HOST:PORT/LOCALHOST-PORT"
218
      (sprintf "%s. If HOST is omitted, then localhost is assumed to be HOST."
20✔
219
         description )
220

221
  module Client = struct
222
    let daemon =
223
      create ~name:"--daemon-port" ~aliases:[ "daemon-port" ] ~arg_type
10✔
224
        (make_doc_builder "Client to local daemon communication"
10✔
225
           Port.default_client )
226
        (Resolve_with_default (Port.to_host_and_port Port.default_client))
10✔
227
  end
228

229
  module Daemon = struct
230
    let archive =
231
      create ~name:"--archive-address" ~aliases:[ "archive-address" ] ~arg_type
10✔
232
        (make_doc_builder "Daemon to archive process communication"
10✔
233
           Port.default_archive )
234
        Optional
235
  end
236
end
237

238
module Uri = struct
239
  let parse_uri ~path raw =
240
    match Port.of_raw raw with
×
241
    | Ok port ->
×
242
        Port.to_uri ~path port
243
    | Error _ ->
×
244
        Uri.of_string raw
245

246
  let arg_type ~path =
247
    Command.Arg_type.map Command.Param.string ~f:(parse_uri ~path)
20✔
248

249
  let is_localhost (host_and_port : Uri.t) =
250
    Option.value_map ~default:false (Uri.host host_and_port)
70✔
251
      ~f:Host.is_localhost
252

253
  let to_string uri =
254
    if is_localhost uri then
70✔
255
      sprintf "%i or %s" (Option.value_exn (Uri.port uri)) (Uri.to_string uri)
30✔
256
    else Uri.to_string uri
40✔
257

258
  module Client = struct
259
    let doc_builder =
260
      Doc_builder.create ~display:to_string
10✔
261
        ~examples:
262
          [ Port.to_uri ~path:"graphql" Port.default_rest
10✔
263
          ; Uri.of_string
10✔
264
              ( "/dns4/peer1-rising-phoenix.o1test.net" ^ ":"
265
              ^ Int.to_string Port.default_rest
10✔
266
              ^/ "graphql" )
10✔
267
          ]
268
        "URI/LOCALHOST-PORT" "graphql rest server for daemon interaction"
269

270
    let name = "rest-server"
271

272
    let default = Port.to_uri ~path:"graphql" Port.default_rest
10✔
273

274
    let rest_graphql =
275
      create ~name:"--rest-server" ~aliases:[ "rest-server" ]
10✔
276
        ~arg_type:(arg_type ~path:"graphql") doc_builder
277
        (Resolve_with_default default)
278

279
    let rest_graphql_opt =
280
      create ~name:"--rest-server" ~aliases:[ "rest-server" ]
10✔
281
        ~arg_type:(arg_type ~path:"graphql") doc_builder Optional
282
  end
283

284
  module Archive = struct
285
    let postgres =
286
      let doc_builder =
287
        Doc_builder.create ~display:to_string
288
          ~examples:
289
            [ Uri.of_string "postgres://admin:codarules@postgres:5432/archiver"
10✔
290
            ]
291
          "URI" "URI for postgresql database"
292
      in
293
      create ~name:"--postgres-uri" ~aliases:[ "postgres-uri" ]
10✔
294
        ~arg_type:(Command.Arg_type.map Command.Param.string ~f:Uri.of_string)
10✔
295
        doc_builder
296
        (Resolve_with_default
297
           (Uri.of_string "postgres://admin:codarules@postgres:5432/archiver")
10✔
298
        )
299
  end
300
end
301

302
module Log = struct
303
  let json =
304
    let open Command.Param in
305
    flag "--log-json" ~aliases:[ "log-json" ] no_arg
10✔
306
      ~doc:"Print log output as JSON (default: plain text)"
307

308
  let all_levels =
309
    String.concat ~sep:"|" (List.map ~f:Logger.Level.show Logger.Level.all)
10✔
310

311
  let level =
312
    let log_level = Arg_type.log_level in
313
    let open Command.Param in
314
    let doc = sprintf "LEVEL Set log level (%s, default: Info)" all_levels in
315
    flag "--log-level" ~aliases:[ "log-level" ] ~doc
10✔
316
      (optional_with_default Logger.Level.Info log_level)
10✔
317

318
  let file_log_level =
319
    let log_level = Arg_type.log_level in
320
    let open Command.Param in
321
    let doc =
322
      sprintf "LEVEL Set log level for the log file (%s, default: Trace)"
323
        all_levels
324
    in
325
    flag "--file-log-level" ~aliases:[ "file-log-level" ] ~doc
10✔
326
      (optional_with_default Logger.Level.Trace log_level)
10✔
327

328
  let file_log_rotations =
329
    let open Command.Param in
330
    flag "--file-log-rotations"
10✔
331
      ~doc:
332
        (Printf.sprintf
10✔
333
           "Number of file log rotations before overwriting old logs (default: \
334
            %d)"
335
           Default.file_log_rotations )
336
      (optional_with_default Default.file_log_rotations int)
10✔
337

338
  let file =
339
    let open Command.Param in
340
    flag "--log-file" ~aliases:[ "log-file" ]
10✔
341
      ~doc:"FILE Set log file (stores JSON)" (optional string)
10✔
342
end
343

344
type signed_command_common =
345
  { sender : Signature_lib.Public_key.Compressed.t
346
  ; fee : Currency.Fee.t
347
  ; nonce : Mina_base.Account.Nonce.t option
348
  ; memo : string option
349
  }
350

351
let fee_common ~default_transaction_fee ~minimum_user_command_fee :
352
    Currency.Fee.t Command.Param.t =
NEW
353
  Command.Param.flag "--fee" ~aliases:[ "fee" ]
×
354
    ~doc:
NEW
355
      (Printf.sprintf
×
356
         "FEE Amount you are willing to pay to process the transaction \
357
          (default: %s) (minimum: %s)"
NEW
358
         (Currency.Fee.to_mina_string default_transaction_fee)
×
NEW
359
         (Currency.Fee.to_mina_string minimum_user_command_fee) )
×
NEW
360
    (Command.Param.optional_with_default default_transaction_fee
×
361
       Arg_type.txn_fee )
362

363
let signed_command_common ~default_transaction_fee ~minimum_user_command_fee :
364
    signed_command_common Command.Param.t =
UNCOV
365
  let open Command.Let_syntax in
×
366
  let open Arg_type in
367
  let%map_open sender =
UNCOV
368
    flag "--sender" ~aliases:[ "sender" ]
×
UNCOV
369
      (required public_key_compressed)
×
370
      ~doc:"PUBLICKEY Public key from which you want to send the transaction"
371
  and fee = fee_common ~default_transaction_fee ~minimum_user_command_fee
372
  and nonce =
UNCOV
373
    flag "--nonce" ~aliases:[ "nonce" ]
×
374
      ~doc:
375
        "NONCE Nonce that you would like to set for your transaction (default: \
376
         nonce of your account on the best ledger or the successor of highest \
377
         value nonce of your sent transactions from the transaction pool )"
UNCOV
378
      (optional txn_nonce)
×
379
  and memo =
UNCOV
380
    flag "--memo" ~aliases:[ "memo" ]
×
UNCOV
381
      ~doc:"STRING Memo accompanying the transaction" (optional string)
×
382
  in
NEW
383
  { sender; fee; nonce; memo }
×
384

385
module Signed_command = struct
386
  open Arg_type
387

388
  let hd_index =
389
    let open Command.Param in
390
    flag "--hd-index" ~aliases:[ "HD-index" ]
10✔
391
      ~doc:"HD-INDEX Index used by hardware wallet" (required hd_index)
10✔
392

393
  let receiver_pk =
394
    let open Command.Param in
395
    flag "--receiver" ~aliases:[ "receiver" ]
10✔
396
      ~doc:"PUBLICKEY Public key to which you want to send money"
397
      (required public_key_compressed)
10✔
398

399
  let amount =
400
    let open Command.Param in
401
    flag "--amount" ~aliases:[ "amount" ]
10✔
402
      ~doc:"VALUE Payment amount you want to send" (required txn_amount)
10✔
403

404
  let fee ~default_transaction_fee ~minimum_user_command_fee =
UNCOV
405
    let open Command.Param in
×
406
    flag "--fee" ~aliases:[ "fee" ]
407
      ~doc:
UNCOV
408
        (Printf.sprintf
×
409
           "FEE Amount you are willing to pay to process the transaction \
410
            (default: %s) (minimum: %s)"
NEW
411
           (Currency.Fee.to_mina_string default_transaction_fee)
×
NEW
412
           (Currency.Fee.to_mina_string minimum_user_command_fee) )
×
UNCOV
413
      (optional txn_fee)
×
414

415
  let valid_until =
416
    let open Command.Param in
417
    flag "--valid-until" ~aliases:[ "valid-until" ]
10✔
418
      ~doc:
419
        "GLOBAL-SLOT The last global-slot at which this transaction will be \
420
         considered valid. This makes it possible to have transactions which \
421
         expire if they are not applied before this time. If omitted, the \
422
         transaction will never expire."
423
      (optional global_slot)
10✔
424

425
  let nonce =
426
    let open Command.Param in
427
    flag "--nonce" ~aliases:[ "nonce" ]
10✔
428
      ~doc:
429
        "NONCE Nonce that you would like to set for your transaction (default: \
430
         nonce of your account on the best ledger or the successor of highest \
431
         value nonce of your sent transactions from the transaction pool )"
432
      (optional txn_nonce)
10✔
433

434
  let memo =
435
    let open Command.Param in
436
    flag "--memo" ~aliases:[ "memo" ]
10✔
437
      ~doc:
438
        (sprintf
10✔
439
           "STRING Memo accompanying the transaction (up to %d characters)"
440
           Mina_base.Signed_command_memo.max_input_length )
441
      (optional string)
10✔
442
end
20✔
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