Step-by-Step dApp
Now put a web UI on the dApp you published. This chapter builds a React frontend that calls your enclave's functions through the runner — the browser submits a payload, the network executes it in your enclave, and the decrypted result comes back to the page. If you haven't published a dApp yet, start with Build & publish your first dApp.
Project Setup
To initiate the creation of a new React app using npx create-react-app, follow these steps:
Ensure that you have Node.js and npm (Node Package Manager) installed on your system.
Open your terminal or command prompt.
Execute the following command:
npx create-react-app my-appReplace "my-app" with your desired name for the React app. This command will establish a new directory named "my-app" and configure a basic React application structure within it.
After the process completes, navigate to the newly created directory:
cd my-appLaunch the development server:
npm startThis action will start the development server and automatically open your React app in a web browser. You can now commence building your React application by making changes to the files within the "src" directory.
Utilizing npx create-react-app presents a swift and straightforward method for initializing a new React project with all the essential configurations and dependencies, freeing you to concentrate on developing your app without concerning yourself with the initial setup.
Ethernity Cloud Runner package 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 --saveThis 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.
Ethernity Cloud Runner usage and integration
This comprehensive guide explains the seamless integration of the Ethernity Cloud Runner module into your React application, empowering developers to execute Python tasks. The following sections elaborate on the integration process:
Import Statements:
Begin by editing /src/App.js and by importing the essential modules and styles. Import
./App.cssfor styling, and the pivotal pieces from the@ethernity-cloud/runnerpackage: the defaultEthernityCloudRunnerclass plusECRunner,ECStatus, andECAddressfrom the enums entry point.These are what you use to interact with the runner, pick the enclave image, react to task status, and select the network.
Defining Code to be Executed:
The Ethernity Cloud Runner allows users to execute tasks using different programming languages and frameworks. Currently, the runner supports two main templates: Python and Node.js. Users can define the code to be executed within these templates to perform specific tasks on the Ethernity Cloud ecosystem.
Python Template:
In the Python template, users can write their code in Python programming language.
Below there is an example of Python code that returns
Node.js Template: For those who prefer JavaScript, the Node.js template offers a powerful option.
Below there is an example of Node.js code that computes the sum of two numbers:
To use either template, users need to provide the code in the corresponding programming language that defines the specific task they want to execute. As you can see, the
ecld.resultfunction is specially used inside a Ethernity Cloud Runner tasks. When executing a task, this function allows the task code to send the result back to the Ethernity Cloud ecosystem.ecld.resultis the way to return a task's result — the same call as the bareecldResult(...)(Python:ecld_result). The older ___etny_result___ still works, unchanged. It encodes any value automatically (JSON / text / base64) and can attach your dApp's persistent state to theManaging dApp State (ESR).Because there is no output console of the code that is being process, this special function plays a crucial role in ensuring that the results of executed tasks are safely recorded and sent to the user performing the task request. For our example we are using the following nodejs code:
App Function Component:
Define the
Appfunction component, which plays a pivotal role in rendering the entire application.
Execute Task Function:
Within the App function, define the executeTask function as an asynchronous function that triggers upon clicking the "Execute task" button.
Runner Initialization:
The first crucial step involves creating an instance of the EthernityCloudRunner. Initialize the runner by constructing:
Called with no arguments, the runner targets the Bloxberg testnet and uses the browser wallet (MetaMask via window.ethereum).
Selecting a network. The constructor takes the network's token contract address as its first argument (import the addresses from @ethernity-cloud/runner/enums). Ethernity Cloud supports the following networks:
Bloxberg
mainnet
8995
ECAddress.BLOXBERG.MAINNET_ADDRESS
Bloxberg
testnet
8995
ECAddress.BLOXBERG.TESTNET_ADDRESS
Polygon
mainnet
137
ECAddress.POLYGON.MAINNET_ADDRESS
Polygon Amoy
testnet
80002
ECAddress.POLYGON.TESTNET_ADDRESS
IoTeX
testnet
4690
ECAddress.IOTEX.TESTNET_ADDRESS
Ethereum Sepolia
testnet
11155111
ECAddress.SEPOLIA.TESTNET_ADDRESS
LitVM LiteForge
testnet
4441
ECAddress.LITVM.TESTNET_ADDRESS
The IoTeX, Sepolia, and LitVM testnets share a single ECLD token address, so the runner reads the chain ID from your wallet/provider to tell them apart. When you connect a browser wallet or pass a provider, this is automatic. If you drive the runner with a raw private key instead, pass the network's chain ID as the third constructor argument (and an rpcUrl in the wallet options) so the correct chain is selected:
Make sure the enclave image you pass to runner.run(...) (step 8) belongs to the same network — the ECRunner enum is keyed by network, e.g. ECRunner.IOTEX.PYNITHY_RUNNER_TESTNET for IoTeX or ECRunner.BLOXBERG.PYNITHY_RUNNER_TESTNET for Bloxberg.
Decentralized Storage Initialization:
Next, initialize the Ethernity Cloud Runner's decentralized storage by specifying the IPFS address where it will communicate with the IPFS network.
For this integration, you have multiple options to initialize the storage:
Ethernity Cloud IPFS Server (Recommended for Development):
Utilize the default IPFS address 'https://ipfs.ethernity.cloud' provided by Ethernity Cloud, which serves as an efficient option for development purposes. It ensures seamless initialization with the specified IPFS address, allowing you to focus on task execution without managing your own IPFS infrastructure.
Custom IPFS Server:
Alternatively, if you have your own IPFS server set up or prefer to use a different IPFS address, you can provide the desired IPFS address to the runner.initializeStorage(ipfsAddress) method. This option empowers you to leverage any IPFS infrastructure that suits your specific requirements.
Other Decentralized Storage Solutions:
Ethernity Cloud Runner offers the flexibility to integrate with various decentralized storage solutions beyond IPFS. While IPFS is the default and recommended option, you can explore other decentralized storage systems based on your needs and preferences.
Events subscription:
The runner is an EventTarget. As a task moves through its lifecycle it dispatches CustomEvents named by the task status, so you subscribe using the ECStatus values:
ECStatus.DEFAULT("Running") — progress updates while the task is encrypting, being submitted, matched, and processed.ECStatus.SUCCESS("Success") — the task finished and a result is available.ECStatus.ERROR("Error") — something failed.
Each event's detail carries { message, status, progress }, where progress is a human-readable phase label (one of the ECEvent values, e.g. "In Progress", "Downloading result", "Finished").
By subscribing to these three status events, developers can follow the execution phase-by-phase (via e.detail.progress) and fetch the final result with await runner.getResult() once ECStatus.SUCCESS fires.
Task Execution:
The heart of the integration is the await runner.run(...) line, which initiates task execution. The function signature is run(resources, secureLockEnclave, code, nodeAddress = '', trustedZoneEnclave):
Resources: An object describing the resources the task needs —
taskPrice(in the network's token),cpu,memory(GB),storage(GB),bandwidth,duration, andvalidators.Enclave image (
secureLockEnclave): The enclave image to execute the task, taken from the network-keyedECRunnerenum. Two templates are available per network:Python:
ECRunner.<NETWORK>.PYNITHY_RUNNER_TESTNETNode.js:
ECRunner.<NETWORK>.NODENITHY_RUNNER_TESTNETwhere
<NETWORK>matches the network you selected in step 5 (BLOXBERG,POLYGON,IOTEX,SEPOLIA,LITVM). Mainnet variants drop the_TESTNETsuffix.
Code: The code to execute as the task (preserve proper indentation for Python).
Node Address (Optional): Provide an EC node's wallet address to auto-approve the order on that node; omit it (empty string) to have the order matched and manually approved by any available node.
Manual Approval: Omitting the node address lets the network match and approve the task.
Automatic Approval: Passing a node address targets that node for a seamless, quick execution.
Rendering the Button
Final application code
Application styling
Now, navigate to the src/App.css file and proceed to enhance its content by adding the following CSS classes:
In conclusion, the above-mentioned code elegantly integrates the Ethernity Cloud Runner into your React app, enabling seamless execution of Python/Node.js code snippets while facilitating interaction with the IPFS network for efficient data storage and retrieval. As a professional developer, you can now leverage this integration to enhance your React applications with powerful decentralized task execution capabilities.
Last updated