@ethernity-cloud/sdk-js 1.7.13 → 1.7.15

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/README.md CHANGED
@@ -182,6 +182,11 @@ sets the enclave heap (default `1024M`).
182
182
  `--network`/`--securelock`/`--trustedzone`; the signing key is `PRIVATE_KEY`
183
183
  (or `ECLD_PRIVATE_KEY`) — a funded `0x` key that pays for the order. Resources
184
184
  are tunable with `--task-price`/`--cpu`/`--memory`/`--storage`/`--bandwidth`/`--duration`/`--validators`.
185
+ `--input <file>` / `--input-text <string>` send the task's input dataset, read
186
+ as `___etny_data_set___`; it travels encrypted, and the trustedzone checks it
187
+ against the sha256 the request carries. Exit code 0 on a `SUCCESS` task result,
188
+ 1 otherwise; a task that raised in the enclave prints its task code (e.g.
189
+ `4 (BASE_EXCEPTION)`) and the enclave's error report as its result.
185
190
  `--ipfs intake` (the default) delivers the payload to the bootnode's payload
186
191
  intake once the request is on chain; `--ipfs <url>` writes and reads through
187
192
  that IPFS RPC API instead, with `ECLD_IPFS_TOKEN` (or `IPFS_TOKEN`) as its
package/cas/config.js CHANGED
@@ -14,8 +14,9 @@
14
14
  // Kept in sync with etny-{pynithy,nodenithy}/v3/networks.yaml
15
15
  // (cas_session_registry_address, validator_registry_address).
16
16
  const VALIDATOR_REGISTRY = {
17
- 'etny-pynithy-testnet': '0x0014aB102FEa6b02e3D793FF4b9a0Af309fB4E14',
18
- 'etny-nodenithy-testnet': '0x0014aB102FEa6b02e3D793FF4b9a0Af309fB4E14',
17
+ // The Phase 2 ValidatorRegistry of 2026-10-21 (ethernity-cas CAS-SETUP.md).
18
+ 'etny-pynithy-testnet': '0x8CC8B1dc22f0E06193161CeC79d75987b0640e02',
19
+ 'etny-nodenithy-testnet': '0x8CC8B1dc22f0E06193161CeC79d75987b0640e02',
19
20
  'ecld-pynithy-litvm-testnet': '0xbE3759f327e8643fC5A1717fb2072A0dAcBAD29E',
20
21
  'ecld-nodenithy-litvm-testnet': '0xbE3759f327e8643fC5A1717fb2072A0dAcBAD29E',
21
22
  'ecld-pynithy-ethereum-sepolia': '0x8ad24b3F406A41a0F8D3440021792EB203957F43',
@@ -23,8 +24,10 @@ const VALIDATOR_REGISTRY = {
23
24
  };
24
25
 
25
26
  const SESSION_REGISTRY = {
26
- 'etny-pynithy-testnet': '0x444429681fCb26470Cb12B5436E48402cF7478A3',
27
- 'etny-nodenithy-testnet': '0x444429681fCb26470Cb12B5436E48402cF7478A3',
27
+ // The SessionRegistry with image binding of 2026-10-22; it links an image
28
+ // only once the Image Registry records it under the session's name.
29
+ 'etny-pynithy-testnet': '0x78f0c5E92E7A9Ec2f2A36A4509ED4a75D0f9463B',
30
+ 'etny-nodenithy-testnet': '0x78f0c5E92E7A9Ec2f2A36A4509ED4a75D0f9463B',
28
31
  'ecld-pynithy-litvm-testnet': '0xfA70B5Df7C773A21164cAc5413704117e4dEaB76',
29
32
  'ecld-nodenithy-litvm-testnet': '0xfA70B5Df7C773A21164cAc5413704117e4dEaB76',
30
33
  // Bound to Sepolia's ECImageRegistryV3 of 2026-10-14.
@@ -117,8 +120,19 @@ const renderCompose = (content, cas, unsafe) => content
117
120
  .map((line) => line.replace(/\s*# __(?:CAS|NO_CAS|SAFE)_ONLY__$/, ''))
118
121
  .join('\n');
119
122
 
123
+ // The securelock session's ESR environment entry. A CAS-provisioned enclave
124
+ // takes its environment from the session, not from the image's ENV, so the
125
+ // registry address the build baked must also be set here; without ESR (or
126
+ // without an address) the entry is a YAML comment.
127
+ const esrSessionEnvironment = (env) => {
128
+ const enabled = /^(1|true|yes)$/i.test(String(env.ESR_ENABLED || '').trim());
129
+ const address = String(env.ESR_CONTRACT_ADDRESS || '').trim();
130
+ if (!enabled || !/^0x[0-9a-fA-F]{40}$/.test(address)) return '# ESR not enabled';
131
+ return `ESR_CONTRACT_ADDRESS: "${address}"`;
132
+ };
133
+
120
134
  module.exports = {
121
135
  VALIDATOR_REGISTRY, SESSION_REGISTRY, CHAIN, casProvisioned, isMainnetNetwork,
122
136
  UNSAFE_NETWORKS, isUnsafeNetwork, TESTNETS, isTestnetNetwork, sessionAttestation,
123
- nameOnNetwork, sessionTag, renderCompose,
137
+ nameOnNetwork, sessionTag, renderCompose, esrSessionEnvironment,
124
138
  };
@@ -20,6 +20,9 @@ services:
20
20
  pwd: /
21
21
  environment:
22
22
  GREETING: hello from ETNY SECURELOCK!!!!
23
+ # A CAS-provisioned enclave takes its environment from this session,
24
+ # not from the image's ENV; run.js fills in the ESR registry address.
25
+ __ESR_ENVIRONMENT__
23
26
 
24
27
  images:
25
28
  - name: application_image
package/nodenithy/run.js CHANGED
@@ -311,7 +311,8 @@ const main = async () => {
311
311
  const replacementsSecurelock = {
312
312
  PREDECESSOR: PREDECESSOR_HASH_SECURELOCK === 'EMPTY' ? `# predecessor: ${PREDECESSOR_HASH_SECURELOCK}` : `predecessor: ${PREDECESSOR_HASH_SECURELOCK}`,
313
313
  MRENCLAVE: process.env.MRENCLAVE_SECURELOCK,
314
- ENCLAVE_NAME: ENCLAVE_NAME_SECURELOCK
314
+ ENCLAVE_NAME: ENCLAVE_NAME_SECURELOCK,
315
+ ESR_ENVIRONMENT: casConfig.esrSessionEnvironment(process.env)
315
316
  };
316
317
  if (cas) {
317
318
  processYamlTemplate('etny-securelock-test.yaml.tpl', 'etny-securelock-test.yaml', replacementsSecurelock);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethernity-cloud/sdk-js",
3
- "version": "1.7.13",
3
+ "version": "1.7.15",
4
4
  "description": "A package to run ethernity cloud build scripts",
5
5
  "scripts": {
6
6
  "test": "node --test \"test/**/*.test.js\"",
@@ -32,6 +32,7 @@
32
32
  "test.js",
33
33
  "info.js",
34
34
  "run.js",
35
+ "runReport.js",
35
36
  "network.js",
36
37
  "localKubo.js",
37
38
  "revert.js",
@@ -39,7 +40,7 @@
39
40
  "!**/*.pyc"
40
41
  ],
41
42
  "dependencies": {
42
- "@ethernity-cloud/runner": "^0.6.6",
43
+ "@ethernity-cloud/runner": "^0.6.11",
43
44
  "acorn": "^8.11.0",
44
45
  "adm-zip": "^0.5.14",
45
46
  "axios": "^1.7.2",
@@ -24,6 +24,9 @@ services:
24
24
  # libraries call os.path.expanduser('~') at startup and abort with
25
25
  # "$HOME is not defined" before the enclave emits its public key.
26
26
  HOME: /tmp
27
+ # A CAS-provisioned enclave takes its environment from this session,
28
+ # not from the image's ENV; run.js fills in the ESR registry address.
29
+ __ESR_ENVIRONMENT__
27
30
 
28
31
  images:
29
32
  - name: application_image
package/pynithy/run.js CHANGED
@@ -309,7 +309,8 @@ const main = async () => {
309
309
  const replacementsSecurelock = {
310
310
  PREDECESSOR: PREDECESSOR_HASH_SECURELOCK === 'EMPTY' ? `# predecessor: ${PREDECESSOR_HASH_SECURELOCK}` : `predecessor: ${PREDECESSOR_HASH_SECURELOCK}`,
311
311
  MRENCLAVE: process.env.MRENCLAVE_SECURELOCK,
312
- ENCLAVE_NAME: ENCLAVE_NAME_SECURELOCK
312
+ ENCLAVE_NAME: ENCLAVE_NAME_SECURELOCK,
313
+ ESR_ENVIRONMENT: casConfig.esrSessionEnvironment(process.env)
313
314
  };
314
315
  if (cas) {
315
316
  processYamlTemplate('etny-securelock-test.yaml.tpl', 'etny-securelock-test.yaml', replacementsSecurelock);
package/run.js CHANGED
@@ -44,6 +44,7 @@ try { require('dotenv').config(); } catch (e) { /* dotenv optional */ }
44
44
  const casConfig = require('./cas/config.js');
45
45
  const { networkFor, unsafeVariant } = require('./network.js');
46
46
  const { PUBLIC_IPFS_HOST } = require('./localKubo.js');
47
+ const { reportRun } = require('./runReport.js');
47
48
 
48
49
  // `--ipfs intake` (the default): the artefacts' CIDs are computed locally and
49
50
  // the bytes delivered to the bootnode's payload intake once the DO request is
@@ -116,20 +117,19 @@ async function main() {
116
117
  let input = null;
117
118
  if (opts.inputFile !== undefined) input = fs.readFileSync(opts.inputFile, 'utf8');
118
119
  else if (opts.inputText !== undefined) input = opts.inputText;
119
- // The enclave executor exposes the input as ___etny_data_set___; the runner
120
- // passes it as part of the code's scope, so a payload references it by name.
121
- // ecld-run mirrors ecld-test: input is delivered via the payload call itself.
120
+ // The input is the task's input dataset (runner option inputData): sent
121
+ // sealed for the trustedzone and read in the payload as ___etny_data_set___.
122
122
 
123
123
  // ---- runner (ESM) ----
124
- let EthernityCloudRunner, ECStatus, ECEvent, ECOrderTaskStatus, enums;
124
+ let EthernityCloudRunner, ECStatus, ECEvent, enums;
125
125
  try {
126
126
  const runnerMod = await import('@ethernity-cloud/runner');
127
127
  EthernityCloudRunner = runnerMod.default || runnerMod.EthernityCloudRunner;
128
128
  enums = await import('@ethernity-cloud/runner/enums.js');
129
- ({ ECStatus, ECEvent, ECOrderTaskStatus } = enums);
129
+ ({ ECStatus, ECEvent } = enums);
130
130
  } catch (e) {
131
131
  console.error('ecld-run: the runner package is not installed or is too old '
132
- + '(need @ethernity-cloud/runner >= 0.6.0): ' + e.message);
132
+ + '(need @ethernity-cloud/runner >= 0.6.11): ' + e.message);
133
133
  process.exit(1);
134
134
  }
135
135
 
@@ -228,10 +228,9 @@ async function main() {
228
228
  const timeout = new Promise((resolve) => { timer = setTimeout(() => resolve('TIMEOUT'), timeoutMs); });
229
229
 
230
230
  try {
231
- const runArgs = [resources, securelock, code, opts.node];
232
- if (trustedzone) runArgs.push(trustedzone);
233
231
  // Fire the run; its own promise also settles on completion.
234
- const runPromise = runner.run(...runArgs).catch((e) => ({ error: e.message }));
232
+ const runPromise = runner.run(resources, securelock, code, opts.node, trustedzone || null, { inputData: input })
233
+ .catch((e) => ({ error: e.message }));
235
234
  const outcome = await Promise.race([done, timeout, runPromise]);
236
235
  clearTimeout(timer);
237
236
 
@@ -239,28 +238,7 @@ async function main() {
239
238
  console.error(`\necld-run: no result after ${opts.timeout}s; the order may still process on-chain.`);
240
239
  process.exit(1);
241
240
  }
242
- if (outcome && outcome.error) {
243
- console.error(`\nstatus : ERROR`);
244
- console.error(`error : ${outcome.error}`);
245
- process.exit(1);
246
- }
247
-
248
- // SUCCESS
249
- const result = await runner.getResult();
250
- const typed = (runner.getStructuredResult && runner.getStructuredResult()) || null;
251
- const taskCode = runner.resultTaskCode;
252
- const taskName = runner.resultTaskCodeName
253
- || (ECOrderTaskStatus && taskCode !== undefined ? ECOrderTaskStatus[taskCode] : undefined);
254
-
255
- if (opts.json) {
256
- console.log(JSON.stringify({ task_code: taskCode, task_code_name: taskName, value: result, structured: typed }, null, 2));
257
- } else {
258
- if (taskName && taskName !== 'SUCCESS') console.log(`task code : ${taskCode} (${taskName})`);
259
- console.log('result :');
260
- console.log(result);
261
- }
262
- // A non-zero enclave task code is a failed run even though the order landed.
263
- process.exit(taskCode === undefined || taskCode === 0 ? 0 : 1);
241
+ process.exit(await reportRun(runner, outcome, { json: opts.json }));
264
242
  } catch (e) {
265
243
  clearTimeout(timer);
266
244
  console.error('ecld-run: run failed: ' + (e && e.stack ? e.stack : e));
package/runReport.js ADDED
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ /* ecld-run's report of a finished run.
4
+ *
5
+ * A run that delivered a result prints it; a task the enclave reported with a
6
+ * non-zero task code (an exception in the dApp, a checksum mismatch, ...)
7
+ * prints that code and its result, which is the enclave's error report. The
8
+ * runner signals such a task with its ERROR event, carrying getLastError().
9
+ */
10
+
11
+ /**
12
+ * Print the outcome of a run and return the exit code.
13
+ * outcome: 'SUCCESS', or { error } from the ERROR event or a rejected run().
14
+ */
15
+ async function reportRun(runner, outcome, { json = false, out = console.log, err = console.error } = {}) {
16
+ // { code, name } of the enclave's task code, or null when no result came.
17
+ const taskCode = runner.getResultTaskCode();
18
+ const error = outcome && outcome.error;
19
+ if (!taskCode && error) {
20
+ err('\nstatus : ERROR');
21
+ err(`error : ${error}`);
22
+ return 1;
23
+ }
24
+ const result = await runner.getResult();
25
+ const typed = (runner.getStructuredResult && runner.getStructuredResult()) || null;
26
+ if (json) {
27
+ out(JSON.stringify({
28
+ task_code: taskCode ? taskCode.code : undefined,
29
+ task_code_name: taskCode ? taskCode.name : undefined,
30
+ value: result,
31
+ structured: typed,
32
+ }, null, 2));
33
+ } else {
34
+ if (taskCode && taskCode.code !== 0) out(`task code : ${taskCode.code} (${taskCode.name})`);
35
+ out('result :');
36
+ out(result);
37
+ }
38
+ if (taskCode && taskCode.code !== 0) {
39
+ err(`error : ${runner.getLastError() || error || taskCode.name}`);
40
+ return 1;
41
+ }
42
+ return error ? 1 : 0;
43
+ }
44
+
45
+ module.exports = { reportRun };