@parity/product-lab 0.1.2 → 0.3.0
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 +26 -0
- package/adapters/environment/engine/README.md +22 -3
- package/adapters/environment/engine/src/engine/engine-config.d.ts +1 -0
- package/adapters/environment/engine/src/engine/fork-bundle.d.ts +1 -1
- package/adapters/environment/engine/src/engine/fork-bundle.js +2 -2
- package/adapters/environment/engine/src/engine/fork-refresh.d.ts +4 -7
- package/adapters/environment/engine/src/engine/fork-refresh.js +52 -23
- package/adapters/environment/engine/src/engine/published-bundle.d.ts +19 -15
- package/adapters/environment/engine/src/engine/published-bundle.js +44 -51
- package/adapters/environment/engine/src/index.d.ts +3 -2
- package/adapters/environment/engine/src/index.js +3 -2
- package/adapters/environment/engine/src/saved-fork/saved-fork-tooling.d.ts +1 -1
- package/adapters/environment/engine/src/saved-fork/saved-fork-tooling.js +5 -2
- package/adapters/environment/engine/src/saved-fork/saved-fork.js +1 -1
- package/adapters/environment/engine/src/setup/engine-build.d.ts +4 -4
- package/adapters/environment/engine/src/setup/engine-build.js +14 -4
- package/adapters/environment/engine/src/setup/engine-tooling.d.ts +33 -0
- package/adapters/environment/engine/src/setup/engine-tooling.js +59 -0
- package/adapters/environment/engine/src/setup/node-workspace.patch +403 -0
- package/adapters/environment/engine/src/setup/patch-catalogue.d.ts +23 -0
- package/adapters/environment/engine/src/setup/patch-catalogue.js +8 -0
- package/adapters/environment/engine/src/setup/patches.d.ts +15 -1
- package/adapters/environment/engine/src/setup/patches.js +17 -2
- package/adapters/environment/engine/src/setup/prepare-engine.d.ts +6 -5
- package/adapters/environment/engine/src/setup/prepare-engine.js +27 -10
- package/composition/README.md +6 -4
- package/composition/src/engine-setup.js +9 -3
- package/composition/src/index.d.ts +2 -1
- package/composition/src/index.js +2 -1
- package/composition/src/people-dev/onboarding.d.ts +17 -3
- package/composition/src/people-dev/onboarding.js +25 -9
- package/composition/src/previewnet-genesis.d.ts +62 -0
- package/composition/src/previewnet-genesis.js +127 -0
- package/core/application/src/runs/failure-rules.js +5 -2
- package/entrypoints/cli/src/setup-commands.d.ts +1 -1
- package/entrypoints/cli/src/setup-commands.js +3 -1
- package/package.json +1 -1
|
@@ -231,7 +231,7 @@ export function savedForkEnvironment(fork, settings) {
|
|
|
231
231
|
dashboard: `http://127.0.0.1:${ports.DASHBOARD_PORT}`, extraPath: engine.extraPath,
|
|
232
232
|
startupTimeoutMs: SAVED_FORK_STARTUP_MS, ports, nodePorts: { from: block.base + 900, to: block.base + 949 },
|
|
233
233
|
template: true, isolate: true, expose: false, ...(fork.topology ? { forkTopology: fork.topology } : {}),
|
|
234
|
-
|
|
234
|
+
enginePatch: recordedPatch(prepared.build),
|
|
235
235
|
...(settings.txpoolLog ? { txpoolLog: settings.txpoolLog } : {}), ...(settings.bulletinAuthoring ? { bulletinAuthoring: settings.bulletinAuthoring } : {}),
|
|
236
236
|
seed: networkSeedDirectory(settings.seedsDir, { network: NETWORK, checkout: engine.checkout, ...(fork.topology ? { topology: fork.topology } : {}) }),
|
|
237
237
|
});
|
|
@@ -3,11 +3,11 @@ import type { SyncCommandRunner } from "@parity/product-lab/ports/system";
|
|
|
3
3
|
export declare const NODE_VERIFIER_OPTION = "--node-verifier";
|
|
4
4
|
export type NodeVerifier = "metric" | "none";
|
|
5
5
|
export declare function nodeVerifierArgs(verifier: NodeVerifier | undefined): string[];
|
|
6
|
-
/**
|
|
7
|
-
export declare const ENGINE_PATCHES: readonly ["owned-processes", "none"];
|
|
6
|
+
/** Stock and the optional shipped fix (node-workspace); owned-processes is recognized only to refuse stale configurations. */
|
|
7
|
+
export declare const ENGINE_PATCHES: readonly ["owned-processes", "none", "node-workspace"];
|
|
8
8
|
export type EnginePatch = (typeof ENGINE_PATCHES)[number];
|
|
9
9
|
export declare const ENGINE_PATCH_RETIRED = "the owned-processes Engine patch is retired; prepare stock Engine v0.11.0 instead";
|
|
10
10
|
/** The build must exist. The prepared checkout's pin and record are checked by preparedEngine. */
|
|
11
|
-
export declare function engineBuildIssue(checkout: string,
|
|
12
|
-
/** Before every start, refuse retired
|
|
11
|
+
export declare function engineBuildIssue(checkout: string, commands: SyncCommandRunner, patch?: EnginePatch): string | undefined;
|
|
12
|
+
/** Before every start, verify the optional patch and refuse retired configurations and incomplete builds. */
|
|
13
13
|
export declare function requireEngineBuild(checkout: string, commands: SyncCommandRunner, patch?: EnginePatch): void;
|
|
@@ -2,19 +2,29 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { shippedEnginePatch } from "./patches.js";
|
|
6
|
+
import { NODE_WORKSPACE_PATCH } from "./patch-catalogue.js";
|
|
5
7
|
import { engineSetupCommand } from "./setup-command.js";
|
|
6
8
|
export const NODE_VERIFIER_OPTION = "--node-verifier";
|
|
7
9
|
export function nodeVerifierArgs(verifier) {
|
|
8
10
|
return verifier ? [NODE_VERIFIER_OPTION, verifier] : [];
|
|
9
11
|
}
|
|
10
|
-
export const ENGINE_PATCHES = ["owned-processes", "none"];
|
|
12
|
+
export const ENGINE_PATCHES = ["owned-processes", "none", "node-workspace"];
|
|
11
13
|
export const ENGINE_PATCH_RETIRED = "the owned-processes Engine patch is retired; prepare stock Engine v0.11.0 instead";
|
|
12
|
-
export function engineBuildIssue(checkout,
|
|
13
|
-
if (patch !== "none")
|
|
14
|
+
export function engineBuildIssue(checkout, commands, patch = "none") {
|
|
15
|
+
if (patch !== "none" && patch !== "node-workspace")
|
|
14
16
|
return ENGINE_PATCH_RETIRED;
|
|
17
|
+
if (patch === "node-workspace") {
|
|
18
|
+
const resolved = shippedEnginePatch(patch);
|
|
19
|
+
if (resolved.sha256 !== NODE_WORKSPACE_PATCH.sha256 || resolved.base !== NODE_WORKSPACE_PATCH.base)
|
|
20
|
+
return "node-workspace patch differs from its tested catalogue";
|
|
21
|
+
const check = commands.run({ command: "git", args: ["apply", "--reverse", "--check", resolved.path], cwd: checkout, timeoutMs: 30_000 });
|
|
22
|
+
if (check.code !== 0)
|
|
23
|
+
return "node-workspace patch is missing or changed in the Engine checkout";
|
|
24
|
+
}
|
|
15
25
|
for (const file of ["packages/cli/dist/commands/start.js", "packages/cli/dist/cli.js"])
|
|
16
26
|
if (!existsSync(join(checkout, file)))
|
|
17
|
-
return `the stock Engine checkout at ${checkout} is not built (no ${file})`;
|
|
27
|
+
return `the ${patch === "none" ? "stock" : "patched"} Engine checkout at ${checkout} is not built (no ${file})`;
|
|
18
28
|
return undefined;
|
|
19
29
|
}
|
|
20
30
|
export function requireEngineBuild(checkout, commands, patch = "none") {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EnvironmentTooling } from "@parity/product-lab/ports/environment";
|
|
2
|
+
import type { SyncCommandRunner } from "@parity/product-lab/ports/system";
|
|
3
|
+
import type { EnginePatch } from "./engine-build.js";
|
|
4
|
+
import { type PreparedEngine, type PreparedEnginePatch } from "./prepare-engine.js";
|
|
5
|
+
/** What an Engine checkout tooling prepares, and where. */
|
|
6
|
+
export interface EngineCheckoutSettings {
|
|
7
|
+
/** The state directory it is prepared in (engine-build.json, engine.json and `tooling/<key>/`): its own. */
|
|
8
|
+
readonly state: string;
|
|
9
|
+
/** Engine's network whose binaries its fetch downloads. */
|
|
10
|
+
readonly network: "previewnet" | "paseo-next-v2";
|
|
11
|
+
/** The build an environment starts from: stock (`none`) or with the shipped node-workspace patch. */
|
|
12
|
+
readonly patch: Exclude<EnginePatch, "owned-processes">;
|
|
13
|
+
/** The lab's id of the environment that starts from it, for the command that prepares it. */
|
|
14
|
+
readonly environment: string;
|
|
15
|
+
/** The command that prepares it, as messages name it. Default: `engineFetchCommand(environment)`. */
|
|
16
|
+
readonly setupCommand?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The command that prepares an environment's own tooling: `product-lab fetch --environment <id>`, through the checkout's
|
|
20
|
+
* CLI script there (`bun run setup` prepares only the copies' stock Engine), through npx in a product.
|
|
21
|
+
*/
|
|
22
|
+
export declare function engineFetchCommand(environment: string, checkout?: boolean): string;
|
|
23
|
+
/**
|
|
24
|
+
* The prepared checkout in `settings.state`, as `patch` names it (default `settings.patch`), or `EngineNotPrepared`
|
|
25
|
+
* naming the fix. `ref`: also check that commit (default the tested release; `as-prepared` takes the recorded one).
|
|
26
|
+
*/
|
|
27
|
+
export declare function preparedEngineCheckout(settings: EngineCheckoutSettings, commands: SyncCommandRunner, patch?: PreparedEnginePatch, ref?: string): PreparedEngine;
|
|
28
|
+
/**
|
|
29
|
+
* The Engine checkout `settings` names, as an environment's tooling: always the build `settings.patch` names, which is
|
|
30
|
+
* the one its environment starts from (`preparedEngineCheckout(settings, commands, settings.patch)`). Another repository
|
|
31
|
+
* or ref may be asked for; another build may not (`--no-engine-patch` for a patched one is refused, naming why).
|
|
32
|
+
*/
|
|
33
|
+
export declare function engineCheckoutTooling(settings: EngineCheckoutSettings): EnvironmentTooling;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { defaultEngineRepository, EngineNotPrepared, prepareEngine, preparedEngine, testedEngineRef } from "./prepare-engine.js";
|
|
4
|
+
import { engineBuildWords } from "../saved-fork/saved-fork-tooling.js";
|
|
5
|
+
import { insideProductLabCheckout } from "./setup-command.js";
|
|
6
|
+
export function engineFetchCommand(environment, checkout = insideProductLabCheckout()) {
|
|
7
|
+
return checkout ? `bun run product-lab fetch --config <lab.config.ts> --environment ${environment}` : `npx --no-install product-lab fetch --environment ${environment}`;
|
|
8
|
+
}
|
|
9
|
+
const fixOf = (settings) => settings.setupCommand ?? engineFetchCommand(settings.environment);
|
|
10
|
+
export function preparedEngineCheckout(settings, commands, patch = settings.patch, ref) {
|
|
11
|
+
return preparedEngine(settings.state, { stateDirectory: ".", fix: fixOf(settings), commands, patch, ...(ref ? { ref } : {}) });
|
|
12
|
+
}
|
|
13
|
+
function syncCommands(system) {
|
|
14
|
+
if (!system.syncCommands)
|
|
15
|
+
throw new Error("The Engine checkout is checked through the lab's sync command adapter (SystemPorts.syncCommands), which this lab lacks");
|
|
16
|
+
return system.syncCommands;
|
|
17
|
+
}
|
|
18
|
+
export function engineCheckoutTooling(settings) {
|
|
19
|
+
const status = (commands, patch, ref) => {
|
|
20
|
+
try {
|
|
21
|
+
return { ready: true, detail: engineBuildWords(preparedEngineCheckout(settings, commands, patch, ref)) };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (!(error instanceof EngineNotPrepared))
|
|
25
|
+
throw error;
|
|
26
|
+
return { ready: false, detail: error.reason, fix: fixOf(settings) };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
id: `engine:${settings.state}`,
|
|
31
|
+
kind: "engine",
|
|
32
|
+
label: `Engine checkout${settings.patch === "none" ? "" : ` (${settings.patch} patch)`}`,
|
|
33
|
+
check: (system) => status(syncCommands(system), settings.patch),
|
|
34
|
+
async prepare(request) {
|
|
35
|
+
const commands = syncCommands(request.system);
|
|
36
|
+
const source = request.source ?? {};
|
|
37
|
+
const patch = settings.patch;
|
|
38
|
+
if (source.patched === false && patch !== "none")
|
|
39
|
+
throw new Error(`The ${settings.environment} environment starts from Engine with the ${patch} patch, so it cannot be prepared without it (--no-engine-patch)`);
|
|
40
|
+
const ref = source.ref ?? testedEngineRef;
|
|
41
|
+
const pinned = /^[0-9a-f]{40}$/i.test(ref);
|
|
42
|
+
const already = pinned ? status(commands, patch, ref) : undefined;
|
|
43
|
+
if (already?.ready) {
|
|
44
|
+
request.log?.(`Engine checkout: already prepared (${already.detail})`);
|
|
45
|
+
return { ...already, prepared: false };
|
|
46
|
+
}
|
|
47
|
+
request.log?.(`Engine ${ref.slice(0, 12)} from ${source.repository ?? defaultEngineRepository}, ${patch === "none" ? "stock (no lab patch)" : `with the ${patch} patch`}, into ${settings.state}: ` +
|
|
48
|
+
"clone, pnpm install and build, Engine's fetch of the network's binaries, the pinned dot CLI (the first time: a few minutes and about 900 MB)");
|
|
49
|
+
const homebrewPrefix = request.system.environment?.get("HOMEBREW_PREFIX");
|
|
50
|
+
prepareEngine(settings.state, ref, settings.network, commands, ".", { platform: process.platform, ...(homebrewPrefix ? { homebrewPrefix } : {}) }, {
|
|
51
|
+
...(source.repository ? { repository: source.repository } : {}),
|
|
52
|
+
patch,
|
|
53
|
+
...(request.output ? { output: request.output } : {}),
|
|
54
|
+
});
|
|
55
|
+
const after = status(commands, patch, pinned ? ref : undefined);
|
|
56
|
+
return { ...after, prepared: after.ready };
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
diff --git a/packages/cli/src/lib/spawn-env.ts b/packages/cli/src/lib/spawn-env.ts
|
|
2
|
+
index 90205fb..ae56253 100644
|
|
3
|
+
--- a/packages/cli/src/lib/spawn-env.ts
|
|
4
|
+
+++ b/packages/cli/src/lib/spawn-env.ts
|
|
5
|
+
@@ -1,169 +1,178 @@
|
|
6
|
+
// The spawn environment `ppn start` states, in one place.
|
|
7
|
+
//
|
|
8
|
+
// zombienet forwards no environment to custom processes, so everything the dashboard,
|
|
9
|
+
// eth-rpc, the dub stack and the storage provider cannot derive has to be *stated*.
|
|
10
|
+
// `ppn start` states it three times: config/ports.local.env (read by custom processes),
|
|
11
|
+
// zombie-cli's child environment (which the configs' {{BIN}} and {{SCRIPTS}} are filled from),
|
|
12
|
+
// and each custom process's own `env` in the config it spawns (customProcessEnv), the only
|
|
13
|
+
// environment zombie-cli hands them. A deployment that spawns zombie-cli directly never runs
|
|
14
|
+
// `ppn start`, so it has to restate the same facts itself.
|
|
15
|
+
//
|
|
16
|
+
// This module is the canonical statement, and the contract a deployment implements: it is
|
|
17
|
+
// exported as `@parity/ppn/spawn-env` so the restating side can assert against the key lists
|
|
18
|
+
// rather than keeping its own copy in step by hand.
|
|
19
|
+
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
|
|
22
|
+
/** Facts config/ports.local.env states for zombienet's custom processes. */
|
|
23
|
+
export interface LocalEnvFacts {
|
|
24
|
+
/** The network this run resolved to, so every service resolves the same one. */
|
|
25
|
+
network: string;
|
|
26
|
+
/** The data dir this run writes to — per-mode (data/ vs data-fork/). */
|
|
27
|
+
dataDir: string;
|
|
28
|
+
ephemeral: boolean;
|
|
29
|
+
/** Where the identity postgres cluster keeps its data. */
|
|
30
|
+
identityDataDir: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The gitignored file `ppn start` writes; every service overlays it on top of ports.env. */
|
|
34
|
+
export function localEnvContent(f: LocalEnvFacts): string {
|
|
35
|
+
return (
|
|
36
|
+
'# Generated by `ppn start` — gitignored, do not edit.\n' +
|
|
37
|
+
`WEB3_STORAGE_PROVIDER_STORAGE_MODE=${f.ephemeral ? 'inmemory' : 'disk'}\n` +
|
|
38
|
+
`DUB_POSTGRES_DATA_DIR=${f.identityDataDir}\n` +
|
|
39
|
+
`PPN_NETWORK=${f.network}\n` +
|
|
40
|
+
// An ephemeral run keeps its chains in a temp dir, so PPN_DATA_DIR below holds an earlier
|
|
41
|
+
// run's files, which the services that read the data dir must not take for this one's.
|
|
42
|
+
`PPN_EPHEMERAL=${f.ephemeral ? '1' : '0'}\n` +
|
|
43
|
+
// zombienet forwards no env to custom processes, and the data dir is per-mode
|
|
44
|
+
// (data/ vs data-fork/): without this the dashboard reads the *other* mode's
|
|
45
|
+
// spawn stamp and logs — a fork reporting itself as yesterday's genesis.
|
|
46
|
+
`PPN_DATA_DIR=${f.dataDir}\n`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Facts `ppn start` puts into zombie-cli's environment (inherited by node-level procs). */
|
|
51
|
+
export interface ChildEnvFacts {
|
|
52
|
+
binDir: string;
|
|
53
|
+
/** The workspace this run resolved to, so the launchers do not resolve it again. */
|
|
54
|
+
workspace: string;
|
|
55
|
+
scriptsDir: string;
|
|
56
|
+
dataDir: string;
|
|
57
|
+
ephemeral: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function childEnv(f: ChildEnvFacts): Record<string, string> {
|
|
61
|
+
return {
|
|
62
|
+
BIN: f.binDir,
|
|
63
|
+
// zombienet forwards node-level env but gives custom processes no HOME, which is the
|
|
64
|
+
// one thing the shell fallback would need — so the resolved workspace travels here.
|
|
65
|
+
PPN_HOME: f.workspace,
|
|
66
|
+
SCRIPTS: f.scriptsDir,
|
|
67
|
+
DATA_DIR: f.dataDir,
|
|
68
|
+
EPHEMERAL: f.ephemeral ? '1' : '',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Facts every custom process is handed in its own `env` (custom-process-env): zombie-cli starts
|
|
74
|
+
* nodes and custom processes with an empty environment but TZ, LANG, PATH and what the TOML
|
|
75
|
+
* gives each one, so neither zombie-cli's environment (childEnv) nor the shell's reaches them.
|
|
76
|
+
* Without PPN_HOME a launcher falls back to the checkout it sits in, or ~/.ppn
|
|
77
|
+
* (scripts/lib/workspace.sh), and reads that workspace's ports.local.env, binaries and data
|
|
78
|
+
* instead of this run's.
|
|
79
|
+
*/
|
|
80
|
+
export function customProcessEnv(f: { workspace: string; network: string; dataDir: string }): Record<string, string> {
|
|
81
|
+
return { PPN_HOME: f.workspace, PPN_NETWORK: f.network, PPN_DATA_DIR: f.dataDir };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const SECTION = /^\s*\[\[?\s*([\w.-]+)\s*\]\]?\s*(#.*)?$/;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `toml` with `env` added to every `[[custom_processes]]` block, before any entry the block
|
|
88
|
+
* already has; an entry the block names itself is kept, not repeated. Other sections are left
|
|
89
|
+
* alone. Line-based, for the configs this repository generates and any hand-written one in the
|
|
90
|
+
* same shape: one key per line, `env = [` opening its array on the key's own line.
|
|
91
|
+
*/
|
|
92
|
+
export function withCustomProcessEnv(toml: string, env: Record<string, string>): string {
|
|
93
|
+
+ return withProcessEnv(toml, env, ['custom_processes']);
|
|
94
|
+
+}
|
|
95
|
+
+
|
|
96
|
+
+/** Node processes also start with a stripped environment; preserve each node's explicit overrides. */
|
|
97
|
+
+export function withNodeProcessEnv(toml: string, env: Record<string, string>): string {
|
|
98
|
+
+ return withProcessEnv(toml, env, ['relaychain.nodes', 'parachains.collators']);
|
|
99
|
+
+}
|
|
100
|
+
+
|
|
101
|
+
+function withProcessEnv(toml: string, env: Record<string, string>, sections: string[]): string {
|
|
102
|
+
const lines = toml.split('\n');
|
|
103
|
+
const out: string[] = [];
|
|
104
|
+
const entry = (name: string, value: string) => `{ name = ${JSON.stringify(name)}, value = ${JSON.stringify(value)} }`;
|
|
105
|
+
let i = 0;
|
|
106
|
+
while (i < lines.length) {
|
|
107
|
+
const header = SECTION.exec(lines[i]);
|
|
108
|
+
out.push(lines[i++]);
|
|
109
|
+
- if (!header || header[1] !== 'custom_processes' || !lines[i - 1].trim().startsWith('[[')) continue;
|
|
110
|
+
+ if (!header || !sections.includes(header[1]) || !lines[i - 1].trim().startsWith('[[')) continue;
|
|
111
|
+
// The block runs to the next section header.
|
|
112
|
+
const start = i;
|
|
113
|
+
while (i < lines.length && !SECTION.test(lines[i])) i++;
|
|
114
|
+
const block = lines.slice(start, i);
|
|
115
|
+
const named = new Set([...block.join('\n').matchAll(/\{\s*name\s*=\s*"([^"]+)"/g)].map((m) => m[1]));
|
|
116
|
+
const missing = Object.entries(env).filter(([name]) => !named.has(name)).map(([n, v]) => entry(n, v));
|
|
117
|
+
const at = block.findIndex((line) => /^\s*env\s*=\s*\[/.test(line));
|
|
118
|
+
if (missing.length === 0) {
|
|
119
|
+
out.push(...block);
|
|
120
|
+
} else if (at === -1) {
|
|
121
|
+
- // No env yet: after the block's last key, before the blank lines that separate it.
|
|
122
|
+
+ // No env yet: after the last key, before trailing comments for the next section.
|
|
123
|
+
let last = block.length;
|
|
124
|
+
- while (last > 0 && block[last - 1].trim() === '') last--;
|
|
125
|
+
+ while (last > 0 && /^\s*(?:#.*)?$/.test(block[last - 1])) last--;
|
|
126
|
+
out.push(...block.slice(0, last), `env = [${missing.join(', ')}]`, ...block.slice(last));
|
|
127
|
+
} else {
|
|
128
|
+
const open = block[at].indexOf('[') + 1;
|
|
129
|
+
const rest = block[at].slice(open).trim();
|
|
130
|
+
if (rest === '') {
|
|
131
|
+
// Multi-line array: one entry per line, as the generators write them.
|
|
132
|
+
out.push(...block.slice(0, at + 1), ...missing.map((e) => ` ${e},`), ...block.slice(at + 1));
|
|
133
|
+
} else {
|
|
134
|
+
const joined = rest.startsWith(']') ? missing.join(', ') : `${missing.join(', ')}, `;
|
|
135
|
+
out.push(...block.slice(0, at), `${block[at].slice(0, open)}${joined}${rest}`, ...block.slice(at + 1));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return out.join('\n');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Where `ppn start` writes the config it spawns: beside the one it was made from, so relative paths still resolve. */
|
|
143
|
+
export function spawnTomlFor(source: string): string {
|
|
144
|
+
return path.join(path.dirname(source), `${path.basename(source, '.toml')}.spawn.toml`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const DUMMY_LOCAL: LocalEnvFacts = { network: 'x', dataDir: 'x', ephemeral: false, identityDataDir: 'x' };
|
|
148
|
+
const DUMMY_CHILD: ChildEnvFacts = { binDir: 'x', workspace: 'x', scriptsDir: 'x', dataDir: 'x', ephemeral: false };
|
|
149
|
+
|
|
150
|
+
/** Keys `ppn start` writes into config/ports.local.env, derived from the real writer. */
|
|
151
|
+
export function localEnvKeys(): string[] {
|
|
152
|
+
return [...localEnvContent(DUMMY_LOCAL).matchAll(/^([A-Z_][A-Z0-9_]*)=/gm)].map((m) => m[1]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Keys `ppn start` puts into zombie-cli's environment, derived from the real builder. */
|
|
156
|
+
export function childEnvKeys(): string[] {
|
|
157
|
+
return Object.keys(childEnv(DUMMY_CHILD));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Every key a spawn receives through `ppn start`, deduplicated. */
|
|
161
|
+
export function spawnEnvKeys(): string[] {
|
|
162
|
+
return [...new Set([...localEnvKeys(), ...childEnvKeys()])];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Keys the server path deliberately does not supply. Each needs a reason, and the reason has
|
|
167
|
+
* to be about the *server*, not about effort.
|
|
168
|
+
*/
|
|
169
|
+
export const WAIVED: Record<string, string> = {
|
|
170
|
+
// A server persists by definition; ephemeral is a laptop mode. Nothing reads it there.
|
|
171
|
+
EPHEMERAL: 'ephemeral is a local-only mode; a deployment always persists',
|
|
172
|
+
|
|
173
|
+
// KNOWN GAP, deliberately recorded rather than silently waived.
|
|
174
|
+
//
|
|
175
|
+
// `ppn start` sets it so every service resolves the network the user asked for.
|
|
176
|
+
// On a server nothing sets it, and currentNetworkName() (network-config/src/networks.ts)
|
|
177
|
+
// falls back to previewnet. Staging and prod run previewnet, so this is *accidentally*
|
|
178
|
+
// correct today and breaks nothing — but the first non-previewnet deployment would have
|
|
179
|
+
// every service resolve previewnet's chains, ports and bin directory instead.
|
|
180
|
+
//
|
|
181
|
+
// Not fixed here because the fix belongs with `ppn start --server` (see docs/DASHBOARD.md,
|
|
182
|
+
// "Why a server does not run `ppn start`"), which makes one path the sole author of all of
|
|
183
|
+
// this. Until then it is written down, and the conformance test keeps it from being
|
|
184
|
+
// forgotten.
|
|
185
|
+
PPN_NETWORK: 'KNOWN GAP: falls back to previewnet, which is what servers run today',
|
|
186
|
+
};
|
|
187
|
+
diff --git a/scripts/lib/workspace.sh b/scripts/lib/workspace.sh
|
|
188
|
+
index acb15c9..2ae2002 100755
|
|
189
|
+
--- a/scripts/lib/workspace.sh
|
|
190
|
+
+++ b/scripts/lib/workspace.sh
|
|
191
|
+
@@ -1,47 +1,67 @@
|
|
192
|
+
#!/usr/bin/env bash
|
|
193
|
+
# Where the workspace is — the one rule, shared by every launcher. Mirrors workspaceRoot()
|
|
194
|
+
# in @parity/ppn-network-config: $PPN_HOME, else the nearest ancestor of the cwd with
|
|
195
|
+
# networks/, else a checkout this script sits in, else the per-user home. In a checkout all
|
|
196
|
+
# of these agree; installed from npm the script lives in node_modules, whose bin/ does not
|
|
197
|
+
# exist — five launchers each grew their own partial copy of this logic and each broke a
|
|
198
|
+
# different way, which is why it now lives here once.
|
|
199
|
+
#
|
|
200
|
+
# zombienet runs custom processes with a stripped environment (no HOME), so the last resort
|
|
201
|
+
# derives the home from the owner of this file — the user whose `ppn fetch` filled ~/.ppn.
|
|
202
|
+
#
|
|
203
|
+
# Usage: source "$(dirname "${BASH_SOURCE[0]}")/lib/workspace.sh" (adjust depth)
|
|
204
|
+
# Sets: PPN_WS the workspace root
|
|
205
|
+
# PPN_WS_BIN its bin/ (callers append /<network> for non-previewnet binaries)
|
|
206
|
+
|
|
207
|
+
ppn_workspace_root() {
|
|
208
|
+
if [[ -n "${PPN_HOME:-}" ]]; then
|
|
209
|
+
echo "$PPN_HOME"; return
|
|
210
|
+
fi
|
|
211
|
+
+ # A native node can be launched outside `ppn start` with no environment at all.
|
|
212
|
+
+ # zombienet's absolute base path is <workspace>/{data,data-fork}/<node>/data.
|
|
213
|
+
+ # Only callers explicitly passing node args use this fallback; stop at the relay-side `--`.
|
|
214
|
+
+ local arg base="" previous="" candidate layout
|
|
215
|
+
+ for arg in "$@"; do
|
|
216
|
+
+ [[ "$arg" == "--" ]] && break
|
|
217
|
+
+ case "$previous" in --base-path|-d) base="$arg" ;; esac
|
|
218
|
+
+ case "$arg" in --base-path=*) base="${arg#--base-path=}" ;; esac
|
|
219
|
+
+ [[ -n "$base" ]] && break
|
|
220
|
+
+ previous="$arg"
|
|
221
|
+
+ done
|
|
222
|
+
+ if [[ "$base" == /*/data ]]; then
|
|
223
|
+
+ candidate="${base%/data}"
|
|
224
|
+
+ candidate="${candidate%/*}"
|
|
225
|
+
+ layout="${candidate##*/}"
|
|
226
|
+
+ candidate="${candidate%/*}"
|
|
227
|
+
+ if [[ -n "$candidate" && ( "$layout" == "data" || "$layout" == "data-fork" ) ]] && [[ -d "$candidate/bin" ]]; then
|
|
228
|
+
+ echo "$candidate"; return
|
|
229
|
+
+ fi
|
|
230
|
+
+ fi
|
|
231
|
+
local dir="$PWD"
|
|
232
|
+
for _ in 1 2 3 4 5 6 7 8; do
|
|
233
|
+
[[ -d "$dir/networks" ]] && { echo "$dir"; return; }
|
|
234
|
+
[[ "$dir" == "/" ]] && break
|
|
235
|
+
dir="$(dirname "$dir")"
|
|
236
|
+
done
|
|
237
|
+
# A checkout: this helper sits at <root>/scripts/lib/workspace.sh, and a checkout has a
|
|
238
|
+
# fetched bin/. The npm package ships scripts/ too but never a bin/, so this rung
|
|
239
|
+
# distinguishes them.
|
|
240
|
+
local own; own="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
241
|
+
[[ -d "$own/bin" ]] && { echo "$own"; return; }
|
|
242
|
+
# The per-user home.
|
|
243
|
+
if [[ -n "${XDG_DATA_HOME:-}" ]]; then
|
|
244
|
+
echo "$XDG_DATA_HOME/ppn"; return
|
|
245
|
+
fi
|
|
246
|
+
if [[ -n "${HOME:-}" ]]; then
|
|
247
|
+
echo "$HOME/.ppn"; return
|
|
248
|
+
fi
|
|
249
|
+
local owner
|
|
250
|
+
owner="$(stat -c '%U' "${BASH_SOURCE[0]}" 2>/dev/null)" \
|
|
251
|
+
|| owner="$(stat -f '%Su' "${BASH_SOURCE[0]}" 2>/dev/null)" \
|
|
252
|
+
|| owner=""
|
|
253
|
+
[[ "$owner" =~ ^[A-Za-z0-9._-]+$ ]] && { echo "$(eval echo "~$owner")/.ppn"; return; }
|
|
254
|
+
echo ""
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
PPN_WS="$(ppn_workspace_root)"
|
|
258
|
+
PPN_WS_BIN="$PPN_WS/bin"
|
|
259
|
+
diff --git a/scripts/omni-node.sh b/scripts/omni-node.sh
|
|
260
|
+
index b3cd73d..3bce0d9 100755
|
|
261
|
+
--- a/scripts/omni-node.sh
|
|
262
|
+
+++ b/scripts/omni-node.sh
|
|
263
|
+
@@ -1,112 +1,115 @@
|
|
264
|
+
#!/usr/bin/env bash
|
|
265
|
+
# Wrapper around polkadot-omni-node that forces the libp2p network backend on the
|
|
266
|
+
# collator's *relay-chain* side.
|
|
267
|
+
#
|
|
268
|
+
# Why this exists: a collator runs a relay-chain node in the same process, configured by
|
|
269
|
+
# the args after the `--` separator. zombienet owns those args and passes no
|
|
270
|
+
# `--network-backend`, so the relay side takes the default — litep2p — whose websocket
|
|
271
|
+
# listener dies a few seconds after startup with:
|
|
272
|
+
#
|
|
273
|
+
# litep2p::websocket: [Relaychain] Websocket listener terminated error=Kind(InvalidInput)
|
|
274
|
+
# sc_service::task_manager: [Relaychain] Essential task `network-worker` failed.
|
|
275
|
+
#
|
|
276
|
+
# `network-worker` is essential, so the whole collator exits, usually right after it has
|
|
277
|
+
# authored its first block. Verified on macOS arm64 with 1.24.0-2f2eeb2b81d: with the
|
|
278
|
+
# default backend three or four collators die on every start; with libp2p, none do.
|
|
279
|
+
#
|
|
280
|
+
# This is consistent rather than exceptional — PPN already passes --network-backend=libp2p
|
|
281
|
+
# to every relay validator (see CHAIN_ARGS.relay in @ppn/network-config). The
|
|
282
|
+
# relay side of a collator is the one relay node that was still getting the default.
|
|
283
|
+
#
|
|
284
|
+
# The flag is appended, which puts it in the relay-chain arg list, and only on a real node
|
|
285
|
+
# run: zombienet also invokes this binary for spec and key generation, where it would be
|
|
286
|
+
# rejected as an unexpected argument.
|
|
287
|
+
#
|
|
288
|
+
# Which binary is exec'd, and from where, comes from the environment (set per collator
|
|
289
|
+
# in the generated fork TOML — zombienet forwards node-level env):
|
|
290
|
+
# PPN_BIN_DIR bin directory; non-previewnet networks keep theirs in bin/<network>
|
|
291
|
+
# PPN_COLLATOR_BINARY e.g. polkadot-parachain (networks/<name>.json parachain `command`)
|
|
292
|
+
# The libp2p fix applies to any cumulus collator, whichever binary it is.
|
|
293
|
+
set -euo pipefail
|
|
294
|
+
|
|
295
|
+
# Where the binaries are is a property of the *workspace*, never of this script's location.
|
|
296
|
+
# `ppn fetch` writes them to the workspace's bin/ ($PPN_HOME, or the checkout); installed from
|
|
297
|
+
# npm this script lives in node_modules/@parity/ppn/scripts, whose ../bin does not exist at all
|
|
298
|
+
# — under `set -e` the old `cd .../../bin` ended the script before the fallback below could run.
|
|
299
|
+
# So: the explicit env first, then the workspace, and only then this script's own tree, which is
|
|
300
|
+
# the right answer in a checkout and a harmless miss anywhere else.
|
|
301
|
+
source "$(dirname "${BASH_SOURCE[0]}")/lib/workspace.sh"
|
|
302
|
+
+# Only the node launcher opts into base-path recovery; service args are never scanned.
|
|
303
|
+
+PPN_WS="$(ppn_workspace_root "$@")"
|
|
304
|
+
+PPN_WS_BIN="$PPN_WS/bin"
|
|
305
|
+
REPO_BIN="$PPN_WS_BIN"
|
|
306
|
+
# `ppn start` exports BIN as the directory this run resolved to — bin/ for previewnet,
|
|
307
|
+
# bin/<network> for everything else — and the probe below inherits it even though it gets
|
|
308
|
+
# none of the node-level env.
|
|
309
|
+
BIN_DIR="${PPN_BIN_DIR:-${BIN:-$REPO_BIN}}"
|
|
310
|
+
BINARY="${PPN_COLLATOR_BINARY:-polkadot-omni-node}"
|
|
311
|
+
BIN="$BIN_DIR/$BINARY"
|
|
312
|
+
|
|
313
|
+
# Fall back to bin/<network>/ when the resolved path has nothing in it.
|
|
314
|
+
#
|
|
315
|
+
# Before spawning anything, zombienet probes each node command to learn which arguments it
|
|
316
|
+
# accepts — and that probe runs *without* the node-level env, so PPN_BIN_DIR is unset and the
|
|
317
|
+
# lookup above lands on plain bin/. previewnet keeps its binaries there, so it works; every other
|
|
318
|
+
# network keeps them in bin/<network>/, and the probe fails with a bare
|
|
319
|
+
#
|
|
320
|
+
# NodeAvailableArgsError("", ".../scripts/omni-node.sh")
|
|
321
|
+
#
|
|
322
|
+
# which says nothing about a missing binary. It only shows up on a machine that has fetched one
|
|
323
|
+
# network and not previewnet — a fresh CI runner — so a developer whose bin/ still holds a
|
|
324
|
+
# previewnet fetch will never see it.
|
|
325
|
+
#
|
|
326
|
+
# The probe cannot know the *name* either: Kusama's collator is polkadot-parachain and it
|
|
327
|
+
# still probes as the default, which is how a completed bite died at spawn with the error
|
|
328
|
+
# above naming bin/polkadot-omni-node. A network's directory holds one collator, so
|
|
329
|
+
# whichever of the two is in there is the one this network runs.
|
|
330
|
+
if [[ ! -x "$BIN" ]]; then
|
|
331
|
+
dirs=("$BIN_DIR")
|
|
332
|
+
if [[ -n "$REPO_BIN" ]]; then
|
|
333
|
+
[[ -n "${PPN_NETWORK:-}" ]] && dirs+=("$REPO_BIN/$PPN_NETWORK")
|
|
334
|
+
dirs+=("$REPO_BIN" "$REPO_BIN"/*/)
|
|
335
|
+
fi
|
|
336
|
+
for dir in "${dirs[@]}"; do
|
|
337
|
+
for name in "$BINARY" polkadot-omni-node polkadot-parachain; do
|
|
338
|
+
if [[ -x "${dir%/}/$name" ]]; then
|
|
339
|
+
BIN="${dir%/}/$name"
|
|
340
|
+
break 2
|
|
341
|
+
fi
|
|
342
|
+
done
|
|
343
|
+
done
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
# On a chain whose Aura is ed25519 (Polkadot's Asset Hub), zombienet's keystore has no key the
|
|
347
|
+
# collator can author with: it writes `aura` as sr25519 and files the ed25519 key under `gran`.
|
|
348
|
+
# Same seed, so inserting it under `aura` is all that is missing — without it the collator syncs,
|
|
349
|
+
# reports no error, and never proposes a block.
|
|
350
|
+
#
|
|
351
|
+
# Only on a real node run: the arg probe passes neither, and `key insert` on a half-set-up node
|
|
352
|
+
# would fail the probe rather than the spawn.
|
|
353
|
+
if [[ "${PPN_COLLATOR_AURA:-}" == "ed25519" ]]; then
|
|
354
|
+
base=""; chain=""
|
|
355
|
+
prev=""
|
|
356
|
+
for arg in "$@"; do
|
|
357
|
+
case "$prev" in
|
|
358
|
+
--base-path|-d) base="$arg" ;;
|
|
359
|
+
--chain) chain="$arg" ;;
|
|
360
|
+
esac
|
|
361
|
+
prev="$arg"
|
|
362
|
+
done
|
|
363
|
+
if [[ -n "$base" && -n "$chain" ]]; then
|
|
364
|
+
name="$(basename "$base")"
|
|
365
|
+
[[ "$name" == "data" ]] && name="$(basename "$(dirname "$base")")"
|
|
366
|
+
"$BIN" key insert --key-type aura --scheme ed25519 \
|
|
367
|
+
--suri "//$name" --chain "$chain" --base-path "$base" \
|
|
368
|
+
|| echo "omni-node.sh: could not insert the ed25519 aura key for $name" >&2
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
for arg in "$@"; do
|
|
373
|
+
if [[ "$arg" == "--" ]]; then
|
|
374
|
+
exec "$BIN" "$@" --network-backend=libp2p --discover-local --allow-private-ip
|
|
375
|
+
fi
|
|
376
|
+
done
|
|
377
|
+
|
|
378
|
+
exec "$BIN" "$@"
|
|
379
|
+
diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts
|
|
380
|
+
index 3758d00..1f79646 100644
|
|
381
|
+
--- a/packages/cli/src/commands/start.ts
|
|
382
|
+
+++ b/packages/cli/src/commands/start.ts
|
|
383
|
+
@@ -24,7 +24,7 @@ import {
|
|
384
|
+
type NetworkDef,
|
|
385
|
+
} from '@parity/ppn-network-config';
|
|
386
|
+
import { readSpawnStamp, writeSpawnStamp, SPAWN_FILE } from '../lib/spawn-stamp.js';
|
|
387
|
+
-import { localEnvContent, childEnv, customProcessEnv, spawnTomlFor, withCustomProcessEnv } from '../lib/spawn-env.js';
|
|
388
|
+
+import { localEnvContent, childEnv, customProcessEnv, spawnTomlFor, withCustomProcessEnv, withNodeProcessEnv } from '../lib/spawn-env.js';
|
|
389
|
+
import { forkBundleName } from '../lib/fork-bundle-name.js';
|
|
390
|
+
import {
|
|
391
|
+
classifyGroup,
|
|
392
|
+
@@ -550,7 +550,10 @@ export async function start(args: string[], opts: StartOptions = {}): Promise<vo
|
|
393
|
+
const tomlFile = spawnTomlFor(sourceToml);
|
|
394
|
+
fs.writeFileSync(
|
|
395
|
+
tomlFile,
|
|
396
|
+
- withCustomProcessEnv(fs.readFileSync(sourceToml, 'utf-8'), customProcessEnv({ workspace: WS, network: name, dataDir }))
|
|
397
|
+
+ withNodeProcessEnv(
|
|
398
|
+
+ withCustomProcessEnv(fs.readFileSync(sourceToml, 'utf-8'), customProcessEnv({ workspace: WS, network: name, dataDir })),
|
|
399
|
+
+ { PPN_HOME: WS, PPN_BIN_DIR: binDir, PPN_NETWORK: name }
|
|
400
|
+
+ )
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
// Decided after ensureDeps, which is where a --fresh-bite produces the bundle the data is
|
|
@@ -18,3 +18,26 @@ export declare const LIGHT_TOPOLOGY_OVERLAY: {
|
|
|
18
18
|
};
|
|
19
19
|
/** The descriptor overlays a fork layout names (`ForkLayout.descriptors`), by manifest entry. */
|
|
20
20
|
export declare const DESCRIPTOR_OVERLAYS: Readonly<Record<string, unknown>>;
|
|
21
|
+
/**
|
|
22
|
+
* The native-node workspace fix (patches/previewnet-engine/manifest.json, `node-workspace`): optional, stock Engine stays
|
|
23
|
+
* the default. Its file ships beside this catalogue (`file`, in this folder), byte for byte the repository's
|
|
24
|
+
* patches/previewnet-engine/node-workspace.patch, so an installed package prepares the same patched Engine as the
|
|
25
|
+
* checkout (`shippedEnginePatch`, patches.ts). This entry is its manifest entry in the package.
|
|
26
|
+
*/
|
|
27
|
+
export declare const NODE_WORKSPACE_PATCH: {
|
|
28
|
+
readonly name: "node-workspace";
|
|
29
|
+
readonly file: "node-workspace.patch";
|
|
30
|
+
readonly repository: "https://github.com/paritytech/previewnet-engine.git";
|
|
31
|
+
readonly base: "e11792b234ca0c39a5fc1d47af491f82fc8e2670";
|
|
32
|
+
readonly sha256: "a4b866a6da4cbb636bd614271c9691280490b00172dae02a8b113ad161055757";
|
|
33
|
+
};
|
|
34
|
+
/** The Engine patches the package ships, by name (`EngineSource.patch`). */
|
|
35
|
+
export declare const SHIPPED_ENGINE_PATCHES: {
|
|
36
|
+
readonly "node-workspace": {
|
|
37
|
+
readonly name: "node-workspace";
|
|
38
|
+
readonly file: "node-workspace.patch";
|
|
39
|
+
readonly repository: "https://github.com/paritytech/previewnet-engine.git";
|
|
40
|
+
readonly base: "e11792b234ca0c39a5fc1d47af491f82fc8e2670";
|
|
41
|
+
readonly sha256: "a4b866a6da4cbb636bd614271c9691280490b00172dae02a8b113ad161055757";
|
|
42
|
+
};
|
|
43
|
+
};
|
|
@@ -13,3 +13,11 @@ export const OWNED_PROCESSES_PATCH = {
|
|
|
13
13
|
};
|
|
14
14
|
export const LIGHT_TOPOLOGY_OVERLAY = { relay: { validators: 4 } };
|
|
15
15
|
export const DESCRIPTOR_OVERLAYS = { "light-topology": LIGHT_TOPOLOGY_OVERLAY };
|
|
16
|
+
export const NODE_WORKSPACE_PATCH = {
|
|
17
|
+
name: "node-workspace",
|
|
18
|
+
file: "node-workspace.patch",
|
|
19
|
+
repository: ENGINE_RELEASE.repository,
|
|
20
|
+
base: ENGINE_RELEASE.base,
|
|
21
|
+
sha256: "a4b866a6da4cbb636bd614271c9691280490b00172dae02a8b113ad161055757",
|
|
22
|
+
};
|
|
23
|
+
export const SHIPPED_ENGINE_PATCHES = { [NODE_WORKSPACE_PATCH.name]: NODE_WORKSPACE_PATCH };
|
|
@@ -9,7 +9,7 @@ declare const patchEntry: z.ZodObject<{
|
|
|
9
9
|
export type PatchEntry = z.infer<typeof patchEntry>;
|
|
10
10
|
/** Repository-level `patches/` directory, shared by every provider. */
|
|
11
11
|
export declare const patchesDirectory: string;
|
|
12
|
-
/** Why a
|
|
12
|
+
/** Why a repository patch's manifest cannot be read here: this installation carries no patches/ folder. */
|
|
13
13
|
export declare const ENGINE_PATCHES_REPOSITORY_ONLY: string;
|
|
14
14
|
/** A patch or manifest was asked for where patches/<upstream>/ does not exist (an installed package). */
|
|
15
15
|
export declare class EnginePatchesNotInstalled extends Error {
|
|
@@ -34,4 +34,18 @@ export declare function resolvePatch(upstream: string, name: string): {
|
|
|
34
34
|
base: string;
|
|
35
35
|
repository: string;
|
|
36
36
|
};
|
|
37
|
+
/** The Engine patch the package ships (adapters/environment/engine/src/setup/), read here and digest-checked. */
|
|
38
|
+
export declare const shippedPatchesDirectory: string;
|
|
39
|
+
/**
|
|
40
|
+
* One Engine patch the package ships (`SHIPPED_ENGINE_PATCHES`), from its file beside the catalogue, refused when the
|
|
41
|
+
* file differs from the catalogue's digest. The same file in product-lab's checkout and in an installed package;
|
|
42
|
+
* `directory` is for tests (a changed copy is refused).
|
|
43
|
+
*/
|
|
44
|
+
export declare function shippedEnginePatch(name: string, directory?: string): {
|
|
45
|
+
name: string;
|
|
46
|
+
path: string;
|
|
47
|
+
sha256: "a4b866a6da4cbb636bd614271c9691280490b00172dae02a8b113ad161055757";
|
|
48
|
+
base: "e11792b234ca0c39a5fc1d47af491f82fc8e2670";
|
|
49
|
+
repository: "https://github.com/paritytech/previewnet-engine.git";
|
|
50
|
+
};
|
|
37
51
|
export {};
|