@ethernity-cloud/runner

中文文档
0.6.27发布于 2026/11/07AGPL-3.0ES Module近 30 天下载 2229

Ethernity Cloud Runner

原始使用文档
文档目录12 节
  1. The JavaScript implementation of the Ethernity CLOUD protoc…
  2. Installation
  3. Environment Prerequisites
  4. 4. Code execution
  5. Choosing the trustedzone
  6. ___etny_result___ function
  7. Events subscription
  8. Input dataset
  9. Task resources
  10. Networks
  11. Wallet options
  12. Storage and the result read

Ethernity Cloud logo

The JavaScript implementation of the Ethernity CLOUD protocol

Installation

To begin developing with the Ethernity Cloud Runner, you can easily set up your environment by installing the package using npm:

$ npm install @ethernity-cloud/runner --save

This command will install the Ethernity Cloud Runner package and save it as a dependency in your project. With the package installed, you're ready to start utilizing the Ethernity Cloud Runner functionality and explore its capabilities for your application development.

Environment Prerequisites

1. IDE

For a streamlined development process, we recommend using Visual Studio Code—a powerful and versatile code editor that offers a seamless experience for developers. You can download Visual Studio Code from the official website.

After running the IDE, a new workspace will be created, where you can start developing the framework and code.

2. Framework

Using a Terminal within the IDE workspace, follow these steps to set up your framework of choice.

Node.js: Node.js is an open-source, server-side JavaScript runtime environment that allows developers to execute JavaScript code outside of a web browser. It uses an event-driven, non-blocking I/O model, making it highly efficient and suitable for building scalable and real-time applications.

Install Node.js on your local machine by following the instructions provided here: Node.js Download.

3. Wallet Setup

A wallet is a crucial tool within the Ethernity Cloud ecosystem, empowering users to securely store and transfer their data for processing. As a developer, having a Web3 dApp testing wallet is necessary.

The wallet setup process with Metamask is detailed here: Getting started with MetaMask.

Ethernity Cloud runs on several networks. Set up your wallet for the network you intend to use (see the Networks section below for the full list and chain IDs):

  • Bloxberg (mainnet and testnet)
  • Polygon (mainnet) and Polygon Amoy (testnet)
  • IoTeX Testnet, Ethereum Sepolia, and LitVM LiteForge (testnets)

4. Code execution

To execute a new task using the Ethernity Cloud Runner, follow the straightforward template provided below. Simply insert your desired code into the designated section, and the runner will handle the rest, interacting with the IPFS network and processing the task accordingly.

import EthernityCloudRunner from "@ethernity-cloud/runner";
import { ECRunner, ECStatus, ECAddress } from "@ethernity-cloud/runner/enums";

const executeTask = async () => {
    const code = `___etny_result___("Hello, World!")`;

    // Progress updates (encrypting, submitting, matching, downloading, ...).
    const onProgress = (e) => {
        console.log(`[${e.detail.progress}] ${e.detail.message}`);
    };

    // Fired once the task completes; fetch the result from the runner.
    const onSuccess = async () => {
        const result = await runner.getResult();
        console.log(`Task Result: ${result}`);
    };

    const onError = (e) => {
        console.error(e.detail.message);
    };

    // No network address -> Bloxberg testnet + the browser wallet.
    // To target another network pass its token address, e.g.
    //   new EthernityCloudRunner(ECAddress.POLYGON.TESTNET_ADDRESS);
    const runner = new EthernityCloudRunner();
    // On the Bloxberg testnet the task's artefacts are delivered through the
    // bootnode's payload intake: no storage call is needed. Every other network
    // needs your own Kubo RPC API, which also replaces the intake here:
    //   runner.initializeStorage('http://127.0.0.1:5001');

    // Events are dispatched named by task status (the ECStatus values).
    runner.addEventListener(ECStatus.DEFAULT, onProgress); // "Running" updates
    runner.addEventListener(ECStatus.SUCCESS, onSuccess);
    runner.addEventListener(ECStatus.ERROR, onError);

    const resources = { taskPrice: 10, cpu: 1, memory: 1, storage: 40, bandwidth: 1, duration: 1, validators: 1 };
    // Execute a task with the Python testnet enclave on Bloxberg.
    // Signature: run(resources, secureLockEnclave, code, nodeAddress = '', trustedZoneEnclave)
    await runner.run(resources, ECRunner.BLOXBERG.PYNITHY_RUNNER_TESTNET, code);
}

await executeTask();

Choosing the trustedzone

run() and runSession() take trustedZoneEnclave, the trustedzone the securelock was built against. It defaults to the one setNetwork() chose, else the network's pynithy trustedzone (etny-pynithy-testnet on the bloxberg testnet); a nodenithy dApp passes etny-nodenithy-testnet.

A securelock published without a CAS (<project>-unsafe) runs on an -unsafe network, which you choose by name with await runner.setNetwork('BLOXBERG', 'TESTNET_UNSAFE') (or ('LITVM', 'TESTNET_UNSAFE')). An -unsafe network has the chain and contracts of the network it is named after; its trustedzone is etny-pynithy-testnet-unsafe (ecld-pynithy-litvm-testnet-unsafe on LitVM), and a nodenithy dApp passes ECRunner.BLOXBERG.NODENITHY_RUNNER_TESTNET_UNSAFE. The runner runs an -unsafe trustedzone only on an -unsafe network and runs nothing else there, so a task that runs without a CAS always says so in the network it names.

The runner accepts a result only when the transaction the enclave signed is _addResultToOrder for this order, addressed to this network's protocol contract and signed for this chain, and its signer is the wallet derived from the task's challenge. Task codes 37, 39 and 40 (OPERATOR_FAULT_CODES) are node-side faults the validator refunds; the runner resubmits such a task as a new request.

___etny_result___ function

The ___etny_result___ function is a special function used in Ethernity Cloud Runner tasks. When executing a task, this function allows the task code to send the result back from the Ethernity Cloud platform.

In the context of the Ethernity Cloud Runner, tasks are executed in a decentralized and distributed manner. The ___etny_result___ function acts as a communication channel between the task code and the Ethernity Cloud platform. When the function is called with the result data as its argument, it sends the result back to the platform, where it can be processed and stored.

This special function plays a crucial role in ensuring that the results of executed tasks are properly recorded and accessible. It enables seamless interaction with the Ethernity Cloud platform, making it a key component of the Ethernity Cloud Runner's functionality.

Events subscription

The runner extends EventTarget and, as a task moves through its lifecycle, dispatches CustomEvents named by the task status. You therefore subscribe using the ECStatus values, not a separate event-name enum:

Event name (ECStatus)ValueWhen it fires
ECStatus.DEFAULT"Running"Progress updates while the task is encrypting, being submitted, matched, processed, and the result downloaded.
ECStatus.SUCCESS"Success"The task finished successfully and a result is available.
ECStatus.ERROR"Error"The task failed (e.g. no matching node, insufficient balance, checksum error).

Every event's detail is { message, status, progress }:

  • message — a human-readable message for the current step.
  • status — the ECStatus value (same as the event name).
  • progress — a phase label from ECEvent (e.g. "Encrypting task", "In Progress", "Downloading result", "Finished"), useful for driving a progress UI.
// Progress: use e.detail.progress for the phase and e.detail.message for detail.
const onProgress = (e) => {
    console.log(`[${e.detail.progress}] ${e.detail.message}`);
};

// Success: the result is available on the runner once this fires.
const onSuccess = async () => {
    const result = await runner.getResult();
    console.log(`Task Result: ${result}`);
};

// Error: something went wrong; e.detail.message explains what.
const onError = (e) => {
    console.error(e.detail.message);
};

runner.addEventListener(ECStatus.DEFAULT, onProgress);
runner.addEventListener(ECStatus.SUCCESS, onSuccess);
runner.addEventListener(ECStatus.ERROR, onError);

After ECStatus.SUCCESS, call await runner.getResult() to obtain the decrypted task result.

A task the enclave reports with a non-zero task code, such as BASE_EXCEPTION for an exception raised in the dApp, ends in ECStatus.ERROR: runner.getLastError() names the code, runner.getResultTaskCode() returns { code, name }, and await runner.getResult() still returns the result, whose value is the enclave's error report (for an exception, its traceback).

Input dataset

run(resources, secureLockEnclave, code, nodeAddress, trustedZoneEnclave, { inputData }) sends a string to the task as its input dataset, read in the payload as ___etny_data_set___ (ecld.input). It is encrypted for the trustedzone and stored like the code, and the request carries its sha256, which the trustedzone verifies before the securelock receives it. An interactive session takes its inputs through sendInput instead.

Every artefact (challenge, code, input) is stored as an IPFS node with its default settings stores a file added with --cid-version=1 --raw-leaves: in blocks of 256 KiB, a single block as it is, several under a UnixFS tree. The runner computes that CID itself, so an artefact of any size is named in the request before it is uploaded, and the bootnode's payload intake takes it up to its 100 MiB body cap.

Task resources

 const resources = { taskPrice: 10, cpu: 1, memory: 1, storage: 40, bandwidth: 1, duration: 1, validators: 1 };

The resources parameter is the first argument to the run method and is an object that defines the resource requirements for executing a new task using the Python/Node.js template. It specifies the amount of various resources needed for the task to be processed on the EthernityCloud network. The resources object contains the following properties:

  1. taskPrice: the most the user pays per hour of the task, in whole tokens (tETNY on bloxberg). A node takes the order when this covers its own price plus the fees the network adds to it: 5% for Ethernity, 2% for the validator, and the publishers' fees of the two images the task runs with (the trustedzone template's, 10% unless its publisher set another, and the securelock's, 0 unless its publisher set one), so a node asking 1 token is taken from a price of 2 with the default fees.

  2. cpu: This specifies the amount of CPU (Central Processing Unit) resources required for the task. It indicates the computational power needed to execute the task's code.

  3. memory: This indicates the amount of RAM memory required for the task's execution. It represents the storage space in RAM memory needed to run the task.

  4. storage: This property represents the storage space needed for the task's execution. It indicates the amount of disk space required for the task.

  5. bandwidth: This defines the amount of network bandwidth required for the task's execution. It represents the data transfer capacity needed to perform the task.

  6. duration: This specifies the time duration or the maximum time allowed for the task's execution. It sets a time limit for how long the task can run.

  7. validators: This property determines the number of validators required for the task. Validators are nodes on the network responsible for processing and validating tasks.

By providing these resource requirements in the resources object, the task execution engine (EthernityCloudRunner) can use this information to allocate the necessary resources and process the task accordingly on the selected network.

When no node places an order on the request within options.orderWaitSeconds (the sixth argument of run, default 1800), the runner cancels the request, which returns its escrow, and the task fails with ECError.NO_NODE. If a node booked the request just before the cancel, the cancel is refused by the contract and the task goes on with that node's order.

Networks

The network is chosen by passing the network's token contract address (from ECAddress) as the first argument to the constructor. With no argument, the runner targets the Bloxberg testnet.

NetworkTypeChain IDConstructor address
Bloxbergmainnet8995ECAddress.BLOXBERG.MAINNET_ADDRESS
Bloxbergtestnet8995ECAddress.BLOXBERG.TESTNET_ADDRESS
Polygonmainnet137ECAddress.POLYGON.MAINNET_ADDRESS
Polygon Amoytestnet80002ECAddress.POLYGON.TESTNET_ADDRESS
IoTeXtestnet4690ECAddress.IOTEX.TESTNET_ADDRESS
Ethereum Sepoliatestnet11155111ECAddress.SEPOLIA.TESTNET_ADDRESS
LitVM LiteForgetestnet4441ECAddress.LITVM.TESTNET_ADDRESS

A testnet that has an ethernity-cas validator set -- Bloxberg testnet, LitVM LiteForge and Ethereum Sepolia -- comes in two kinds. The table's entry runs the securelock in an enclave the set attests, on nodes whose platform it can attest (DCAP), and the set validates the order in full, as on mainnet. Beside each is an -unsafe network, chosen by name with await runner.setNetwork('BLOXBERG', 'TESTNET_UNSAFE'), ('LITVM', 'TESTNET_UNSAFE') or ('SEPOLIA', 'TESTNET_UNSAFE'): the same chain and contracts, for hardware SGX platforms the CAS cannot attest (EPID-only, SGX1); its enclaves are debug-signed and self-signed from their measurement, so a result proves which image ran, not that an enclave ran it, and the validators judge such an order without the challenge-derived signer check. Its enclaves are the *_TESTNET_UNSAFE entries of ECRunner (see "Choosing the trustedzone"). Mainnet has no -unsafe network.

import { ECAddress, ECRunner } from "@ethernity-cloud/runner/enums";

// Run on Polygon Amoy
const runner = new EthernityCloudRunner(ECAddress.POLYGON.TESTNET_ADDRESS);
// ...
await runner.run(resources, ECRunner.POLYGON.PYNITHY_RUNNER_TESTNET, code);

The ECRunner enclave-image enum is keyed by network, so use the entry matching the network you constructed the runner with (e.g. ECRunner.IOTEX.PYNITHY_RUNNER_TESTNET). Mainnet variants drop the _TESTNET suffix.

The IoTeX and LitVM testnets share a single ECLD token address, so the runner reads the chain ID from your wallet/provider to distinguish them — automatic with a browser wallet or an injected provider. Ethereum Sepolia has a token of its own, so the runner selects its RPC (https://ethereum-sepolia-rpc.publicnode.com) without an rpcUrl. On the raw-private-key path for IoTeX and LitVM, pass the chain ID as the third constructor argument and an rpcUrl in the wallet options:

const runner = new EthernityCloudRunner(
    ECAddress.IOTEX.TESTNET_ADDRESS,
    { privateKey: "0x…", rpcUrl: "https://babel-api.testnet.iotex.io" },
    4690 // IoTeX Testnet chain ID
);

In this release the bootnode's payload intake serves the Bloxberg testnet, Polygon Amoy, LitVM LiteForge and Ethereum Sepolia (each with its -unsafe twin). On every other network in the table (Bloxberg mainnet, Polygon mainnet and IoTeX) a run needs runner.initializeStorage(<your own Kubo RPC URL>) before run() (see Storage and the result read); without it run() fails before any transaction is sent, with an error that says so.

Wallet options

The second constructor argument chooses the wallet: { privateKey, rpcUrl } signs with a raw key on the network's RPC (or rpcUrl); { signer } and/or { provider } use a wallet you already hold; with neither, the runner uses the browser wallet at window.ethereum. encryptionPublicKey (hex) supplies the key results are encrypted to when the wallet cannot answer eth_getEncryptionPublicKey. The runner is built on ethers 6, so a signer or provider you pass must be an ethers 6 object; with a provider alone, the runner asks it for its account the first time it needs one.

Storage and the result read

A task's artefacts (the encrypted challenge and code, and a session's inputs) are delivered through the bootnode's payload intake by default: the runner computes their CIDs locally and, once the DO request is on chain, POSTs the bytes to https://ipfs.ethernity.cloud/payload/<network>/<doRequestId>/<cid>, which takes no token. The intake serves the networks the bootnode's agent runs, and the runner routes to it the Bloxberg testnet and LitVM LiteForge, each with its -unsafe twin: on every other network (Bloxberg mainnet, Polygon mainnet, Polygon Amoy, IoTeX and Sepolia) run() fails before any transaction is sent, until a storage is configured. On the Bloxberg testnet, runner.initializePublicIntake(baseUrl) selects the intake explicitly, at another base URL when needed.

initializeStorage delivers through an IPFS API of your own instead, as a URL or as host, protocol and port, and takes precedence over the intake:

// Your own Kubo RPC API.
runner.initializeStorage('http://127.0.0.1:5001');
// The same, by host.
runner.initializeStorage('127.0.0.1', 'http', 5001);
// The public API, which answers add and pin with 403 without a writer token.
// The token is sent as given in the Authorization header of every request.
runner.initializeStorage('https://ipfs.ethernity.cloud', undefined, undefined, writerToken);

A result is read from the configured endpoint first and from the public gateway https://ipfs.io second, without credentials; each request is abandoned after 60 seconds, and the read is repeated until the order's deadline (its duration plus 15 minutes, and at least two minutes after it closed) before the task is reported as IPFS download result error.

版本与发布记录

@ethernity-cloud/runner 共发布 67 个版本,首次发布于 2023/08/02;过去 12 个月发布了 40 个版本。

版本发布日期距今
0.6.27latest2026/11/077 天前
0.6.232026/10/2717 天前
0.6.222026/10/2718 天前
0.6.202026/10/2718 天前
0.6.192026/10/2718 天前
0.6.172026/10/2519 天前

关于 @ethernity-cloud/runner 的常见问题

@ethernity-cloud/runner 是什么?

Ethernity Cloud Runner

如何安装 @ethernity-cloud/runner?

在项目目录运行 npm install @ethernity-cloud/runner,或使用 pnpm add / yarn add / bun add。

@ethernity-cloud/runner 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/ethernity-cloud__runner 是否存在。

@ethernity-cloud/runner 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@ethernity-cloud/runner 可以商用吗?

@ethernity-cloud/runner 使用 AGPL-3.0 许可。最严格的 Copyleft:除分发外,通过网络向用户提供基于它的服务也需要开源对应源码。闭源 SaaS 使用前务必评估。以上为概括,不构成法律意见,请以许可原文为准。

@ethernity-cloud/runner 的下载量有多少?

根据 npm 官方下载统计,@ethernity-cloud/runner 在 2026/10/14 – 2026/11/12 这 30 天内被下载 2,229 次,日均约 74 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ethernity-cloud/runner 还在维护吗?

最新版本 0.6.27 发布于 2026/11/07(7 天前);至今共发布 67 个版本,其中过去 12 个月发布了 40 个;首次发布于 2023/08/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。