@cartesi/cli 2.0.0-alpha.5 → 2.0.0-alpha.7
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/dist/base.d.ts +10 -6
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +41 -15
- package/dist/builder/directory.d.ts.map +1 -1
- package/dist/builder/docker.d.ts.map +1 -1
- package/dist/builder/empty.d.ts.map +1 -1
- package/dist/builder/none.d.ts.map +1 -1
- package/dist/builder/tar.d.ts.map +1 -1
- package/dist/commands/address-book.d.ts +3 -1
- package/dist/commands/address-book.d.ts.map +1 -1
- package/dist/commands/address-book.js +3 -3
- package/dist/commands/build.d.ts +4 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +3 -3
- package/dist/commands/clean.d.ts +1 -1
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +3 -3
- package/dist/commands/create.d.ts +4 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +3 -4
- package/dist/commands/deploy/build.d.ts +1 -1
- package/dist/commands/deploy/build.d.ts.map +1 -1
- package/dist/commands/deploy/build.js +7 -54
- package/dist/commands/deploy.d.ts +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +9 -73
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +23 -11
- package/dist/commands/hash.d.ts +3 -1
- package/dist/commands/hash.d.ts.map +1 -1
- package/dist/commands/hash.js +3 -3
- package/dist/commands/rollups/deploy.d.ts +16 -0
- package/dist/commands/rollups/deploy.d.ts.map +1 -0
- package/dist/commands/rollups/deploy.js +225 -0
- package/dist/commands/rollups/logs.d.ts +11 -0
- package/dist/commands/rollups/logs.d.ts.map +1 -0
- package/dist/commands/rollups/logs.js +32 -0
- package/dist/commands/rollups/start.d.ts +14 -0
- package/dist/commands/rollups/start.d.ts.map +1 -0
- package/dist/commands/rollups/start.js +209 -0
- package/dist/commands/rollups/status.d.ts +7 -0
- package/dist/commands/rollups/status.d.ts.map +1 -0
- package/dist/commands/rollups/status.js +46 -0
- package/dist/commands/rollups/stop.d.ts +5 -0
- package/dist/commands/rollups/stop.d.ts.map +1 -0
- package/dist/commands/rollups/stop.js +26 -0
- package/dist/commands/rollups.d.ts +6 -0
- package/dist/commands/rollups.d.ts.map +1 -0
- package/dist/commands/rollups.js +19 -0
- package/dist/commands/run.d.ts +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +7 -155
- package/dist/commands/send/erc20.d.ts +10 -1
- package/dist/commands/send/erc20.d.ts.map +1 -1
- package/dist/commands/send/erc20.js +10 -8
- package/dist/commands/send/erc721.d.ts +10 -1
- package/dist/commands/send/erc721.d.ts.map +1 -1
- package/dist/commands/send/erc721.js +10 -8
- package/dist/commands/send/ether.d.ts +10 -1
- package/dist/commands/send/ether.d.ts.map +1 -1
- package/dist/commands/send/ether.js +10 -8
- package/dist/commands/send/generic.d.ts +11 -1
- package/dist/commands/send/generic.d.ts.map +1 -1
- package/dist/commands/send/generic.js +10 -9
- package/dist/commands/send.d.ts +4 -4
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +19 -19
- package/dist/commands/shell.d.ts +5 -1
- package/dist/commands/shell.d.ts.map +1 -1
- package/dist/commands/shell.js +3 -3
- package/dist/compose/rollups/default.env +35 -0
- package/dist/compose/rollups/docker-compose-anvil.yaml +15 -0
- package/dist/{node → compose/rollups}/docker-compose-bundler.yaml +12 -26
- package/dist/{node → compose/rollups}/docker-compose-database.yaml +4 -2
- package/dist/compose/rollups/docker-compose-espresso.yaml +94 -0
- package/dist/{node → compose/rollups}/docker-compose-explorer.yaml +18 -37
- package/dist/compose/rollups/docker-compose-graphql.yaml +49 -0
- package/dist/compose/rollups/docker-compose-node-cpus.yaml +7 -0
- package/dist/compose/rollups/docker-compose-node-memory.yaml +6 -0
- package/dist/compose/rollups/docker-compose-node.yaml +36 -0
- package/dist/compose/rollups/docker-compose-paymaster.yaml +18 -0
- package/dist/compose/rollups/docker-compose-proxy.yaml +24 -0
- package/dist/compose/rollups/proxy/bundler.yaml +17 -0
- package/dist/compose/rollups/proxy/espresso.yaml +17 -0
- package/dist/compose/rollups/proxy/explorer-api.yaml +17 -0
- package/dist/compose/rollups/proxy/explorer.yaml +10 -0
- package/dist/compose/rollups/proxy/graphql.yaml +10 -0
- package/dist/compose/rollups/proxy/paymaster.yaml +17 -0
- package/dist/compose/rollups/proxy/rollups-node.yaml +17 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/exec/cartesi-machine.d.ts.map +1 -1
- package/dist/exec/crane.d.ts +1 -1
- package/dist/exec/crane.d.ts.map +1 -1
- package/dist/exec/genext2fs.d.ts.map +1 -1
- package/dist/exec/mksquashfs.d.ts.map +1 -1
- package/dist/exec/rollups.d.ts +17 -0
- package/dist/exec/rollups.d.ts.map +1 -0
- package/dist/exec/rollups.js +40 -0
- package/dist/exec/util.d.ts +1 -1
- package/dist/exec/util.d.ts.map +1 -1
- package/dist/index.js +23 -21
- package/dist/machine.d.ts.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/wallet.d.ts.map +1 -1
- package/dist/wallet.js +29 -6
- package/package.json +24 -22
- package/dist/node/DockerfileDeploy.txt +0 -4
- package/dist/node/default.env +0 -27
- package/dist/node/docker-compose-anvil.yaml +0 -50
- package/dist/node/docker-compose-envfile.yaml +0 -4
- package/dist/node/docker-compose-espresso.yaml +0 -127
- package/dist/node/docker-compose-host.yaml +0 -30
- package/dist/node/docker-compose-paymaster.yaml +0 -33
- package/dist/node/docker-compose-prompt.yaml +0 -17
- package/dist/node/docker-compose-proxy.yaml +0 -48
- package/dist/node/docker-compose-snapshot-volume.yaml +0 -8
- package/dist/node/docker-compose-validator-cpus.yaml +0 -6
- package/dist/node/docker-compose-validator-memory.yaml +0 -6
- package/dist/node/docker-compose-validator.yaml +0 -59
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { Command, Option } from "@commander-js/extra-typings";
|
|
2
|
+
import input from "@inquirer/input";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
import { zeroHash } from "viem";
|
|
7
|
+
import { anvil } from "viem/chains";
|
|
8
|
+
import { getContextPath, getMachineHash, parseAddress, parseHash, } from "../../base.js";
|
|
9
|
+
import { applicationFactoryAbi, applicationFactoryAddress, authorityFactoryAbi, authorityFactoryAddress, } from "../../contracts.js";
|
|
10
|
+
import { addressInput } from "../../prompts.js";
|
|
11
|
+
import { connect } from "../send.js";
|
|
12
|
+
/**
|
|
13
|
+
* Deploy authority contract (if not already deployed)
|
|
14
|
+
* @param options
|
|
15
|
+
* @returns address of the authority
|
|
16
|
+
*/
|
|
17
|
+
const deployAuthority = async (publicClient, walletClient, options) => {
|
|
18
|
+
const { epochLength, progress, salt } = options;
|
|
19
|
+
// deploy authority contract (if not already deployed)
|
|
20
|
+
const authorityOwner = options.authorityOwner ||
|
|
21
|
+
(await addressInput({
|
|
22
|
+
message: "Authority Owner",
|
|
23
|
+
default: walletClient.account?.address,
|
|
24
|
+
}));
|
|
25
|
+
const authorityAddress = await publicClient.readContract({
|
|
26
|
+
abi: authorityFactoryAbi,
|
|
27
|
+
address: authorityFactoryAddress,
|
|
28
|
+
functionName: "calculateAuthorityAddress",
|
|
29
|
+
args: [authorityOwner, BigInt(epochLength), salt],
|
|
30
|
+
});
|
|
31
|
+
// check if authority is already deployed
|
|
32
|
+
const authorityCode = await publicClient.getCode({
|
|
33
|
+
address: authorityAddress,
|
|
34
|
+
});
|
|
35
|
+
if (authorityCode === undefined) {
|
|
36
|
+
// deploy authority
|
|
37
|
+
const { request } = await publicClient.simulateContract({
|
|
38
|
+
abi: authorityFactoryAbi,
|
|
39
|
+
address: authorityFactoryAddress,
|
|
40
|
+
account: walletClient.account,
|
|
41
|
+
functionName: "newAuthority",
|
|
42
|
+
args: [authorityOwner, BigInt(epochLength), salt],
|
|
43
|
+
});
|
|
44
|
+
progress.start("Deploying authority...");
|
|
45
|
+
const hash = await walletClient.writeContract(request);
|
|
46
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
47
|
+
progress.succeed(`Authority ${chalk.cyan(authorityAddress)}`);
|
|
48
|
+
}
|
|
49
|
+
return authorityAddress;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Deploy application contract
|
|
53
|
+
* @param options
|
|
54
|
+
* @returns address of the application
|
|
55
|
+
*/
|
|
56
|
+
const deployApplication = async (publicClient, walletClient, options) => {
|
|
57
|
+
const { authorityAddress, progress, salt, templateHash } = options;
|
|
58
|
+
const applicationOwner = options.applicationOwner ||
|
|
59
|
+
(await addressInput({
|
|
60
|
+
message: "Application Owner",
|
|
61
|
+
default: walletClient.account?.address,
|
|
62
|
+
}));
|
|
63
|
+
const applicationAddress = await publicClient.readContract({
|
|
64
|
+
abi: applicationFactoryAbi,
|
|
65
|
+
address: applicationFactoryAddress,
|
|
66
|
+
functionName: "calculateApplicationAddress",
|
|
67
|
+
args: [
|
|
68
|
+
authorityAddress,
|
|
69
|
+
applicationOwner,
|
|
70
|
+
templateHash,
|
|
71
|
+
// "0x", // XXX: update to latest rollups contract
|
|
72
|
+
salt,
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
// check if application is already deployed
|
|
76
|
+
const applicationCode = await publicClient.getCode({
|
|
77
|
+
address: applicationAddress,
|
|
78
|
+
});
|
|
79
|
+
if (applicationCode === undefined) {
|
|
80
|
+
// deploy application
|
|
81
|
+
const { request } = await publicClient.simulateContract({
|
|
82
|
+
abi: applicationFactoryAbi,
|
|
83
|
+
address: applicationFactoryAddress,
|
|
84
|
+
account: walletClient.account,
|
|
85
|
+
functionName: "newApplication",
|
|
86
|
+
args: [authorityAddress, applicationOwner, templateHash, salt],
|
|
87
|
+
});
|
|
88
|
+
progress.start("Deploying application...");
|
|
89
|
+
const hash = await walletClient.writeContract(request);
|
|
90
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
91
|
+
progress.succeed(`Application ${chalk.cyan(applicationAddress)}`);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// abort, because application is already deployed
|
|
95
|
+
throw new Error(`Application ${chalk.cyan(templateHash)} already deployed to ${chalk.cyan(applicationAddress)}`);
|
|
96
|
+
}
|
|
97
|
+
return applicationAddress;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Publish machine snapshot to rollups node by copying it to the rollups node container
|
|
101
|
+
* @param options
|
|
102
|
+
* @returns path to the snapshot in the rollups node
|
|
103
|
+
*/
|
|
104
|
+
const publishMachine = async (options) => {
|
|
105
|
+
const { progress, environmentName, templateHash } = options;
|
|
106
|
+
const snapshotPath = getContextPath("image");
|
|
107
|
+
const containerSnapshotPath = `/var/lib/cartesi-rollups-node/snapshots/${templateHash}/`;
|
|
108
|
+
progress.start("Publishing machine snapshot...");
|
|
109
|
+
await execa("docker", [
|
|
110
|
+
"compose",
|
|
111
|
+
"--project-name",
|
|
112
|
+
environmentName,
|
|
113
|
+
"cp",
|
|
114
|
+
snapshotPath,
|
|
115
|
+
`rollups-node:${containerSnapshotPath}`,
|
|
116
|
+
]);
|
|
117
|
+
progress.succeed(`Machine snapshot ${chalk.cyan(containerSnapshotPath)}`);
|
|
118
|
+
return containerSnapshotPath;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Register application in rollups node
|
|
122
|
+
* @param options
|
|
123
|
+
* @returns name of the application
|
|
124
|
+
*/
|
|
125
|
+
const registerApplication = async (options) => {
|
|
126
|
+
const { applicationAddress, progress, environmentName, snapshotPath } = options;
|
|
127
|
+
// use template hash as the name of the deployment
|
|
128
|
+
const name = options.name ??
|
|
129
|
+
(await input({
|
|
130
|
+
message: "Application Name",
|
|
131
|
+
default: applicationAddress.toLowerCase(),
|
|
132
|
+
}));
|
|
133
|
+
// deploy application
|
|
134
|
+
progress.start("Registering application...");
|
|
135
|
+
const { stdout } = await execa("docker", [
|
|
136
|
+
"compose",
|
|
137
|
+
"--project-name",
|
|
138
|
+
environmentName,
|
|
139
|
+
"exec",
|
|
140
|
+
"rollups-node",
|
|
141
|
+
"cartesi-rollups-cli",
|
|
142
|
+
"app",
|
|
143
|
+
"register",
|
|
144
|
+
"--name",
|
|
145
|
+
name,
|
|
146
|
+
"--address",
|
|
147
|
+
applicationAddress,
|
|
148
|
+
"--template-path",
|
|
149
|
+
snapshotPath,
|
|
150
|
+
"--print-json",
|
|
151
|
+
]);
|
|
152
|
+
const registration = stdout ? JSON.parse(stdout) : undefined;
|
|
153
|
+
if (registration) {
|
|
154
|
+
if (registration.State !== "ENABLED") {
|
|
155
|
+
throw new Error(registration.Reason);
|
|
156
|
+
}
|
|
157
|
+
progress.succeed(`Registration ${chalk.cyan(name)}`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
throw new Error("Failed to deploy application");
|
|
161
|
+
}
|
|
162
|
+
return name;
|
|
163
|
+
};
|
|
164
|
+
export const createDeployCommand = () => {
|
|
165
|
+
return new Command("deploy")
|
|
166
|
+
.description("Deploy a rollups application to a rollups node.")
|
|
167
|
+
.configureHelp({ showGlobalOptions: true })
|
|
168
|
+
.option("--chain-id <id>", "Chain ID", parseInt, 31337)
|
|
169
|
+
.option("--rpc-url <url>", "RPC URL")
|
|
170
|
+
.option("--mnemonic <phrase>", "Mnemonic passphrase")
|
|
171
|
+
.option("--mnemonic-index <index>", "Mnemonic account index", parseInt, 0)
|
|
172
|
+
.option("--name <string>", "application name")
|
|
173
|
+
.option("--authority-owner <address>", "authority owner", parseAddress, undefined)
|
|
174
|
+
.option("--application-owner <address>", "application owner", parseAddress, undefined)
|
|
175
|
+
.addOption(new Option("--epoch-length <number>", "length of an epoch (in blocks)")
|
|
176
|
+
.argParser(Number)
|
|
177
|
+
.default(720))
|
|
178
|
+
.option("--salt <hash>", "salt for deployment", parseHash, zeroHash)
|
|
179
|
+
.option("--json", "output in JSON format")
|
|
180
|
+
.action(async (options, command) => {
|
|
181
|
+
const rollupsOptions = command.optsWithGlobals();
|
|
182
|
+
const { environmentName } = rollupsOptions;
|
|
183
|
+
const { json } = options;
|
|
184
|
+
// XXX: json support is not implemented yet
|
|
185
|
+
// if case of json maybe we should not support interactive mode
|
|
186
|
+
const progress = ora();
|
|
187
|
+
// get cartesi machine snapshot hash, produced by 'build'
|
|
188
|
+
const templateHash = getMachineHash();
|
|
189
|
+
if (!templateHash) {
|
|
190
|
+
progress.fail(`Cartesi machine snapshot not found, run 'build'`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
progress.succeed(`Cartesi machine template hash ${chalk.cyan(templateHash)}`);
|
|
194
|
+
// connect to some chain
|
|
195
|
+
const { publicClient, walletClient } = await connect(options);
|
|
196
|
+
try {
|
|
197
|
+
// deploy authority contract (if not already deployed)
|
|
198
|
+
const authorityAddress = await deployAuthority(publicClient, walletClient, { progress, ...options });
|
|
199
|
+
// deploy application contract
|
|
200
|
+
const applicationAddress = await deployApplication(publicClient, walletClient, { authorityAddress, progress, templateHash, ...options });
|
|
201
|
+
if (publicClient.chain?.id === anvil.id) {
|
|
202
|
+
// copy machine snapshot to rollups node container
|
|
203
|
+
const containerSnapshotPath = await publishMachine({
|
|
204
|
+
progress,
|
|
205
|
+
templateHash,
|
|
206
|
+
environmentName,
|
|
207
|
+
});
|
|
208
|
+
const name = await registerApplication({
|
|
209
|
+
applicationAddress,
|
|
210
|
+
progress,
|
|
211
|
+
snapshotPath: containerSnapshotPath,
|
|
212
|
+
...options,
|
|
213
|
+
...rollupsOptions,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
const snapshotPath = getContextPath("image");
|
|
218
|
+
progress.succeed(`Done. Manually copy machine to rollups node ${chalk.cyan(snapshotPath)}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch (e) {
|
|
222
|
+
progress.fail(e instanceof Error ? e.message : "Unknown error");
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
export declare const createLogsCommand: () => Command<[], {
|
|
3
|
+
follow?: true | undefined;
|
|
4
|
+
color: boolean;
|
|
5
|
+
since?: string | undefined;
|
|
6
|
+
tail: string;
|
|
7
|
+
until?: string | undefined;
|
|
8
|
+
}, {
|
|
9
|
+
environmentName: string;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../src/commands/rollups/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAItD,eAAO,MAAM,iBAAiB;;;;;;;;EAuC7B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
export const createLogsCommand = () => {
|
|
4
|
+
return new Command("logs")
|
|
5
|
+
.description("Show logs of a local rollups node environment.")
|
|
6
|
+
.option("-f, --follow", "Follow log output")
|
|
7
|
+
.option("--no-color", "Produce monochrome output")
|
|
8
|
+
.option("--since <string>", "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)")
|
|
9
|
+
.option("-n, --tail <string>", "Number of lines to show from the end of the logs", "all")
|
|
10
|
+
.option("--until <string>", "Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)")
|
|
11
|
+
.configureHelp({ showGlobalOptions: true })
|
|
12
|
+
.action(async ({ follow, color, since, tail, until }, command) => {
|
|
13
|
+
const { environmentName } = command.optsWithGlobals();
|
|
14
|
+
const logOptions = ["--no-log-prefix"];
|
|
15
|
+
if (follow)
|
|
16
|
+
logOptions.push("--follow");
|
|
17
|
+
if (color === false)
|
|
18
|
+
logOptions.push("--no-color");
|
|
19
|
+
if (since)
|
|
20
|
+
logOptions.push("--since", since);
|
|
21
|
+
if (tail)
|
|
22
|
+
logOptions.push("--tail", tail);
|
|
23
|
+
await execa("docker", [
|
|
24
|
+
"compose",
|
|
25
|
+
"--project-name",
|
|
26
|
+
environmentName,
|
|
27
|
+
"logs",
|
|
28
|
+
...logOptions,
|
|
29
|
+
"rollups-node",
|
|
30
|
+
], { stdio: "inherit" });
|
|
31
|
+
});
|
|
32
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
export declare const createStartCommand: () => Command<[], {
|
|
3
|
+
blockTime: number;
|
|
4
|
+
defaultBlock: "latest" | "pending" | "safe" | "finalized";
|
|
5
|
+
cpus?: number | undefined;
|
|
6
|
+
memory?: number | undefined;
|
|
7
|
+
services: string[];
|
|
8
|
+
port: number;
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
verbose: boolean;
|
|
11
|
+
}, {
|
|
12
|
+
environmentName: string;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/rollups/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,6BAA6B,CAAC;AA2I9D,eAAO,MAAM,kBAAkB;;;;;;;;;;;EAgK9B,CAAC"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { Command, Option } from "@commander-js/extra-typings";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
import { Listr } from "listr2";
|
|
5
|
+
import pRetry from "p-retry";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { getServiceHealth } from "../../base.js";
|
|
8
|
+
import { DEFAULT_SDK } from "../../config.js";
|
|
9
|
+
const commaSeparatedList = (value) => value.split(",");
|
|
10
|
+
const host = "http://127.0.0.1";
|
|
11
|
+
// services configuration
|
|
12
|
+
const baseServices = [
|
|
13
|
+
{
|
|
14
|
+
name: "anvil",
|
|
15
|
+
file: "docker-compose-anvil.yaml",
|
|
16
|
+
healthySemaphore: "anvil",
|
|
17
|
+
healthyTitle: `${chalk.cyan("anvil")} service ready at ${chalk.cyan(`${host}:8545`)}`,
|
|
18
|
+
waitTitle: `${chalk.cyan("anvil")} service starting...`,
|
|
19
|
+
errorTitle: `${chalk.red("anvil")} service failed`,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "proxy",
|
|
23
|
+
file: "docker-compose-proxy.yaml",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "database",
|
|
27
|
+
file: "docker-compose-database.yaml",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "rpc",
|
|
31
|
+
file: "docker-compose-node.yaml",
|
|
32
|
+
healthySemaphore: "rollups-node",
|
|
33
|
+
healthyTitle: (port) => `${chalk.cyan("rpc")} service ready at ${chalk.cyan(`${host}:${port}/rpc`)}`,
|
|
34
|
+
waitTitle: `${chalk.cyan("rpc")} service starting...`,
|
|
35
|
+
errorTitle: `${chalk.red("rpc")} service failed`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "inspect",
|
|
39
|
+
file: "docker-compose-node.yaml",
|
|
40
|
+
healthySemaphore: "rollups-node",
|
|
41
|
+
healthyTitle: (port) => `${chalk.cyan("inspect")} service ready at ${chalk.cyan(`${host}:${port}/inspect/<application_address>`)}`,
|
|
42
|
+
waitTitle: `${chalk.cyan("inspect")} service starting...`,
|
|
43
|
+
errorTitle: `${chalk.red("inspect")} service failed`,
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
const availableServices = [
|
|
47
|
+
{
|
|
48
|
+
name: "bundler",
|
|
49
|
+
file: "docker-compose-bundler.yaml",
|
|
50
|
+
healthySemaphore: "bundler",
|
|
51
|
+
healthyTitle: (port) => `${chalk.cyan("bundler")} service ready at ${chalk.cyan(`${host}:${port}/bundler/rpc`)}`,
|
|
52
|
+
waitTitle: `${chalk.cyan("bundler")} service starting...`,
|
|
53
|
+
errorTitle: `${chalk.red("bundler")} service failed`,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "espresso",
|
|
57
|
+
file: "docker-compose-espresso.yaml",
|
|
58
|
+
healthySemaphore: "espresso",
|
|
59
|
+
healthyTitle: (port) => `${chalk.cyan("espresso")} service ready at ${chalk.cyan(`${host}:${port}/transaction`)}`,
|
|
60
|
+
waitTitle: `${chalk.cyan("espresso")} service starting...`,
|
|
61
|
+
errorTitle: `${chalk.red("espresso")} service failed`,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "explorer",
|
|
65
|
+
file: "docker-compose-explorer.yaml",
|
|
66
|
+
healthySemaphore: "explorer_api",
|
|
67
|
+
healthyTitle: (port) => `${chalk.cyan("explorer")} service ready at ${chalk.cyan(`${host}:${port}/explorer`)}`,
|
|
68
|
+
waitTitle: `${chalk.cyan("explorer")} service starting...`,
|
|
69
|
+
errorTitle: `${chalk.red("explorer")} service failed`,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "graphql",
|
|
73
|
+
file: "docker-compose-graphql.yaml",
|
|
74
|
+
healthySemaphore: "graphql",
|
|
75
|
+
healthyTitle: (port) => `${chalk.cyan("graphql")} service ready at ${chalk.cyan(`${host}:${port}/graphql`)}`,
|
|
76
|
+
waitTitle: `${chalk.cyan("graphql")} service starting...`,
|
|
77
|
+
errorTitle: `${chalk.red("graphql")} service failed`,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "paymaster",
|
|
81
|
+
file: "docker-compose-paymaster.yaml",
|
|
82
|
+
healthySemaphore: "paymaster",
|
|
83
|
+
healthyTitle: (port) => `${chalk.cyan("paymaster")} service ready at ${chalk.cyan(`${host}:${port}/paymaster`)}`,
|
|
84
|
+
waitTitle: `${chalk.cyan("paymaster")} service starting...`,
|
|
85
|
+
errorTitle: `${chalk.red("paymaster")} service failed`,
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
const serviceMonitorTask = (options) => {
|
|
89
|
+
const { errorTitle, healthyTitle, service, waitTitle } = options;
|
|
90
|
+
return {
|
|
91
|
+
task: async (_ctx, task) => {
|
|
92
|
+
await pRetry(async () => {
|
|
93
|
+
const health = await getServiceHealth(options);
|
|
94
|
+
if (health !== "healthy") {
|
|
95
|
+
throw new Error(errorTitle ??
|
|
96
|
+
`Service ${chalk.cyan(service)} is not healthy`);
|
|
97
|
+
}
|
|
98
|
+
}, { retries: 100, minTimeout: 500, factor: 1.1 });
|
|
99
|
+
task.title =
|
|
100
|
+
healthyTitle ?? `Service ${chalk.cyan(service)} is ready`;
|
|
101
|
+
},
|
|
102
|
+
title: waitTitle ?? `Starting ${chalk.cyan(service)}...`,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
export const createStartCommand = () => {
|
|
106
|
+
return new Command("start")
|
|
107
|
+
.description("Start a local rollups node environment.")
|
|
108
|
+
.configureHelp({ showGlobalOptions: true })
|
|
109
|
+
.addOption(new Option("--block-time <number>", "interval between blocks (in seconds)")
|
|
110
|
+
.argParser(Number)
|
|
111
|
+
.default(5))
|
|
112
|
+
.addOption(new Option("--default-block <string>", "default block to be used when fetching new blocks.")
|
|
113
|
+
.choices(["latest", "safe", "pending", "finalized"])
|
|
114
|
+
.default("latest"))
|
|
115
|
+
.addOption(new Option("--cpus <number>", "number of cpu limits for the rollups-node").argParser(Number))
|
|
116
|
+
.addOption(new Option("--memory <number>", "memory limit for the rollups-node in MB").argParser(Number))
|
|
117
|
+
.option("--services <string>", `optional services to start, comma separated list from [${availableServices.map(({ name }) => name).join(", ")}]`, commaSeparatedList, [])
|
|
118
|
+
.option("-p, --port <number>", "port to listen on", parseInt, 8080)
|
|
119
|
+
.option("--dry-run", "show the docker compose configuration", false)
|
|
120
|
+
.option("-v, --verbose", "verbose output", false)
|
|
121
|
+
.action(async (options, command) => {
|
|
122
|
+
const { environmentName } = command.optsWithGlobals();
|
|
123
|
+
const { blockTime, cpus, defaultBlock, dryRun, memory, port, services, verbose, } = options;
|
|
124
|
+
// path of the tool instalation
|
|
125
|
+
const binPath = path.join(path.dirname(new URL(import.meta.url).pathname), "../..");
|
|
126
|
+
// setup the environment variable used in docker compose
|
|
127
|
+
const env = {
|
|
128
|
+
BLOCK_TIME: blockTime.toString(),
|
|
129
|
+
CARTESI_BLOCKCHAIN_DEFAULT_BLOCK: defaultBlock,
|
|
130
|
+
CARTESI_LOG_LEVEL: verbose ? "debug" : "info",
|
|
131
|
+
CARTESI_BIN_PATH: binPath,
|
|
132
|
+
CARTESI_LISTEN_PORT: port.toString(),
|
|
133
|
+
CARTESI_ROLLUPS_NODE_CPUS: cpus?.toString(),
|
|
134
|
+
CARTESI_ROLLUPS_NODE_MEMORY: memory?.toString(),
|
|
135
|
+
CARTESI_SDK_IMAGE: DEFAULT_SDK,
|
|
136
|
+
};
|
|
137
|
+
// build a list of unique compose files
|
|
138
|
+
const composeFiles = [
|
|
139
|
+
...new Set(baseServices.map(({ file }) => file)),
|
|
140
|
+
];
|
|
141
|
+
// cpu and memory limits, mostly for testing and debuggingpurposes
|
|
142
|
+
if (cpus) {
|
|
143
|
+
composeFiles.push("docker-compose-node-cpus.yaml");
|
|
144
|
+
}
|
|
145
|
+
if (memory) {
|
|
146
|
+
composeFiles.push("docker-compose-node-memory.yaml");
|
|
147
|
+
}
|
|
148
|
+
// select subset of optional services
|
|
149
|
+
const optionalServices = services.length === 1 && services[0] === "all"
|
|
150
|
+
? availableServices
|
|
151
|
+
: availableServices.filter(({ name }) => services.includes(name));
|
|
152
|
+
// add to compose files list
|
|
153
|
+
composeFiles.push(...optionalServices.map(({ file }) => file));
|
|
154
|
+
// create the "--file <file>" list
|
|
155
|
+
const files = composeFiles
|
|
156
|
+
.map((f) => [
|
|
157
|
+
"--file",
|
|
158
|
+
path.join(binPath, "compose", "rollups", f),
|
|
159
|
+
])
|
|
160
|
+
.flat();
|
|
161
|
+
const composeArgs = [
|
|
162
|
+
"compose",
|
|
163
|
+
...files,
|
|
164
|
+
"--project-name",
|
|
165
|
+
environmentName,
|
|
166
|
+
];
|
|
167
|
+
// run in detached mode (background)
|
|
168
|
+
const upArgs = ["--detach"];
|
|
169
|
+
if (dryRun) {
|
|
170
|
+
// show the docker compose configuration
|
|
171
|
+
await execa("docker", [...composeArgs, "config"], {
|
|
172
|
+
env,
|
|
173
|
+
stdio: "inherit",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
if (defaultBlock !== "finalized") {
|
|
178
|
+
console.warn(chalk.yellow(`WARNING: default block is set to '${defaultBlock}', production configuration will likely use 'finalized'`));
|
|
179
|
+
}
|
|
180
|
+
// pull images first
|
|
181
|
+
await execa("docker", [...composeArgs, "pull"], {
|
|
182
|
+
env,
|
|
183
|
+
stdio: "inherit",
|
|
184
|
+
});
|
|
185
|
+
// run compose environment
|
|
186
|
+
const up = execa("docker", [...composeArgs, "up", ...upArgs], {
|
|
187
|
+
env,
|
|
188
|
+
});
|
|
189
|
+
// create tasks to monitor services startup
|
|
190
|
+
const monitorTasks = [...baseServices, ...optionalServices]
|
|
191
|
+
.filter(({ healthySemaphore }) => !!healthySemaphore) // only services with a healthy semaphore
|
|
192
|
+
.map((service) => {
|
|
193
|
+
const healthyTitle = typeof service.healthyTitle === "function"
|
|
194
|
+
? service.healthyTitle(port)
|
|
195
|
+
: service.healthyTitle;
|
|
196
|
+
return serviceMonitorTask({
|
|
197
|
+
environmentName,
|
|
198
|
+
service: service.healthySemaphore,
|
|
199
|
+
errorTitle: service.errorTitle,
|
|
200
|
+
waitTitle: service.waitTitle,
|
|
201
|
+
healthyTitle,
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
const tasks = new Listr(monitorTasks, { concurrent: true });
|
|
205
|
+
await tasks.run();
|
|
206
|
+
await up;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/rollups/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAOtD,eAAO,MAAM,mBAAmB;;;;EA8C/B,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
import { getServiceState } from "../../base.js";
|
|
5
|
+
import { getDeployments } from "../../exec/rollups.js";
|
|
6
|
+
export const createStatusCommand = () => {
|
|
7
|
+
return new Command("status")
|
|
8
|
+
.description("Shows the status of a local rollups node environment.")
|
|
9
|
+
.configureHelp({ showGlobalOptions: true })
|
|
10
|
+
.option("--json", "output in JSON format")
|
|
11
|
+
.action(async ({ json }, command) => {
|
|
12
|
+
const { environmentName } = command.optsWithGlobals();
|
|
13
|
+
const status = await getServiceState({
|
|
14
|
+
environmentName,
|
|
15
|
+
service: "rollups-node",
|
|
16
|
+
});
|
|
17
|
+
const deployments = await getDeployments({ environmentName });
|
|
18
|
+
if (json) {
|
|
19
|
+
process.stdout.write(JSON.stringify({
|
|
20
|
+
status,
|
|
21
|
+
deployments,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(`${chalk.cyan(environmentName)} is ${status == "running" ? chalk.green("running") : chalk.red("not running")}`);
|
|
26
|
+
if (status === "running") {
|
|
27
|
+
if (deployments.length === 0) {
|
|
28
|
+
console.log(chalk.red("no applications deployed"));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// print as a table
|
|
32
|
+
const table = new Table({
|
|
33
|
+
head: ["Machine", "Address", "State"],
|
|
34
|
+
style: { border: [], head: [] },
|
|
35
|
+
});
|
|
36
|
+
table.push(...deployments.map((deployment) => [
|
|
37
|
+
deployment.templateHash,
|
|
38
|
+
deployment.address,
|
|
39
|
+
deployment.state,
|
|
40
|
+
]));
|
|
41
|
+
console.log(table.toString());
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../../src/commands/rollups/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAMtD,eAAO,MAAM,iBAAiB;;EAwB7B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
export const createStopCommand = () => {
|
|
6
|
+
return new Command("stop")
|
|
7
|
+
.description("Stop a local rollups node environment.")
|
|
8
|
+
.configureHelp({ showGlobalOptions: true })
|
|
9
|
+
.action(async (_options, command) => {
|
|
10
|
+
const { environmentName } = command.optsWithGlobals();
|
|
11
|
+
const progress = ora(`Stopping ${chalk.cyan(environmentName)} environment...`).start();
|
|
12
|
+
try {
|
|
13
|
+
await execa("docker", [
|
|
14
|
+
"compose",
|
|
15
|
+
"-p",
|
|
16
|
+
environmentName,
|
|
17
|
+
"down",
|
|
18
|
+
"--volumes",
|
|
19
|
+
]);
|
|
20
|
+
progress.succeed(`${chalk.cyan(environmentName)} environment stopped.`);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
progress.fail(e.message);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
export declare const createRollupsCommand: () => Command<[], {
|
|
3
|
+
environmentName: string;
|
|
4
|
+
}, {}>;
|
|
5
|
+
export type RollupsCommandOpts = ReturnType<ReturnType<typeof createRollupsCommand>["opts"]>;
|
|
6
|
+
//# sourceMappingURL=rollups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollups.d.ts","sourceRoot":"","sources":["../../src/commands/rollups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAOtD,eAAO,MAAM,oBAAoB;;MAgBhC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,UAAU,CACvC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAClD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from "@commander-js/extra-typings";
|
|
2
|
+
import { createDeployCommand } from "./rollups/deploy.js";
|
|
3
|
+
import { createLogsCommand } from "./rollups/logs.js";
|
|
4
|
+
import { createStartCommand } from "./rollups/start.js";
|
|
5
|
+
import { createStatusCommand } from "./rollups/status.js";
|
|
6
|
+
import { createStopCommand } from "./rollups/stop.js";
|
|
7
|
+
export const createRollupsCommand = () => {
|
|
8
|
+
const command = new Command("rollups")
|
|
9
|
+
.option("--environment-name <string>", "name of environment", "cartesi-rollups")
|
|
10
|
+
.action(async (_options, program) => {
|
|
11
|
+
program.help();
|
|
12
|
+
});
|
|
13
|
+
command.addCommand(createLogsCommand());
|
|
14
|
+
command.addCommand(createStartCommand());
|
|
15
|
+
command.addCommand(createStatusCommand());
|
|
16
|
+
command.addCommand(createStopCommand());
|
|
17
|
+
command.addCommand(createDeployCommand());
|
|
18
|
+
return command;
|
|
19
|
+
};
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGtD,eAAO,MAAM,gBAAgB,2BAW5B,CAAC"}
|