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

MinaProtocol / mina / 1661

18 Dec 2025 03:32PM UTC coverage: 61.328% (+27.9%) from 33.382%
1661

push

buildkite

web-flow
Merge pull request #18232 from MinaProtocol/amcie-merging-release-330-to-master

Merging 3.3.0 release branch to master

1229 of 2006 new or added lines in 108 files covered. (61.27%)

54 existing lines in 27 files now uncovered.

51257 of 83578 relevant lines covered (61.33%)

472886.36 hits per line

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

1.38
/src/lib/testing/integration_test_local_engine/docker_node_config.ml
1
open Core_kernel
1✔
2
open Async
3
open Integration_test_lib
4
open Docker_compose
5

6
module PortManager = struct
7
  let mina_internal_rest_port = 3085
8

9
  let mina_internal_client_port = 8301
10

11
  let mina_internal_metrics_port = 10001
12

13
  let mina_internal_server_port = 3086
14

15
  let mina_internal_external_port = 10101
16

17
  let postgres_internal_port = 5432
18

19
  type t =
20
    { mutable available_ports : int list
21
    ; mutable used_ports : int list
22
    ; min_port : int
23
    ; max_port : int
24
    }
25

26
  let create ~min_port ~max_port =
27
    let available_ports = List.range min_port max_port in
×
28
    { available_ports; used_ports = []; min_port; max_port }
×
29

30
  let allocate_port t =
31
    match t.available_ports with
×
32
    | [] ->
×
33
        failwith "No available ports"
34
    | port :: rest ->
×
35
        t.available_ports <- rest ;
36
        t.used_ports <- port :: t.used_ports ;
37
        port
38

39
  let allocate_ports_for_node t =
40
    let rest_port_source = allocate_port t in
×
41
    let client_port_source = allocate_port t in
×
42
    let metrics_port_source = allocate_port t in
×
43
    [ { Dockerfile.Service.Port.published = rest_port_source
×
44
      ; target = mina_internal_rest_port
45
      }
46
    ; { published = client_port_source; target = mina_internal_client_port }
47
    ; { published = metrics_port_source; target = mina_internal_metrics_port }
48
    ]
49

50
  let release_port t port =
51
    t.used_ports <- List.filter t.used_ports ~f:(fun p -> p <> port) ;
×
52
    t.available_ports <- port :: t.available_ports
53

54
  let get_latest_used_port t =
55
    match t.used_ports with [] -> failwith "No used ports" | port :: _ -> port
×
56
end
57

58
module Base_node_config = struct
59
  type t =
×
60
    { peer : string option
×
61
    ; log_level : string
×
62
    ; log_snark_work_gossip : bool
×
63
    ; log_txn_pool_gossip : bool
×
64
    ; generate_genesis_proof : bool
×
65
    ; client_port : string
×
66
    ; rest_port : string
×
67
    ; external_port : string
×
68
    ; metrics_port : string
×
69
    ; runtime_config_path : string option
×
70
    ; libp2p_key_path : string
×
71
    ; libp2p_secret : string
×
72
    ; start_filtered_logs : string list
×
73
    }
74
  [@@deriving to_yojson]
75

76
  let container_runtime_config_path = "/root/runtime_config.json"
77

78
  let container_entrypoint_path = "/root/entrypoint.sh"
79

80
  let container_keys_path = "/root/keys"
81

82
  let container_libp2p_key_path = container_keys_path ^ "/libp2p_key"
83

84
  let magic_config_file commit_id =
NEW
85
    Printf.sprintf "/var/lib/coda/config_%s.json" commit_id
×
86

87
  let entrypoint_script commit_id =
88
    ( "entrypoint.sh"
×
89
    , {|#!/bin/bash
90
  # This file is auto-generated by the local integration test framework.
91
  # Remove magic config file which is loaded by default when daemon is starting.
92
  # It can influence final config file
93
  rm |}
NEW
94
      ^ magic_config_file commit_id
×
95
      ^ {|
96
  # Path to the libp2p_key file
97
  LIBP2P_KEY_PATH="|}
98
      ^ container_libp2p_key_path
99
      ^ {|"
100
  # Generate keypair and set permissions if libp2p_key does not exist
101
  if [ ! -f "$LIBP2P_KEY_PATH" ]; then
102
    mina libp2p generate-keypair --privkey-path $LIBP2P_KEY_PATH
103
  fi
104
  /bin/chmod -R 700 |}
105
      ^ container_keys_path ^ {|/
106
  # Import any compatible keys in |}
107
      ^ container_keys_path ^ {|/*, excluding certain keys
108
  for key_file in |}
109
      ^ container_keys_path
110
      ^ {|/*; do
111
    # Exclude specific keys (e.g., libp2p keys)
112
    if [[ $(basename "$key_file") != "libp2p_key" ]]; then
113
      mina accounts import -config-directory /root/.mina-config -privkey-path "$key_file"
114
    fi
115
  done
116
  # Execute the puppeteer script
117
  exec /mina_daemon_puppeteer.py "$@"
118
  |}
119
    )
120

121
  let runtime_config_volume : Docker_compose.Dockerfile.Service.Volume.t =
122
    { type_ = "bind"
123
    ; source = "runtime_config.json"
124
    ; target = container_runtime_config_path
125
    }
126

127
  let entrypoint_volume : Docker_compose.Dockerfile.Service.Volume.t =
128
    { type_ = "bind"
129
    ; source = "entrypoint.sh"
130
    ; target = container_entrypoint_path
131
    }
132

133
  let default ?(runtime_config_path = None) ?(peer = None)
×
134
      ?(start_filtered_logs = []) =
×
135
    { runtime_config_path
×
136
    ; peer
137
    ; log_snark_work_gossip = true
138
    ; log_txn_pool_gossip = true
139
    ; generate_genesis_proof = true
140
    ; log_level = "Debug"
141
    ; client_port = PortManager.mina_internal_client_port |> Int.to_string
×
142
    ; rest_port = PortManager.mina_internal_rest_port |> Int.to_string
×
143
    ; metrics_port = PortManager.mina_internal_metrics_port |> Int.to_string
×
144
    ; external_port = PortManager.mina_internal_external_port |> Int.to_string
×
145
    ; libp2p_key_path = container_libp2p_key_path
146
    ; libp2p_secret = ""
147
    ; start_filtered_logs
148
    }
149

150
  let to_docker_env_vars t =
151
    [ ("DAEMON_REST_PORT", t.rest_port)
×
152
    ; ("DAEMON_CLIENT_PORT", t.client_port)
153
    ; ("DAEMON_METRICS_PORT", t.metrics_port)
154
    ; ("DAEMON_EXTERNAL_PORT", t.external_port)
155
    ; ("RAYON_NUM_THREADS", "8")
156
    ; ("MINA_PRIVKEY_PASS", "naughty blue worm")
157
    ; ("MINA_LIBP2P_PASS", "")
158
    ]
159

160
  let to_list t =
161
    let base_args =
×
162
      [ "-log-level"
163
      ; t.log_level
164
      ; "-log-snark-work-gossip"
165
      ; Bool.to_string t.log_snark_work_gossip
×
166
      ; "-log-txn-pool-gossip"
167
      ; Bool.to_string t.log_txn_pool_gossip
×
168
      ; "-generate-genesis-proof"
169
      ; Bool.to_string t.generate_genesis_proof
×
170
      ; "-client-port"
171
      ; t.client_port
172
      ; "-rest-port"
173
      ; t.rest_port
174
      ; "-external-port"
175
      ; t.external_port
176
      ; "-metrics-port"
177
      ; t.metrics_port
178
      ; "--libp2p-keypair"
179
      ; t.libp2p_key_path
180
      ; "-log-json"
181
      ; "--insecure-rest-server"
182
      ; "-external-ip"
183
      ; "0.0.0.0"
184
      ]
185
    in
186
    let peer_args =
187
      match t.peer with Some peer -> [ "-peer"; peer ] | None -> []
×
188
    in
189
    let start_filtered_logs_args =
190
      List.concat
191
        (List.map t.start_filtered_logs ~f:(fun log ->
×
192
             [ "--start-filtered-logs"; log ] ) )
×
193
    in
194
    let runtime_config_path =
×
195
      match t.runtime_config_path with
196
      | Some path ->
×
197
          [ "-config-file"; path ]
198
      | None ->
×
199
          []
200
    in
201
    List.concat
202
      [ base_args; runtime_config_path; peer_args; start_filtered_logs_args ]
203
end
204

205
module Block_producer_config = struct
206
  type config =
×
207
    { keypair : Network_keypair.t
×
208
    ; priv_key_path : string
×
209
    ; enable_flooding : bool
×
210
    ; enable_peer_exchange : bool
×
211
    ; base_config : Base_node_config.t
×
212
    }
213
  [@@deriving to_yojson]
214

215
  type t =
×
216
    { service_name : string
×
217
    ; config : config
×
218
    ; docker_config : Dockerfile.Service.t
×
219
    }
220
  [@@deriving to_yojson]
221

222
  let create_cmd config =
223
    let base_args = Base_node_config.to_list config.base_config in
×
224
    let block_producer_args =
×
225
      [ "daemon"
226
      ; "-block-producer-key"
227
      ; config.priv_key_path
228
      ; "-enable-flooding"
229
      ; config.enable_flooding |> Bool.to_string
×
230
      ; "-enable-peer-exchange"
231
      ; config.enable_peer_exchange |> Bool.to_string
×
232
      ]
233
    in
234
    List.concat [ block_producer_args; base_args ]
235

236
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment
237
      ~config =
238
    { Dockerfile.Service.image
×
239
    ; command = create_cmd config
×
240
    ; entrypoint
241
    ; ports
242
    ; environment
243
    ; volumes
244
    }
245

246
  let create ~service_name ~image ~ports ~volumes ~config =
247
    let entrypoint = Some [ "/root/entrypoint.sh" ] in
×
248
    let environment = Base_node_config.to_docker_env_vars config.base_config in
249
    let docker_config =
×
250
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint
251
        ~config
252
    in
253
    { service_name; config; docker_config }
254
end
255

256
module Seed_config = struct
257
  let peer_id = "12D3KooWMg66eGtSEx5UZ9EAqEp3W7JaGd6WTxdRFuqhskRN55dT"
258

259
  let libp2p_keypair =
260
    {|{"box_primitive":"xsalsa20poly1305","pw_primitive":"argon2i","nonce":"7Bbvv2wZ6iCeqVyooU9WR81aygshMrLdXKieaHT","pwsalt":"Bh1WborqSwdzBi7m95iZdrCGspSf","pwdiff":[134217728,6],"ciphertext":"8fgvt4eKSzF5HMr1uEZARVHBoMgDKTx17zV7STVQyhyyEz1SqdH4RrU51MFGMPZJXNznLfz8RnSPsjrVqhc1CenfSLLWP5h7tTn86NbGmzkshCNvUiGEoSb2CrSLsvJsdn13ey9ibbZfdeXyDp9y6mKWYVmefAQLWUC1Kydj4f4yFwCJySEttAhB57647ewBRicTjdpv948MjdAVNf1tTxms4VYg4Jb3pLVeGAPaRtW5QHUkA8LwN5fh3fmaFk1mRudMd67UzGdzrVBeEHAp4zCnN7g2iVdWNmwN3"}|}
261

262
  let create_libp2p_peer ~peer_name ~external_port =
263
    Printf.sprintf "/dns4/%s/tcp/%d/p2p/%s" peer_name external_port peer_id
×
264

265
  type config =
×
266
    { archive_address : string option; base_config : Base_node_config.t }
×
267
  [@@deriving to_yojson]
268

269
  type t =
×
270
    { service_name : string
×
271
    ; config : config
×
272
    ; docker_config : Dockerfile.Service.t
×
273
    }
274
  [@@deriving to_yojson]
275

276
  let seed_libp2p_keypair : Docker_compose.Dockerfile.Service.Volume.t =
277
    { type_ = "bind"
278
    ; source = "keys/libp2p_key"
279
    ; target = Base_node_config.container_libp2p_key_path
280
    }
281

282
  let create_cmd config =
283
    let base_args = Base_node_config.to_list config.base_config in
×
284
    let seed_args =
×
285
      match config.archive_address with
286
      | Some archive_address ->
×
287
          [ "daemon"; "-seed"; "-archive-address"; archive_address ]
288
      | None ->
×
289
          [ "daemon"; "-seed" ]
290
    in
291
    List.concat [ seed_args; base_args ]
292

293
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment
294
      ~config =
295
    { Dockerfile.Service.image
×
296
    ; command = create_cmd config
×
297
    ; entrypoint
298
    ; ports
299
    ; environment
300
    ; volumes
301
    }
302

303
  let create ~service_name ~image ~ports ~volumes ~config =
304
    let entrypoint = Some [ "/root/entrypoint.sh" ] in
×
305
    let environment = Base_node_config.to_docker_env_vars config.base_config in
306
    let docker_config =
×
307
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint
308
        ~config
309
    in
310
    { service_name; config; docker_config }
311
end
312

313
module Snark_worker_config = struct
314
  type config =
×
315
    { daemon_address : string
×
316
    ; daemon_port : string
×
317
    ; proof_level : string
×
318
    ; base_config : Base_node_config.t
×
319
    }
320
  [@@deriving to_yojson]
321

322
  type t =
×
323
    { service_name : string
×
324
    ; config : config
×
325
    ; docker_config : Dockerfile.Service.t
×
326
    }
327
  [@@deriving to_yojson]
328

329
  let create_cmd config =
330
    [ "internal"
×
331
    ; "snark-worker"
332
    ; "-proof-level"
333
    ; config.proof_level
334
    ; "-daemon-address"
335
    ; config.daemon_address ^ ":" ^ config.daemon_port
336
    ; "--shutdown-on-disconnect"
337
    ; "false"
338
    ]
339

340
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment
341
      ~config =
342
    { Dockerfile.Service.image
×
343
    ; command = create_cmd config
×
344
    ; entrypoint
345
    ; ports
346
    ; environment
347
    ; volumes
348
    }
349

350
  let create ~service_name ~image ~ports ~volumes ~config =
351
    let entrypoint = Some [ "/root/entrypoint.sh" ] in
×
352
    let environment = Base_node_config.to_docker_env_vars config.base_config in
353
    let docker_config =
×
354
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint
355
        ~config
356
    in
357
    { service_name; config; docker_config }
358
end
359

360
module Snark_coordinator_config = struct
361
  type config =
×
362
    { snark_coordinator_key : string
×
363
    ; snark_worker_fee : string
×
364
    ; work_selection : string
×
365
    ; worker_nodes : Snark_worker_config.t list
×
366
    ; base_config : Base_node_config.t
×
367
    }
368
  [@@deriving to_yojson]
369

370
  type t =
×
371
    { service_name : string
×
372
    ; config : config
×
373
    ; docker_config : Dockerfile.Service.t
×
374
    }
375
  [@@deriving to_yojson]
376

377
  let snark_coordinator_default_env ~snark_coordinator_key ~snark_worker_fee
378
      ~work_selection =
379
    [ ("MINA_SNARK_KEY", snark_coordinator_key)
×
380
    ; ("MINA_SNARK_FEE", snark_worker_fee)
381
    ; ("WORK_SELECTION", work_selection)
382
    ; ("MINA_CLIENT_TRUSTLIST", "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16")
383
    ]
384

385
  let create_cmd config =
386
    let base_args = Base_node_config.to_list config.base_config in
×
387
    let snark_coordinator_args =
×
388
      [ "daemon"
389
      ; "-run-snark-coordinator"
390
      ; config.snark_coordinator_key
391
      ; "-snark-worker-fee"
392
      ; config.snark_worker_fee
393
      ; "-work-selection"
394
      ; config.work_selection
395
      ]
396
    in
397
    List.concat [ snark_coordinator_args; base_args ]
398

399
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment
400
      ~config =
401
    { Dockerfile.Service.image
×
402
    ; command = create_cmd config
×
403
    ; entrypoint
404
    ; ports
405
    ; environment
406
    ; volumes
407
    }
408

409
  let create ~service_name ~image ~ports ~volumes ~config =
410
    let entrypoint = Some [ "/root/entrypoint.sh" ] in
×
411
    let environment =
412
      snark_coordinator_default_env
413
        ~snark_coordinator_key:config.snark_coordinator_key
414
        ~snark_worker_fee:config.snark_worker_fee
415
        ~work_selection:config.work_selection
416
      @ Base_node_config.to_docker_env_vars config.base_config
×
417
    in
418
    let docker_config =
419
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint
420
        ~config
421
    in
422
    { service_name; config; docker_config }
423
end
424

425
module Postgres_config = struct
426
  type config =
×
427
    { host : string
×
428
    ; username : string
×
429
    ; password : string
×
430
    ; database : string
×
431
    ; port : int
×
432
    }
433
  [@@deriving to_yojson]
434

435
  type t =
×
436
    { service_name : string
×
437
    ; config : config
×
438
    ; docker_config : Dockerfile.Service.t
×
439
    }
440
  [@@deriving to_yojson]
441

442
  let postgres_image = "postgres:16.2-bullseye"
443

444
  let postgres_script =
445
    ( "postgres_entrypoint.sh"
446
    , {|#!/bin/bash
447
# This file is auto-generated by the local integration test framework.
448
# Create the archive database and import the schema
449
psql -U postgres -d archive -f ./create_schema.sql
450
|}
451
    )
452

453
  let postgres_create_schema_volume : Dockerfile.Service.Volume.t =
454
    { type_ = "bind"
455
    ; source = "create_schema.sql"
456
    ; target = "/create_schema.sql"
457
    }
458

459
  let postgres_zkapp_schema_volume : Dockerfile.Service.Volume.t =
460
    { type_ = "bind"
461
    ; source = "zkapp_tables.sql"
462
    ; target = "/zkapp_tables.sql"
463
    }
464

465
  let postgres_entrypoint_volume : Dockerfile.Service.Volume.t =
466
    { type_ = "bind"
467
    ; source = "postgres_entrypoint.sh"
468
    ; target = "/docker-entrypoint-initdb.d/postgres_entrypoint.sh"
469
    }
470

471
  let postgres_default_envs ~username ~password ~database ~port =
472
    [ ("POSTGRES_USER", username)
×
473
    ; ("POSTGRES_PASSWORD", password)
474
    ; ("POSTGRES_DB", database)
475
    ; ("PGPASSWORD", password)
476
    ; ("POSTGRESQL_PORT_NUMBER", port)
477
    ]
478

479
  let create_connection_uri ~host ~username ~password ~database ~port =
480
    Printf.sprintf "postgres://%s:%s@%s:%d/%s" username password host port
×
481
      database
482

483
  let to_connection_uri t =
484
    create_connection_uri ~host:t.host ~port:t.port ~username:t.username
×
485
      ~password:t.password ~database:t.database
486

487
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment =
488
    { Dockerfile.Service.image
×
489
    ; command = []
490
    ; entrypoint
491
    ; ports
492
    ; environment
493
    ; volumes
494
    }
495

496
  let create ~service_name ~image ~ports ~volumes ~config =
497
    let environment =
×
498
      postgres_default_envs ~username:config.username ~password:config.password
499
        ~database:config.database
500
        ~port:(Int.to_string config.port)
×
501
    in
502
    let docker_config =
503
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint:None
504
    in
505
    { service_name; config; docker_config }
506
end
507

508
module Archive_node_config = struct
509
  type config =
×
510
    { postgres_config : Postgres_config.t
×
511
    ; server_port : int
×
512
    ; base_config : Base_node_config.t
×
513
    }
514
  [@@deriving to_yojson]
515

516
  type t =
×
517
    { service_name : string
×
518
    ; config : config
×
519
    ; docker_config : Dockerfile.Service.t
×
520
    }
521
  [@@deriving to_yojson]
522

523
  let archive_entrypoint_script =
524
    ( "archive_entrypoint.sh"
525
    , {|#!/bin/bash
526
  # This file is auto-generated by the local integration test framework.
527
  # Sleep for 15 seconds
528
  echo "Sleeping for 15 seconds before starting..."
529
  sleep 15
530
  exec "$@"|}
531
    )
532

533
  let archive_entrypoint_volume : Docker_compose.Dockerfile.Service.Volume.t =
534
    { type_ = "bind"
535
    ; source = "archive_entrypoint.sh"
536
    ; target = Base_node_config.container_entrypoint_path
537
    }
538

539
  let create_cmd config =
540
    let base_args =
×
541
      [ "mina-archive"
542
      ; "run"
543
      ; "-postgres-uri"
544
      ; Postgres_config.to_connection_uri config.postgres_config.config
×
545
      ; "-server-port"
546
      ; Int.to_string config.server_port
×
547
      ]
548
    in
549
    let runtime_config_path =
550
      match config.base_config.runtime_config_path with
551
      | Some path ->
×
552
          [ "-config-file"; path ]
553
      | None ->
×
554
          []
555
    in
556
    List.concat [ base_args; runtime_config_path ]
557

558
  let create_docker_config ~image ~entrypoint ~ports ~volumes ~environment
559
      ~config =
560
    { Dockerfile.Service.image
×
561
    ; command = create_cmd config
×
562
    ; entrypoint
563
    ; ports
564
    ; environment
565
    ; volumes
566
    }
567

568
  let create ~service_name ~image ~ports ~volumes ~config =
569
    let entrypoint = Some [ "/root/entrypoint.sh" ] in
×
570
    let environment = Base_node_config.to_docker_env_vars config.base_config in
571
    let docker_config =
×
572
      create_docker_config ~image ~ports ~volumes ~environment ~entrypoint
573
        ~config
574
    in
575
    { service_name; config; docker_config }
576
end
1✔
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