@vtechcom/hexcore 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/LICENSE +201 -0
- package/README.md +283 -0
- package/dist/app.module.js +55 -0
- package/dist/app.module.js.map +1 -0
- package/dist/auth.js +151 -0
- package/dist/auth.js.map +1 -0
- package/dist/chain/cost-models.js +81 -0
- package/dist/chain/cost-models.js.map +1 -0
- package/dist/chain/provider.js +269 -0
- package/dist/chain/provider.js.map +1 -0
- package/dist/chain/socket.js +48 -0
- package/dist/chain/socket.js.map +1 -0
- package/dist/cli/doctor.js +43 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/hexcore.js +435 -0
- package/dist/cli/hexcore.js.map +1 -0
- package/dist/common/auth.guard.js +66 -0
- package/dist/common/auth.guard.js.map +1 -0
- package/dist/common/http.js +171 -0
- package/dist/common/http.js.map +1 -0
- package/dist/common/zod-validation.pipe.js +47 -0
- package/dist/common/zod-validation.pipe.js.map +1 -0
- package/dist/config.js +354 -0
- package/dist/config.js.map +1 -0
- package/dist/config.module.js +35 -0
- package/dist/config.module.js.map +1 -0
- package/dist/controllers/cardano.controller.js +173 -0
- package/dist/controllers/cardano.controller.js.map +1 -0
- package/dist/controllers/heads.controller.js +225 -0
- package/dist/controllers/heads.controller.js.map +1 -0
- package/dist/controllers/setup.controller.js +127 -0
- package/dist/controllers/setup.controller.js.map +1 -0
- package/dist/controllers/system.controller.js +153 -0
- package/dist/controllers/system.controller.js.map +1 -0
- package/dist/db/database.module.js +73 -0
- package/dist/db/database.module.js.map +1 -0
- package/dist/db/index.js +135 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/repositories.js +220 -0
- package/dist/db/repositories.js.map +1 -0
- package/dist/docker/container-stats.js +134 -0
- package/dist/docker/container-stats.js.map +1 -0
- package/dist/docker/docker.service.js +335 -0
- package/dist/docker/docker.service.js.map +1 -0
- package/dist/hydra/argv.js +172 -0
- package/dist/hydra/argv.js.map +1 -0
- package/dist/hydra/blockfrost-keys.js +15 -0
- package/dist/hydra/blockfrost-keys.js.map +1 -0
- package/dist/hydra/boot-progress.js +165 -0
- package/dist/hydra/boot-progress.js.map +1 -0
- package/dist/hydra/capabilities.js +131 -0
- package/dist/hydra/capabilities.js.map +1 -0
- package/dist/hydra/head.service.js +1072 -0
- package/dist/hydra/head.service.js.map +1 -0
- package/dist/hydra/keys.js +301 -0
- package/dist/hydra/keys.js.map +1 -0
- package/dist/hydra/node-monitor.service.js +265 -0
- package/dist/hydra/node-monitor.service.js.map +1 -0
- package/dist/hydra/ws-client.js +177 -0
- package/dist/hydra/ws-client.js.map +1 -0
- package/dist/main.js +106 -0
- package/dist/main.js.map +1 -0
- package/dist/preflight.js +215 -0
- package/dist/preflight.js.map +1 -0
- package/dist/settings.js +243 -0
- package/dist/settings.js.map +1 -0
- package/dist/setup.service.js +257 -0
- package/dist/setup.service.js.map +1 -0
- package/dist/version.js +46 -0
- package/dist/version.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/api.d.ts +730 -0
- package/node_modules/@hexcore/shared/dist/cjs/api.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/api.js +358 -0
- package/node_modules/@hexcore/shared/dist/cjs/api.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/domain.d.ts +298 -0
- package/node_modules/@hexcore/shared/dist/cjs/domain.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/domain.js +49 -0
- package/node_modules/@hexcore/shared/dist/cjs/domain.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.d.ts +279 -0
- package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.js +453 -0
- package/node_modules/@hexcore/shared/dist/cjs/hydra-versions.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/index.d.ts +7 -0
- package/node_modules/@hexcore/shared/dist/cjs/index.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/index.js +23 -0
- package/node_modules/@hexcore/shared/dist/cjs/index.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/naming.d.ts +118 -0
- package/node_modules/@hexcore/shared/dist/cjs/naming.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/naming.js +103 -0
- package/node_modules/@hexcore/shared/dist/cjs/naming.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/offline.d.ts +73 -0
- package/node_modules/@hexcore/shared/dist/cjs/offline.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/offline.js +80 -0
- package/node_modules/@hexcore/shared/dist/cjs/offline.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/protocol-params.d.ts +79 -0
- package/node_modules/@hexcore/shared/dist/cjs/protocol-params.d.ts.map +1 -0
- package/node_modules/@hexcore/shared/dist/cjs/protocol-params.js +223 -0
- package/node_modules/@hexcore/shared/dist/cjs/protocol-params.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/api.js +355 -0
- package/node_modules/@hexcore/shared/dist/esm/api.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/domain.js +46 -0
- package/node_modules/@hexcore/shared/dist/esm/domain.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/hydra-versions.js +441 -0
- package/node_modules/@hexcore/shared/dist/esm/hydra-versions.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/index.js +7 -0
- package/node_modules/@hexcore/shared/dist/esm/index.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/naming.js +95 -0
- package/node_modules/@hexcore/shared/dist/esm/naming.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/offline.js +75 -0
- package/node_modules/@hexcore/shared/dist/esm/offline.js.map +1 -0
- package/node_modules/@hexcore/shared/dist/esm/package.json +3 -0
- package/node_modules/@hexcore/shared/dist/esm/protocol-params.js +217 -0
- package/node_modules/@hexcore/shared/dist/esm/protocol-params.js.map +1 -0
- package/node_modules/@hexcore/shared/package.json +15 -0
- package/package.json +67 -0
- package/web/200.html +23 -0
- package/web/404.html +23 -0
- package/web/_nuxt/2MxohCD-.js +1 -0
- package/web/_nuxt/4pFXjB_u.js +1 -0
- package/web/_nuxt/B-v0dEQX.js +1 -0
- package/web/_nuxt/B4yE3U25.js +1 -0
- package/web/_nuxt/BFh8Ai0L.js +1 -0
- package/web/_nuxt/BgPn4NJH.js +1 -0
- package/web/_nuxt/Bj1xviSh.js +1 -0
- package/web/_nuxt/BnotlrL7.js +1 -0
- package/web/_nuxt/C1YRg2ic.js +1 -0
- package/web/_nuxt/CGD7MYQH.js +1 -0
- package/web/_nuxt/CQcG7Bu4.js +1 -0
- package/web/_nuxt/CS3KqpH_.js +1 -0
- package/web/_nuxt/CT-yt694.js +1 -0
- package/web/_nuxt/CZK6xUH-.js +1 -0
- package/web/_nuxt/CcdyYRYz.js +1 -0
- package/web/_nuxt/CePNTU1S.js +1 -0
- package/web/_nuxt/CgPLsCeU.js +5 -0
- package/web/_nuxt/CkCrahXt.js +1 -0
- package/web/_nuxt/CnOqDT9k.js +3 -0
- package/web/_nuxt/CqsSss-D.js +1 -0
- package/web/_nuxt/Cr8dL64Q.js +1 -0
- package/web/_nuxt/D3CwzwU0.js +1 -0
- package/web/_nuxt/DDANn6-H.js +1 -0
- package/web/_nuxt/DDl9uKIA.js +1 -0
- package/web/_nuxt/DL9i0ayn.js +1 -0
- package/web/_nuxt/DLNoK9BC.js +1 -0
- package/web/_nuxt/DLztFeOQ.js +1 -0
- package/web/_nuxt/DPihKXdt.js +1 -0
- package/web/_nuxt/DXyr6Naa.js +1 -0
- package/web/_nuxt/DeDg5p0D.js +1 -0
- package/web/_nuxt/DgDlQiDU.js +1 -0
- package/web/_nuxt/DyPI7qJE.js +30 -0
- package/web/_nuxt/LGfPBi70.js +1 -0
- package/web/_nuxt/Onf26W-r.js +1 -0
- package/web/_nuxt/QZNQe_OX.js +1 -0
- package/web/_nuxt/Y8IJM-iz.js +1 -0
- package/web/_nuxt/YUGC0nt0.js +1 -0
- package/web/_nuxt/builds/latest.json +1 -0
- package/web/_nuxt/builds/meta/7e461629-93e2-4694-b237-6d5c6a85c97c.json +1 -0
- package/web/_nuxt/builds/meta/dev.json +1 -0
- package/web/_nuxt/entry.BxsAxZxf.css +1 -0
- package/web/_nuxt/error-404.XbtAw-qw.css +1 -0
- package/web/_nuxt/error-500.CNHVltWM.css +1 -0
- package/web/_nuxt/rS90pPZ_.js +1 -0
- package/web/_nuxt/rhEiP908.js +1 -0
- package/web/_nuxt/vSj9Ec0g.js +1 -0
- package/web/_nuxt/woNjBJMN.js +1 -0
- package/web/favicon.svg +28 -0
- package/web/heads/index.html +23 -0
- package/web/heads/new/index.html +23 -0
- package/web/index.html +23 -0
- package/web/login/index.html +23 -0
- package/web/logo.svg +56 -0
- package/web/settings/index.html +23 -0
- package/web/setup/index.html +23 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reading Docker's stats payload, without Docker.
|
|
4
|
+
*
|
|
5
|
+
* Kept a pure function for the same reason `hydra/argv.ts` is: the interesting
|
|
6
|
+
* part is arithmetic that is wrong in obvious ways and right in non-obvious
|
|
7
|
+
* ones, and it can be tested against captured samples instead of against a
|
|
8
|
+
* daemon. Two pieces of that arithmetic are worth knowing before changing it.
|
|
9
|
+
*
|
|
10
|
+
* **CPU is a delta between two samples, not a reading.** The cgroup counter is
|
|
11
|
+
* cumulative nanoseconds, so a percentage only exists relative to a previous
|
|
12
|
+
* sample. Docker takes that second sample for us when the stats request asks
|
|
13
|
+
* for `stream=false` without `one-shot`; ask for `one-shot=true` and `precpu`
|
|
14
|
+
* comes back zeroed, every delta becomes the whole lifetime of the container,
|
|
15
|
+
* and the number reads as a plausible few percent while meaning nothing.
|
|
16
|
+
*
|
|
17
|
+
* **Memory has to have the page cache subtracted.** The raw cgroup `usage`
|
|
18
|
+
* includes file cache, and a hydra-node reads a ~426 KB trusted setup and maps
|
|
19
|
+
* its persistence — that cache is memory the kernel gives back the moment
|
|
20
|
+
* anything else wants it. `docker stats` subtracts it and so do we, otherwise
|
|
21
|
+
* the number that the ~500 MB-per-node budget is checked against is inflated by
|
|
22
|
+
* whatever the node last touched.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.emptyUsage = emptyUsage;
|
|
26
|
+
exports.readContainerStats = readContainerStats;
|
|
27
|
+
const EMPTY = {
|
|
28
|
+
cpuPercent: null,
|
|
29
|
+
cpuCores: null,
|
|
30
|
+
memoryBytes: null,
|
|
31
|
+
memoryLimitBytes: null,
|
|
32
|
+
memoryPercent: null,
|
|
33
|
+
netRxBytes: null,
|
|
34
|
+
netTxBytes: null,
|
|
35
|
+
blockReadBytes: null,
|
|
36
|
+
blockWriteBytes: null,
|
|
37
|
+
pids: null,
|
|
38
|
+
};
|
|
39
|
+
function emptyUsage() {
|
|
40
|
+
return { ...EMPTY };
|
|
41
|
+
}
|
|
42
|
+
function readContainerStats(raw) {
|
|
43
|
+
if (!raw || typeof raw !== 'object')
|
|
44
|
+
return emptyUsage();
|
|
45
|
+
const stats = raw;
|
|
46
|
+
return {
|
|
47
|
+
...cpuUsage(stats),
|
|
48
|
+
...memoryUsage(stats),
|
|
49
|
+
...networkUsage(stats),
|
|
50
|
+
...blockIoUsage(stats),
|
|
51
|
+
pids: numberOrNull(stats.pids_stats?.current),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function cpuUsage(stats) {
|
|
55
|
+
const cores = stats.cpu_stats?.online_cpus ?? stats.cpu_stats?.cpu_usage?.percpu_usage?.length ?? null;
|
|
56
|
+
/**
|
|
57
|
+
* There must BE a previous sample before a delta can be taken from it.
|
|
58
|
+
*
|
|
59
|
+
* `system_cpu_usage` is the host's cumulative CPU time — on any real second
|
|
60
|
+
* reading it is an enormous positive number, and it is zero in exactly one
|
|
61
|
+
* situation: `precpu_stats` was never filled in, which is what a `one-shot`
|
|
62
|
+
* request returns. Checking the deltas is not enough to catch that, because
|
|
63
|
+
* subtracting zero leaves both of them positive and the ratio comes out as
|
|
64
|
+
* a believable few percent that is actually "container lifetime over host
|
|
65
|
+
* uptime". This is the check that rejects it.
|
|
66
|
+
*/
|
|
67
|
+
const priorSystem = stats.precpu_stats?.system_cpu_usage ?? 0;
|
|
68
|
+
if (priorSystem <= 0 || !cores)
|
|
69
|
+
return { cpuPercent: null, cpuCores: cores };
|
|
70
|
+
const cpuDelta = (stats.cpu_stats?.cpu_usage?.total_usage ?? 0) - (stats.precpu_stats?.cpu_usage?.total_usage ?? 0);
|
|
71
|
+
const systemDelta = (stats.cpu_stats?.system_cpu_usage ?? 0) - priorSystem;
|
|
72
|
+
/**
|
|
73
|
+
* Both deltas must be positive for the ratio to mean anything. A zero
|
|
74
|
+
* system delta means two reads landed inside the same clock tick; a
|
|
75
|
+
* negative one means the container restarted between them and the counters
|
|
76
|
+
* reset. Null in both cases — "we cannot say" is a fact the UI can render,
|
|
77
|
+
* 0% is a lie.
|
|
78
|
+
*/
|
|
79
|
+
if (cpuDelta <= 0 || systemDelta <= 0)
|
|
80
|
+
return { cpuPercent: null, cpuCores: cores };
|
|
81
|
+
return { cpuPercent: round2((cpuDelta / systemDelta) * cores * 100), cpuCores: cores };
|
|
82
|
+
}
|
|
83
|
+
function memoryUsage(stats) {
|
|
84
|
+
const usage = numberOrNull(stats.memory_stats?.usage);
|
|
85
|
+
const limit = numberOrNull(stats.memory_stats?.limit);
|
|
86
|
+
if (usage === null)
|
|
87
|
+
return { memoryBytes: null, memoryLimitBytes: limit, memoryPercent: null };
|
|
88
|
+
/**
|
|
89
|
+
* cgroup v2 names it `inactive_file`, v1 `total_inactive_file`, and older
|
|
90
|
+
* daemons only report `cache`. Docker Desktop is v2 today and the Linux
|
|
91
|
+
* hosts this also runs on may be either, so take whichever is present
|
|
92
|
+
* rather than picking one and being silently wrong on the other.
|
|
93
|
+
*/
|
|
94
|
+
const cache = stats.memory_stats?.stats ?? {};
|
|
95
|
+
const cached = cache.inactive_file ?? cache.total_inactive_file ?? cache.cache ?? 0;
|
|
96
|
+
const used = Math.max(0, usage - cached);
|
|
97
|
+
return {
|
|
98
|
+
memoryBytes: used,
|
|
99
|
+
memoryLimitBytes: limit,
|
|
100
|
+
memoryPercent: limit && limit > 0 ? round2((used / limit) * 100) : null,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function networkUsage(stats) {
|
|
104
|
+
const interfaces = Object.values(stats.networks ?? {});
|
|
105
|
+
if (interfaces.length === 0)
|
|
106
|
+
return { netRxBytes: null, netTxBytes: null };
|
|
107
|
+
return {
|
|
108
|
+
netRxBytes: interfaces.reduce((sum, i) => sum + (i.rx_bytes ?? 0), 0),
|
|
109
|
+
netTxBytes: interfaces.reduce((sum, i) => sum + (i.tx_bytes ?? 0), 0),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function blockIoUsage(stats) {
|
|
113
|
+
const entries = stats.blkio_stats?.io_service_bytes_recursive;
|
|
114
|
+
// Docker Desktop's VM reports this as null rather than an empty array.
|
|
115
|
+
if (!Array.isArray(entries) || entries.length === 0)
|
|
116
|
+
return { blockReadBytes: null, blockWriteBytes: null };
|
|
117
|
+
let read = 0;
|
|
118
|
+
let write = 0;
|
|
119
|
+
for (const entry of entries) {
|
|
120
|
+
const op = (entry.op ?? '').toLowerCase();
|
|
121
|
+
if (op === 'read')
|
|
122
|
+
read += entry.value ?? 0;
|
|
123
|
+
if (op === 'write')
|
|
124
|
+
write += entry.value ?? 0;
|
|
125
|
+
}
|
|
126
|
+
return { blockReadBytes: read, blockWriteBytes: write };
|
|
127
|
+
}
|
|
128
|
+
function numberOrNull(value) {
|
|
129
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
130
|
+
}
|
|
131
|
+
function round2(value) {
|
|
132
|
+
return Math.round(value * 100) / 100;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=container-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-stats.js","sourceRoot":"","sources":["../../src/docker/container-stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
var DockerService_1;
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.DockerService = exports.ImagePullError = exports.DockerUnavailableError = void 0;
|
|
20
|
+
exports.demuxDockerLog = demuxDockerLog;
|
|
21
|
+
/**
|
|
22
|
+
* Docker orchestration.
|
|
23
|
+
*
|
|
24
|
+
* Wraps dockerode with the few operations the head lifecycle needs, plus
|
|
25
|
+
* preflight checks. v1 assumed the daemon was reachable and the image present;
|
|
26
|
+
* when either was false you got a raw ENOENT or a 404 from deep inside a
|
|
27
|
+
* container create. Here every failure is translated into an actionable message.
|
|
28
|
+
*/
|
|
29
|
+
const common_1 = require("@nestjs/common");
|
|
30
|
+
const dockerode_1 = __importDefault(require("dockerode"));
|
|
31
|
+
const node_stream_1 = require("node:stream");
|
|
32
|
+
const shared_1 = require("@hexcore/shared");
|
|
33
|
+
const config_module_1 = require("../config.module");
|
|
34
|
+
const settings_1 = require("../settings");
|
|
35
|
+
class DockerUnavailableError extends Error {
|
|
36
|
+
constructor(cause) {
|
|
37
|
+
/**
|
|
38
|
+
* The daemon's own words, and nothing else.
|
|
39
|
+
*
|
|
40
|
+
* This message is rendered in the UI, and it used to wrap the cause in a
|
|
41
|
+
* second pair of parentheses and then append both the macOS and the
|
|
42
|
+
* Linux remedy — around 250 characters of which most were wrong for
|
|
43
|
+
* whoever was reading them. Docker says why itself ("Docker Desktop is
|
|
44
|
+
* manually paused", "connect ENOENT ..."), so the remedy belongs where
|
|
45
|
+
* there is room for it: preflight adds a platform-specific hint, the UI
|
|
46
|
+
* banner says what is blocked.
|
|
47
|
+
*/
|
|
48
|
+
super(`Cannot reach the Docker daemon: ${cause.replace(/\s+/g, ' ').trim()}`);
|
|
49
|
+
this.name = 'DockerUnavailableError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.DockerUnavailableError = DockerUnavailableError;
|
|
53
|
+
/**
|
|
54
|
+
* A pull that could not produce the image.
|
|
55
|
+
*
|
|
56
|
+
* Docker's own words name the *repository* and never the tag, so a reference
|
|
57
|
+
* with one character wrong ("aniadev" for "aniadev9") reports a repository the
|
|
58
|
+
* operator has never heard of and does not obviously match what they typed.
|
|
59
|
+
* Since the image is chosen once and only checked at the first start, that is
|
|
60
|
+
* exactly the moment they need to see their own string back.
|
|
61
|
+
*/
|
|
62
|
+
class ImagePullError extends Error {
|
|
63
|
+
constructor(image, cause) {
|
|
64
|
+
const said = cause.replace(/\s+/g, ' ').trim();
|
|
65
|
+
const missing = /pull access denied|repository does not exist|manifest unknown|not found/i.test(said);
|
|
66
|
+
super(missing
|
|
67
|
+
? `Cannot pull "${image}". No such image in the registry, or it is private — check the ` +
|
|
68
|
+
`account and repository spelling and the tag, and that the image is public or the ` +
|
|
69
|
+
`Docker daemon is logged in. Docker said: ${said}`
|
|
70
|
+
: `Cannot pull "${image}". Docker said: ${said}`);
|
|
71
|
+
this.name = 'ImagePullError';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.ImagePullError = ImagePullError;
|
|
75
|
+
let DockerService = DockerService_1 = class DockerService {
|
|
76
|
+
config;
|
|
77
|
+
logger = new common_1.Logger(DockerService_1.name);
|
|
78
|
+
docker;
|
|
79
|
+
constructor(config) {
|
|
80
|
+
this.config = config;
|
|
81
|
+
this.docker = new dockerode_1.default({ socketPath: config.dockerSocket });
|
|
82
|
+
}
|
|
83
|
+
async ping() {
|
|
84
|
+
try {
|
|
85
|
+
await this.docker.ping();
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
throw new DockerUnavailableError(err.message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async version() {
|
|
92
|
+
const v = (await this.docker.version());
|
|
93
|
+
return v.Version ?? 'unknown';
|
|
94
|
+
}
|
|
95
|
+
async hasImage(image) {
|
|
96
|
+
try {
|
|
97
|
+
await this.docker.getImage(image).inspect();
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Pull an image, streaming progress lines to onProgress. */
|
|
105
|
+
async pullImage(image, onProgress) {
|
|
106
|
+
const stream = (await this.docker.pull(image));
|
|
107
|
+
await new Promise((resolvePull, rejectPull) => {
|
|
108
|
+
this.docker.modem.followProgress(stream, (err) => (err ? rejectPull(err) : resolvePull()), (event) => {
|
|
109
|
+
if (onProgress && event.status) {
|
|
110
|
+
onProgress(`${event.status}${event.progress ? ' ' + event.progress : ''}`);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async ensureImage(image, onProgress) {
|
|
116
|
+
if (await this.hasImage(image))
|
|
117
|
+
return;
|
|
118
|
+
this.logger.log(`pulling hydra-node image ${image} (first run only)`);
|
|
119
|
+
try {
|
|
120
|
+
await this.pullImage(image, onProgress);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
// A pull failure is about the reference, not about Docker being
|
|
124
|
+
// unreachable — say which image, since Docker will not.
|
|
125
|
+
throw new ImagePullError(image, err.message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Create the shared user-defined bridge so nodes resolve each other by name. */
|
|
129
|
+
async ensureNetwork() {
|
|
130
|
+
const networks = await this.docker.listNetworks();
|
|
131
|
+
if (networks.some(n => n.Name === shared_1.DOCKER_NETWORK))
|
|
132
|
+
return;
|
|
133
|
+
await this.docker.createNetwork({ Name: shared_1.DOCKER_NETWORK, Driver: 'bridge' });
|
|
134
|
+
this.logger.log(`created docker network ${shared_1.DOCKER_NETWORK}`);
|
|
135
|
+
}
|
|
136
|
+
async removeContainer(name) {
|
|
137
|
+
try {
|
|
138
|
+
const container = this.docker.getContainer(name);
|
|
139
|
+
const info = await container.inspect();
|
|
140
|
+
if (info.State.Running)
|
|
141
|
+
await container.stop({ t: 10 }).catch(() => undefined);
|
|
142
|
+
await container.remove({ force: true });
|
|
143
|
+
this.logger.debug(`container ${name} removed`);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const code = err.statusCode;
|
|
147
|
+
if (code !== 404)
|
|
148
|
+
this.logger.warn(`failed removing container ${name}: ${err.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async createAndStart(spec) {
|
|
152
|
+
// Always clear a stale container with the same name first: names are
|
|
153
|
+
// deterministic in v2, so a leftover from a crashed boot would
|
|
154
|
+
// otherwise make every subsequent start fail with 409 Conflict.
|
|
155
|
+
await this.removeContainer(spec.name);
|
|
156
|
+
const exposed = {};
|
|
157
|
+
const bindings = {};
|
|
158
|
+
for (const p of spec.ports) {
|
|
159
|
+
exposed[`${p}/tcp`] = {};
|
|
160
|
+
bindings[`${p}/tcp`] = [{ HostPort: String(p) }];
|
|
161
|
+
}
|
|
162
|
+
const container = await this.docker.createContainer({
|
|
163
|
+
name: spec.name,
|
|
164
|
+
Image: spec.image,
|
|
165
|
+
Cmd: spec.cmd,
|
|
166
|
+
Labels: { [shared_1.LABEL_MANAGED]: 'true', ...spec.labels },
|
|
167
|
+
Env: spec.env,
|
|
168
|
+
User: spec.user,
|
|
169
|
+
ExposedPorts: exposed,
|
|
170
|
+
HostConfig: {
|
|
171
|
+
NetworkMode: shared_1.DOCKER_NETWORK,
|
|
172
|
+
Binds: spec.binds,
|
|
173
|
+
PortBindings: bindings,
|
|
174
|
+
RestartPolicy: { Name: 'unless-stopped' },
|
|
175
|
+
...(spec.logRotation
|
|
176
|
+
? {
|
|
177
|
+
LogConfig: {
|
|
178
|
+
Type: 'json-file',
|
|
179
|
+
Config: {
|
|
180
|
+
'max-size': `${spec.logRotation.maxSizeMb}m`,
|
|
181
|
+
'max-file': String(spec.logRotation.maxFiles),
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
: {}),
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
await container.start();
|
|
189
|
+
this.logger.log(`container ${spec.name} started (${container.id.slice(0, 12)})`);
|
|
190
|
+
return container;
|
|
191
|
+
}
|
|
192
|
+
/** All containers this control-plane manages, optionally filtered by head. */
|
|
193
|
+
async listManaged(headId) {
|
|
194
|
+
const label = [`${shared_1.LABEL_MANAGED}=true`];
|
|
195
|
+
if (headId !== undefined)
|
|
196
|
+
label.push(`${shared_1.LABEL_HEAD_ID}=${headId}`);
|
|
197
|
+
return this.docker.listContainers({ all: true, filters: { label } });
|
|
198
|
+
}
|
|
199
|
+
async isRunning(name) {
|
|
200
|
+
try {
|
|
201
|
+
const info = await this.docker.getContainer(name).inspect();
|
|
202
|
+
return info.State.Running;
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async restart(name) {
|
|
209
|
+
await this.docker.getContainer(name).restart();
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Run a throwaway container and return its combined output.
|
|
213
|
+
*
|
|
214
|
+
* Used to ask an image what it supports (`--help`, `--version`) instead of
|
|
215
|
+
* maintaining a version→flags table that goes stale and cannot describe a
|
|
216
|
+
* fork or a `master` tag. The container is removed on exit; a non-zero exit
|
|
217
|
+
* is still a useful answer, since `--help` exits 1 on some builds, so the
|
|
218
|
+
* output is returned rather than treated as failure.
|
|
219
|
+
*/
|
|
220
|
+
async runOnce(image, cmd, timeoutMs = 60_000) {
|
|
221
|
+
await this.ensureImage(image);
|
|
222
|
+
const chunks = [];
|
|
223
|
+
const sink = new node_stream_1.Writable({
|
|
224
|
+
write(chunk, _enc, done) {
|
|
225
|
+
chunks.push(chunk);
|
|
226
|
+
done();
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
const run = this.docker.run(image, cmd, sink, {
|
|
230
|
+
HostConfig: { AutoRemove: true, NetworkMode: 'none' },
|
|
231
|
+
Tty: false,
|
|
232
|
+
});
|
|
233
|
+
// dockerode's run() resolves only when the container exits; a hung
|
|
234
|
+
// image would otherwise stall boot indefinitely.
|
|
235
|
+
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`timed out after ${timeoutMs}ms`)), timeoutMs).unref?.());
|
|
236
|
+
try {
|
|
237
|
+
await Promise.race([run, timeout]);
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
// Output collected before the failure is still worth returning:
|
|
241
|
+
// `--help` on some builds writes to stderr and exits non-zero.
|
|
242
|
+
if (chunks.length === 0)
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
245
|
+
return demuxDockerLog(Buffer.concat(chunks));
|
|
246
|
+
}
|
|
247
|
+
/** Tail container logs — used by the UI log viewer. */
|
|
248
|
+
async logs(name, tail = 200) {
|
|
249
|
+
try {
|
|
250
|
+
const buf = (await this.docker.getContainer(name).logs({
|
|
251
|
+
stdout: true,
|
|
252
|
+
stderr: true,
|
|
253
|
+
tail,
|
|
254
|
+
timestamps: false,
|
|
255
|
+
}));
|
|
256
|
+
return demuxDockerLog(buf);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
const code = err.statusCode;
|
|
260
|
+
if (code === 404)
|
|
261
|
+
return '';
|
|
262
|
+
throw err;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* One resource sample for a container, or null when it is not there.
|
|
267
|
+
*
|
|
268
|
+
* `stream: false` and NOT `one-shot`: Docker then takes two readings itself
|
|
269
|
+
* and returns the second with `precpu_stats` filled in, which is the only
|
|
270
|
+
* way a CPU percentage exists at all — see docker/container-stats.ts. The
|
|
271
|
+
* cost is that this call blocks for about a second inside the daemon, so it
|
|
272
|
+
* belongs on a request the operator asked for, never on a polling path that
|
|
273
|
+
* runs for every head.
|
|
274
|
+
*/
|
|
275
|
+
async stats(name) {
|
|
276
|
+
try {
|
|
277
|
+
return await this.docker.getContainer(name).stats({ stream: false });
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
const code = err.statusCode;
|
|
281
|
+
if (code === 404)
|
|
282
|
+
return null;
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/** Follow logs as a stream (websocket log tailing). */
|
|
287
|
+
async logStream(name, tail = 50) {
|
|
288
|
+
return (await this.docker.getContainer(name).logs({
|
|
289
|
+
stdout: true,
|
|
290
|
+
stderr: true,
|
|
291
|
+
tail,
|
|
292
|
+
follow: true,
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
labelsFor(headId, nodeId, nodeIndex) {
|
|
296
|
+
return {
|
|
297
|
+
[shared_1.LABEL_HEAD_ID]: String(headId),
|
|
298
|
+
[shared_1.LABEL_NODE_ID]: String(nodeId),
|
|
299
|
+
[shared_1.LABEL_NODE_INDEX]: String(nodeIndex),
|
|
300
|
+
// Which installation owns this. See LABEL_INSTALL — without it a
|
|
301
|
+
// bulk operation cannot tell two Hexcores on one daemon apart.
|
|
302
|
+
[shared_1.LABEL_INSTALL]: this.installId,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
/** This installation's id, derived from its state dir. */
|
|
306
|
+
get installId() {
|
|
307
|
+
return (0, settings_1.installId)(this.config.stateDir);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
exports.DockerService = DockerService;
|
|
311
|
+
exports.DockerService = DockerService = DockerService_1 = __decorate([
|
|
312
|
+
(0, common_1.Injectable)(),
|
|
313
|
+
__param(0, (0, common_1.Inject)(config_module_1.APP_CONFIG)),
|
|
314
|
+
__metadata("design:paramtypes", [Object])
|
|
315
|
+
], DockerService);
|
|
316
|
+
/**
|
|
317
|
+
* Docker multiplexes stdout/stderr into 8-byte-framed chunks when the container
|
|
318
|
+
* has no TTY. Strip the frames so the UI shows clean lines.
|
|
319
|
+
*/
|
|
320
|
+
function demuxDockerLog(buf) {
|
|
321
|
+
const out = [];
|
|
322
|
+
let offset = 0;
|
|
323
|
+
while (offset + 8 <= buf.length) {
|
|
324
|
+
const type = buf[offset];
|
|
325
|
+
// A valid frame header starts with stream type 0/1/2 and 3 zero bytes.
|
|
326
|
+
if (type > 2 || buf[offset + 1] !== 0 || buf[offset + 2] !== 0 || buf[offset + 3] !== 0) {
|
|
327
|
+
return buf.toString('utf8');
|
|
328
|
+
}
|
|
329
|
+
const len = buf.readUInt32BE(offset + 4);
|
|
330
|
+
out.push(buf.toString('utf8', offset + 8, offset + 8 + len));
|
|
331
|
+
offset += 8 + len;
|
|
332
|
+
}
|
|
333
|
+
return out.join('');
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=docker.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.service.js","sourceRoot":"","sources":["../../src/docker/docker.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isOffline = isOffline;
|
|
4
|
+
exports.backendArgs = backendArgs;
|
|
5
|
+
exports.scriptArgs = scriptArgs;
|
|
6
|
+
exports.buildNodeArgv = buildNodeArgv;
|
|
7
|
+
/**
|
|
8
|
+
* hydra-node argv construction.
|
|
9
|
+
*
|
|
10
|
+
* Pure functions so the exact flags a head boots with can be asserted in tests
|
|
11
|
+
* without Docker, a Blockfrost key, or a running Nest app. Getting these wrong
|
|
12
|
+
* is expensive: an unknown or conflicting flag aborts hydra-node during option
|
|
13
|
+
* parsing, the container dies instantly, and the head reports a generic
|
|
14
|
+
* "node never became ready" that points nowhere near the real cause.
|
|
15
|
+
*/
|
|
16
|
+
const shared_1 = require("@hexcore/shared");
|
|
17
|
+
const keys_1 = require("./keys");
|
|
18
|
+
/** True for heads whose layer-1 interface is disabled entirely. See offline.ts. */
|
|
19
|
+
function isOffline(head) {
|
|
20
|
+
return head.chain_backend === 'offline';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Chain backend flags.
|
|
24
|
+
*
|
|
25
|
+
* The backends are mutually exclusive in hydra-node's option parser:
|
|
26
|
+
* --blockfrost cannot be combined with --testnet-magic / --node-socket.
|
|
27
|
+
*/
|
|
28
|
+
function backendArgs(head, nodeIndex, opts) {
|
|
29
|
+
const cp = (0, shared_1.containerHeadPaths)(head.id);
|
|
30
|
+
/**
|
|
31
|
+
* Offline mode is a different branch of the option parser, not a variant of
|
|
32
|
+
* the online backends: no network magic, no socket, no Blockfrost, no
|
|
33
|
+
* scripts. `--initial-utxo` is the L2 ledger's whole starting state.
|
|
34
|
+
*
|
|
35
|
+
* `--ledger-genesis` is emitted only when a genesis file was actually
|
|
36
|
+
* written. hydra-node's own default is to have none, and pointing the flag
|
|
37
|
+
* at a missing file is a hard startup failure.
|
|
38
|
+
*/
|
|
39
|
+
if (isOffline(head)) {
|
|
40
|
+
const args = ['--offline-head-seed', head.offline_head_seed || (0, shared_1.defaultOfflineHeadSeed)(head.id)];
|
|
41
|
+
args.push('--initial-utxo', cp.initialUtxo);
|
|
42
|
+
if (head.offline_ledger_genesis)
|
|
43
|
+
args.push('--ledger-genesis', cp.ledgerGenesis);
|
|
44
|
+
return args;
|
|
45
|
+
}
|
|
46
|
+
if (head.chain_backend === 'cardano-node') {
|
|
47
|
+
return [...(0, keys_1.networkArgs)(head.network), '--node-socket', '/cardano-node/node.socket'];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Each node reads its own token file. hydra-node takes a path, not a key,
|
|
51
|
+
* so per-node keys can only be expressed as per-node files — and pointing
|
|
52
|
+
* every node at one shared file would silently put N nodes on a single
|
|
53
|
+
* Blockfrost rate-limit budget.
|
|
54
|
+
*/
|
|
55
|
+
const args = ['--blockfrost', cp.nodeBlockfrostToken(nodeIndex)];
|
|
56
|
+
/**
|
|
57
|
+
* Blockfrost polls over HTTP rather than following the chain, so a node's
|
|
58
|
+
* tip lags — upstream measured 50-80s on preprod against ~0s for a local
|
|
59
|
+
* socket. hydra-node defaults --unsynced-period to HALF the contestation
|
|
60
|
+
* period, so a common 120s contestation yields 60s, squarely inside that
|
|
61
|
+
* drift band.
|
|
62
|
+
*
|
|
63
|
+
* The consequence is not cosmetic: past the unsynced period hydra-node
|
|
64
|
+
* stops signing snapshots AND rejects client input, so a deposit can
|
|
65
|
+
* silently expire unsigned while the head looks healthy.
|
|
66
|
+
*
|
|
67
|
+
* Raise it only when the node's own default would be tighter, and never
|
|
68
|
+
* lower a value the operator deliberately set higher.
|
|
69
|
+
*/
|
|
70
|
+
if (opts.caps.unsyncedPeriod) {
|
|
71
|
+
const nodeDefault = Math.floor(head.contestation_period / 2);
|
|
72
|
+
args.push('--unsynced-period', `${Math.max(opts.unsyncedPeriod, nodeDefault)}s`);
|
|
73
|
+
}
|
|
74
|
+
if (opts.caps.blockfrostTimeouts) {
|
|
75
|
+
args.push('--blockfrost-query-timeout', String(opts.blockfrostQueryTimeout), '--blockfrost-retry-timeout', String(opts.blockfrostRetryTimeout));
|
|
76
|
+
}
|
|
77
|
+
return args;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Script selection.
|
|
81
|
+
*
|
|
82
|
+
* An explicit tx id wins; otherwise --network picks the last pre-published
|
|
83
|
+
* scripts for that network, which is what lets a head boot with no setup. The
|
|
84
|
+
* two are mutually exclusive, and older images may support neither.
|
|
85
|
+
*/
|
|
86
|
+
function scriptArgs(head, opts) {
|
|
87
|
+
// Offline heads never touch a chain, so there are no on-chain scripts to
|
|
88
|
+
// select. Both flags belong to the online branch and would abort parsing.
|
|
89
|
+
if (isOffline(head))
|
|
90
|
+
return [];
|
|
91
|
+
if (opts.hydraScriptsTxId)
|
|
92
|
+
return ['--hydra-scripts-tx-id', opts.hydraScriptsTxId];
|
|
93
|
+
return opts.caps.network ? ['--network', head.network] : [];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Full argv for one node. Peers are addressed by container name on the shared
|
|
97
|
+
* bridge network, so a head behaves identically on a laptop and on a server
|
|
98
|
+
* without host-network workarounds.
|
|
99
|
+
*/
|
|
100
|
+
function buildNodeArgv(head, node, peers, opts) {
|
|
101
|
+
const cp = (0, shared_1.containerHeadPaths)(head.id);
|
|
102
|
+
const self = cp.nodeKeys(node.node_index);
|
|
103
|
+
const offline = isOffline(head);
|
|
104
|
+
/**
|
|
105
|
+
* Peer wiring works in both modes, but not identically.
|
|
106
|
+
*
|
|
107
|
+
* `--peer` and `--hydra-verification-key` sit OUTSIDE hydra-node's
|
|
108
|
+
* chain-config group, so an offline head forms a multi-party Head over the
|
|
109
|
+
* same network layer as an online one. `--cardano-verification-key` does
|
|
110
|
+
* not: it is inside the online branch, and passing it alongside
|
|
111
|
+
* `--offline-head-seed` aborts option parsing. It is dropped rather than
|
|
112
|
+
* substituted, because offline peers authorise nothing on chain.
|
|
113
|
+
*/
|
|
114
|
+
const peerArgs = peers.flatMap(peer => {
|
|
115
|
+
const pk = cp.nodeKeys(peer.node_index);
|
|
116
|
+
return [
|
|
117
|
+
'--peer',
|
|
118
|
+
`${peer.name}:${peer.p2p_port}`,
|
|
119
|
+
'--hydra-verification-key',
|
|
120
|
+
pk.hydraVk,
|
|
121
|
+
...(offline ? [] : ['--cardano-verification-key', pk.cardanoVk]),
|
|
122
|
+
];
|
|
123
|
+
});
|
|
124
|
+
return [
|
|
125
|
+
// --quiet is a top-level flag; keeping it first also keeps it clear of
|
|
126
|
+
// the mutually exclusive backend groups below.
|
|
127
|
+
...(head.log_quiet ? ['--quiet'] : []),
|
|
128
|
+
'--node-id',
|
|
129
|
+
node.name,
|
|
130
|
+
'--listen',
|
|
131
|
+
`0.0.0.0:${node.p2p_port}`,
|
|
132
|
+
'--advertise',
|
|
133
|
+
`${node.name}:${node.p2p_port}`,
|
|
134
|
+
'--api-host',
|
|
135
|
+
'0.0.0.0',
|
|
136
|
+
'--api-port',
|
|
137
|
+
String(node.api_port),
|
|
138
|
+
'--monitoring-port',
|
|
139
|
+
String(node.monitoring_port),
|
|
140
|
+
'--hydra-signing-key',
|
|
141
|
+
self.hydraSk,
|
|
142
|
+
/**
|
|
143
|
+
* Everything below the Hydra key belongs to the online branch of the
|
|
144
|
+
* option parser.
|
|
145
|
+
*
|
|
146
|
+
* The Cardano key authorises on-chain Hydra transactions and pays their
|
|
147
|
+
* fuel; the two periods bound on-chain close and deposit deadlines.
|
|
148
|
+
* Offline mode has no chain for any of it, and hydra-node rejects the
|
|
149
|
+
* flags outright rather than ignoring them — which is why they are
|
|
150
|
+
* dropped here instead of being passed with harmless values.
|
|
151
|
+
*/
|
|
152
|
+
...(offline ? [] : ['--cardano-signing-key', self.cardanoSk]),
|
|
153
|
+
'--persistence-dir',
|
|
154
|
+
cp.nodePersistence(node.node_index),
|
|
155
|
+
'--persistence-rotate-after',
|
|
156
|
+
String(head.persistence_rotate_after),
|
|
157
|
+
...(offline
|
|
158
|
+
? []
|
|
159
|
+
: ['--contestation-period', `${head.contestation_period}s`, '--deposit-period', `${head.deposit_period}s`]),
|
|
160
|
+
'--ledger-protocol-parameters',
|
|
161
|
+
cp.protocolParameters,
|
|
162
|
+
...peerArgs,
|
|
163
|
+
...scriptArgs(head, opts),
|
|
164
|
+
...backendArgs(head, node.node_index, opts),
|
|
165
|
+
// Appended, never merged: these must be flags nothing above emits.
|
|
166
|
+
// hydra-node's parser rejects a repeated option rather than letting the
|
|
167
|
+
// last one win, so a duplicate here kills the container at startup —
|
|
168
|
+
// hence the test asserting no profile collides with the base argv.
|
|
169
|
+
...(opts.extraArgs ?? []),
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=argv.js.map
|