From a24cd6899861a0d2c281dbc02f6803679254283b Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Fri, 14 Nov 2025 23:08:42 +0500 Subject: [PATCH 01/19] chore: update docs --- docs/pages/CRISP/introduction.mdx | 39 +-- docs/pages/CRISP/running-e3.mdx | 139 +++++----- docs/pages/CRISP/setup.mdx | 51 ++-- docs/pages/_meta.json | 56 ++-- docs/pages/best-practices.mdx | 65 +++++ docs/pages/building-with-enclave.mdx | 98 ++++--- docs/pages/ciphernode-operators.mdx | 240 ++++++++++++++++++ docs/pages/ciphernode-operators/_meta.json | 20 ++ .../exits-and-slashing.mdx | 52 ++++ docs/pages/ciphernode-operators/index.mdx | 48 ++++ .../pages/ciphernode-operators/operations.mdx | 106 ++++++++ .../ciphernode-operators/registration.mdx | 72 ++++++ docs/pages/ciphernode-operators/scenarios.mdx | 48 ++++ .../tickets-and-sortition.mdx | 61 +++++ docs/pages/computation-flow.mdx | 47 ++-- docs/pages/noir-circuits.mdx | 82 ++++++ docs/pages/project-template.mdx | 95 +++++++ docs/pages/quick-start.mdx | 4 +- docs/pages/sdk.mdx | 156 ++++++++++++ docs/pages/setting-up-server.mdx | 8 +- docs/pages/use-cases.mdx | 62 +++++ 21 files changed, 1340 insertions(+), 209 deletions(-) create mode 100644 docs/pages/best-practices.mdx create mode 100644 docs/pages/ciphernode-operators.mdx create mode 100644 docs/pages/ciphernode-operators/_meta.json create mode 100644 docs/pages/ciphernode-operators/exits-and-slashing.mdx create mode 100644 docs/pages/ciphernode-operators/index.mdx create mode 100644 docs/pages/ciphernode-operators/operations.mdx create mode 100644 docs/pages/ciphernode-operators/registration.mdx create mode 100644 docs/pages/ciphernode-operators/scenarios.mdx create mode 100644 docs/pages/ciphernode-operators/tickets-and-sortition.mdx create mode 100644 docs/pages/noir-circuits.mdx create mode 100644 docs/pages/project-template.mdx create mode 100644 docs/pages/sdk.mdx create mode 100644 docs/pages/use-cases.mdx diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index 0f4bbc1b49..698e937c1e 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -31,31 +31,37 @@ CRISP follows a modern Hardhat-based structure with clear separation of concerns ``` CRISP/ -|── client/ # React frontend application -|── server/ # Rust coordination server -|── program/ # RISC Zero computation program -├── contracts/ # Smart contracts (Solidity) -├── circuits/ # Noir circuits for ZK proofs -├── scripts/ # Development and utility scripts -├── enclave.config.yaml # Ciphernode configuration +├── client/ # React frontend application (Vite + @enclave-e3/sdk) +├── server/ # Rust coordination server & CLI +├── program/ # RISC Zero guest + prover control plane +├── packages/ +│ ├── crisp-contracts/ # Hardhat deployment + helpers +│ └── sdk/ # CRISP-specific TypeScript helpers +├── crates/ # Rust libraries for the CLI + services +├── circuits/ # Noir circuits + verifiers (see [Noir Circuits](/noir-circuits)) +├── scripts/ # dev.sh, setup.sh, compile_circuits.sh, etc. +├── enclave.config.yaml # Ciphernodes + aggregator config +└── docker-compose.yaml # Optional multi-node deployment ``` --- ### **Client Application** (`/client`) -The client is a React application built with TypeScript that provides a voting interface: +The client is a React application built with TypeScript that provides a voting interface and reuses +the shared [Enclave SDK](/sdk): - Wallet connection with MetaMask and other wallets - Vote encryption using WebAssembly-based FHE encryption before submission -- Noir Zero-knowledge proof generation for vote validation +- Noir zero-knowledge proof generation for vote validation - Real-time updates on voting status and results --- ### **Coordination Server** (`/server`) -The server is a Rust-based coordination service that manages the E3 lifecycle: +The server is a Rust-based coordination service that manages the E3 lifecycle and drives the same +SDK from a privileged wallet: - Listens to blockchain events and coordinates protocol progression - Collects encrypted votes from the Smart Contract @@ -65,17 +71,16 @@ The server is a Rust-based coordination service that manages the E3 lifecycle: --- -### **ZK Program** (`/program`) +### **ZK Program + Noir Circuits** (`/program`, `/circuits`) -The core computation logic written in Rust for zkVM: - -- Performs computations on encrypted votes -- Counts votes without decrypting individual ballots -- Creates proofs of correct computation +- `program/`: Rust guest code compiled to the RISC Zero zkVM image that runs the CRISP tally logic +- `circuits/`: Noir circuits + SAFE/GRECO libraries used for membership proofs and encryption checks +- `scripts/compile_circuits.sh`: compiles Noir circuits, writes verification keys, and emits the + `CRISPVerifier.sol` contract used by `packages/crisp-contracts` --- -### **Smart Contracts** (`/contracts`) +### **Smart Contracts** (`/packages/crisp-contracts`) Solidity contracts implementing the E3 program interface: diff --git a/docs/pages/CRISP/running-e3.mdx b/docs/pages/CRISP/running-e3.mdx index 64e8001183..7aa075efd4 100644 --- a/docs/pages/CRISP/running-e3.mdx +++ b/docs/pages/CRISP/running-e3.mdx @@ -18,91 +18,64 @@ complete voting round of CRISP and do the following: Please make sure you have followed the [CRISP Setup](/CRISP/setup) guide before proceeding. +enclave nodes up -v -### Start Infrastructure - -First, ensure you have the infrastructure running. If you haven't already, complete the setup: - -**Terminal 1: Start Anvil** - -```sh -anvil -``` +### Prep Once per Checkout -**Terminal 2: Start Ciphernodes** +From the repo root run the bundled setup script (it installs dependencies, builds the CLI, prepares +env files, and compiles contracts): ```sh cd examples/CRISP -enclave nodes up -v +pnpm dev:setup ``` -Make sure contracts are deployed and ciphernodes are added to the registry as described in the setup -guide. - -### Start the Client Application +You only need to re-run this when dependencies change. -**Terminal 3: Client** +### Start Everything with One Command -Navigate to the client directory and start the React application: +The CRISP workspace ships with a supervisor that launches Hardhat, deploys contracts, boots +Ciphernodes, runs the RISC Zero program server, the Rust backend, and the React client. Start it in +the example root: ```sh -cd examples/CRISP/client -pnpm dev +pnpm dev:up ``` -The client application will start on `http://localhost:3000`. +Behind the scenes `scripts/dev.sh` calls `scripts/dev_services.sh`, which: -### Start the Server Application +- Spawns a Hardhat chain on `http://localhost:8545` +- Deploys contracts and registers five Ciphernodes against the local registry +- Runs `enclave program start --dev true` so proving happens instantly while developing +- Launches the Rust server with `cargo run --bin server` +- Starts the React client via `pnpm dev-static` -**Terminal 4: Server** +Keep this terminal open; logs from every service are multiplexed with +`pnpm concurrently`. -Navigate to the server directory and start the backend server: +### (Optional) Build Once for Production -```sh -cd examples/CRISP/server -cargo run --bin server -``` - -The server will start and begin listening for blockchain events. - -### Start the Program Server - -**Terminal 5: Program** - -Navigate to the program directory and start the program server: +If you want release binaries or a static client before running, execute: ```sh -cd examples/CRISP/ -enclave program start +pnpm dev:build ``` -This runs the RISC Zero program server that handles secure computations. - -If you would like to run the program server in dev mode, you can run the following command: - -```sh -cd examples/CRISP/ -enclave program start --dev true -``` - -In this case, Risc0 will not be used to generate proofs, and instead these will be mocked. +That pipeline runs `cargo build --locked`, compiles the contracts, and builds the client bundle. ### Initialize a New Voting Round -**Terminal 6: CLI** - -Navigate to the server directory and start the CLI: +Open a new terminal and launch the CLI from the example root: ```sh -cd examples/CRISP/server -cargo run --bin cli +pnpm cli ``` -Follow these steps in the CLI: +In the interactive menu: -1. Select `CRISP: Voting Protocol (ETH)` from the menu -2. Choose `Initialize new E3 round` to start a new voting round +1. Select `CRISP: Voting Protocol (ETH)` +2. Choose `Initialize new E3 round` You should see output similar to: @@ -115,25 +88,54 @@ You should see output similar to: ### Set Up MetaMask -To interact with the client application, you need to configure MetaMask: +Whether you used `pnpm dev:up` or the manual flow below, you will interact with the Hardhat chain +running at `http://localhost:8545` (chain ID `31337`). Configure MetaMask once: -1. Open MetaMask in your browser -2. Add the Anvil private key to your wallet: +1. Import the Hardhat/Anvil deployer key so you have funds available: ``` 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` -3. Connect to the local Anvil network: - - Network Name: Anvil Local - - RPC URL: `http://localhost:8545` - - Chain ID: `31337` - - Currency Symbol: `ETH` +2. Add a custom network pointing to `http://localhost:8545` with symbol `ETH` and chain ID `31337`. +3. Connect your wallet to `http://localhost:3000` when the client asks. ### Submit Votes via Web Interface -1. Navigate to `http://localhost:3000` in your browser -2. Connect your MetaMask wallet -3. You should see the active voting round -4. Submit your vote by selecting your choice and confirming the transaction +1. Navigate to `http://localhost:3000` (started by `pnpm dev:up`) +2. Connect your MetaMask wallet when prompted +3. You should see the active voting round seeded by the CLI request +4. Cast a vote, approve the transaction, and wait for the confirmation toast + +### Manual Control (Optional) + +If you prefer to run each process in its own terminal (or need to customize flags), replicate what +`pnpm dev:up` does under the hood: + +1. **Hardhat chain + deploy contracts** + ```sh + pnpm -C packages/crisp-contracts hardhat node + # in another terminal + ./scripts/crisp_deploy.sh + ``` +2. **Ciphernodes & wallets** + ```sh + ./scripts/dev_cipher.sh ./.enclave/ready + ``` + This script wipes previous `.enclave` state, installs dev wallets, starts `enclave nodes up -v`, + and waits until all nodes are registered. +3. **Program server** + ```sh + ./scripts/dev_program.sh # add --dev true inside to skip proofs in dev + ``` +4. **Rust server** + ```sh + wait-on tcp:13151 && ./scripts/dev_server.sh + ``` +5. **React client** + ```sh + wait-on tcp:4000 && wait-on file:./.enclave/ready && ./scripts/dev_client.sh + ``` + +You can also let `./scripts/dev_services.sh` orchestrate steps 2–5 once Hardhat is up. ### Monitor the Process @@ -194,7 +196,8 @@ The CRISP voting process involves several key steps: - **Ensure all terminals remain open** during the voting process - **MetaMask connection issues**: Check that you're connected to the correct network (Chain ID: 31337) -- **Transaction failures**: Verify you have sufficient ETH balance from the Anvil faucet +- **Transaction failures**: Verify you have sufficient ETH balance from the Hardhat faucet (the + account with the imported deployer key starts funded) - **Server errors**: Monitor the server logs for detailed error messages - **Ciphernode issues**: Ensure all ciphernode processes are running and connected diff --git a/docs/pages/CRISP/setup.mdx b/docs/pages/CRISP/setup.mdx index 7d25f53d36..ec7059bb4d 100644 --- a/docs/pages/CRISP/setup.mdx +++ b/docs/pages/CRISP/setup.mdx @@ -27,7 +27,8 @@ Before getting started, ensure you have installed: - [RiscZero](https://dev.risczero.com/api/zkvm/install) - [NodeJS](https://nodejs.org/en/download) - [pnpm](https://pnpm.io) -- [Metamask](https://metamask.io) +- [MetaMask](https://metamask.io) +- [Noir toolchain (`nargo`, `bb`)](https://noir-lang.org/docs/getting_started/installation) — required when you recompile the circuits ### Install Node @@ -48,44 +49,32 @@ You can add Metamask as extension to your browser following the official You need to install Rust and Foundry first. After installation, restart your terminal. ```sh -# Install Rust -curl https://sh.rustup.rs -sSf | sh -# Install Foundry -curl -L https://foundry.paradigm.xyz | bash -``` - -### Install RISC Zero Toolchain - -Next, install `rzup` for the `cargo-risczero` toolchain. +```bash +# Prepare the workspace (installs deps, builds server binaries, copies .env files, ensures enclave CLI) +VITE_E3_PROGRAM_ADDRESS=0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44 # Default E3 program address from anvil -```sh -# Install rzup -curl -L https://risczero.com/install | bash +# Launch Hardhat, deploy contracts, start ciphernodes, the program server, coordination server, and UI +pnpm dev:up -# Install RISC Zero toolchain -rzup install cargo-risczero -``` +# Rebuild client/server/crates without re-running setup each time +pnpm dev:build -Verify the installation was successful by running: +# (Optional) Recompile Noir circuits + verifiers +pnpm compile:circuit -```sh -cargo risczero --version +# Open the interactive CLI to start rounds +pnpm cli ``` -At this point, you should have all the tools required to develop and deploy an application with -[RISC Zero](https://www.risczero.com). - -## Environment - -You need to setup your environment variables for `client/` and `server/`. Just copy and paste the -`.env.default` as `.env` and overwrite with your values the following variables (you can leave the -others initialized with the default values). +`dev:up` runs `scripts/dev.sh`, which in turn: -### Client - -```bash -VITE_E3_PROGRAM_ADDRESS=0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44 # Default E3 program address from anvil +- Starts the Hardhat node (`packages/crisp-contracts`) +- Deploys the full contract stack (Enclave, CRISPProgram, validators, registries) +- Boots ciphernodes using the provided `enclave.config.yaml` +- Launches the program server (RISC Zero) +- Starts the coordination server (Rust) and waits for it to expose port `4000` +- Starts the client once the server and nodes are ready VITE_SEMAPHORE_ADDRESS=0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE ``` diff --git a/docs/pages/_meta.json b/docs/pages/_meta.json index e694f486b8..b47d1ca34e 100644 --- a/docs/pages/_meta.json +++ b/docs/pages/_meta.json @@ -3,9 +3,9 @@ "display": "hidden", "title": "Home" }, - "-- Documentation": { + "-- Overview": { "type": "separator", - "title": "Documentation" + "title": "Overview" }, "introduction": { "title": "Introduction" @@ -19,12 +19,18 @@ "computation-flow": { "title": "E3 Computation Flow" }, + "use-cases": { + "title": "Use Cases" + }, "building-with-enclave": { "title": "Building with Enclave" }, - "-- TUTORIAL": { + "best-practices": { + "title": "Best Practices" + }, + "-- Getting Started": { "type": "separator", - "title": "Tutorial" + "title": "Getting Started" }, "installation": { "title": "Installation" @@ -35,41 +41,61 @@ "hello-world-tutorial": { "title": "Hello World" }, - "-- BUILD AN E3": { + "-- Tooling": { + "type": "separator", + "title": "Tooling" + }, + "project-template": { + "title": "Project Template" + }, + "sdk": { + "title": "Enclave SDK" + }, + "setting-up-server": { + "title": "Setting Up the Server" + }, + "noir-circuits": { + "title": "Noir Circuits" + }, + "-- Build an E3": { "type": "separator", - "title": "BUILD AN E3 Program" + "title": "Build an E3 Program" }, "getting-started": { "title": "Getting Started" }, - "compute-provider": { - "title": "Compute Provider Setup" - }, "write-secure-program": { "title": "Writing the Secure Process" }, "write-e3-contract": { "title": "Writing the E3 Program Contract" }, - "setting-up-server": { - "title": "Setting Up the Server" + "compute-provider": { + "title": "Compute Provider Setup" }, "putting-it-together": { "title": "Putting It All Together" }, + "-- Operations": { + "type": "separator", + "title": "Operations" + }, + "ciphernode-operators": { + "title": "Ciphernode Operators" + }, "build-e3": { "display": "hidden" }, - "-- USE CASES": { + "-- Examples": { "type": "separator", - "title": "USE CASES" + "title": "Examples" }, "CRISP": { "title": "CRISP" }, - "-- WHITE PAPER": { + "-- Reference": { "type": "separator", - "title": "WHITE PAPER" + "title": "Reference" }, "whitepaper": { "title": "White Paper" diff --git a/docs/pages/best-practices.mdx b/docs/pages/best-practices.mdx new file mode 100644 index 0000000000..1b1c91f7a0 --- /dev/null +++ b/docs/pages/best-practices.mdx @@ -0,0 +1,65 @@ +--- +title: 'Best Practices' +--- + +# Design & Operations Best Practices + +Competitor docs such as Fhenix's "Key Considerations" and Ritual's architecture primers emphasize +clear guardrails for confidential compute. This guide distills the equivalent playbook for Enclave. + +## Parameter Strategy + +- **Thresholds**: Choose `threshold = [t, n]` so that `t` withstands your adversary model while `n` + matches available Ciphernodes. Higher thresholds improve collusion resistance but increase fees. +- **Timing Windows**: Ensure `startWindow` leaves enough time for committee selection (a few blocks) + and `duration` matches the longest credible compute time plus buffer. +- **Custom Params**: Use `customParams` in `E3RequestParams` to tag jurisdiction, use case, or feature + toggles without redeploying contracts. + +## Input Validation + +- **Push logic to validators**: Implement `IInputValidator.validate` so ZK proofs and policy checks + happen before the Secure Process. This mirrors how CoFHE tutorials offload range proofs from the + heavy computation path. +- **Replay protection**: Include round identifiers or nullifiers inside inputs before you hash them + into the Lean IMT. +- **Access control**: Gate inputs via registries (e.g., DAO membership) or staking requirements to + keep spam out of the queue. + +## Secure Process & Compute Providers + +- **Determinism**: Reconstruct the on-chain Merkle root inside the Secure Process, then assert + equality prior to any heavy math. +- **Proof hooks**: When using RISC Zero or other verifiable CPs, keep witness blobs small and reserve + `computeProviderParams` for runtime toggles (precision, chunk size, etc.). +- **Failover**: Decide how your app reacts if `CiphertextOutputPublished` never arrives—e.g., allow a + guardian to cancel the round and refund deposits. + +## Key Material & Ciphernodes + +- **Key hygiene**: `dev:setup` wipes `.enclave` directories for you; mimic that behavior in production + by rotating committee keys when nodes churn. +- **Monitoring**: Subscribe to `E3Activated` and `PlaintextOutputPublished` events to ensure the CiCo + publishes keys and decryptions on schedule. +- **Operator docs**: Keep the [Ciphernode Operators](/ciphernode-operators) runbooks close to your app + documentation so node providers can mirror your expectations. + +## Observability & Tooling + +- **Structured logs**: Adopt the logging schema from the CRISP server (JSON with `e3_id` and phase) + so you can stitch together end-to-end traces. +- **Synthetic tests**: Reuse `pnpm dev:up` + Playwright to run rehearsal rounds on CI before shipping + new circuits or SDK releases. +- **Dashboarding**: Track request fees, committee saturation, and mean time from `request` to + `PlaintextOutputPublished` just like Ritual exposes node specialization metrics. + +## Deployment Checklist + +1. Run `pnpm dev:build` to preflight the entire stack. +2. Execute integration tests that cover `request → publishInput → publishCiphertextOutput` with mock + proofs. +3. Verify wallet funding for any automation (enclave CLI, Hardhat deployers). +4. Update onboarding docs (MetaMask, scripts) when RPC URLs or ports change. +5. Publish a postmortem template so incidents have consistent follow-up. + +Pair these practices with the [Use Cases](/use-cases) catalog to craft predictable launch plans. diff --git a/docs/pages/building-with-enclave.mdx b/docs/pages/building-with-enclave.mdx index ac40182aad..d1c1c6c681 100644 --- a/docs/pages/building-with-enclave.mdx +++ b/docs/pages/building-with-enclave.mdx @@ -41,24 +41,21 @@ contract Enclave { ### Request Flow -1. Users submits onchain request - -```solidity -function request( - address filter, - uint32[2] calldata threshold, - uint256[2] calldata startWindow, - uint256 duration, - IE3Program e3Program, - bytes memory e3ProgramParams, - bytes memory computeProviderParams -) external -``` - -2. Contract validates request parameters -3. E3 Program contract is set and used to get the Encryption scheme. -4. Request is submitted to the ciphernodeRegistry for committee selection. -5. `E3Requested` event is emitted +1. Users submit `E3RequestParams` containing thresholds, timing windows, program references, and + optional custom params. + + ```solidity + function request( + E3RequestParams calldata requestParams + ) external returns (uint256 e3Id, E3 memory e3); + ``` + +2. Contract validates the struct, estimates the fee, and stores an `E3` record seeded with a random + value derived from block entropy. +3. The E3 program's `validate` hook returns the encryption scheme ID and input validator contract, + which are persisted on the `E3` struct. +4. Committee selection is delegated to the `ciphernodeRegistry` via `requestCommittee`. +5. `E3Requested(e3Id, e3, e3Program)` is emitted with the full configuration payload for watchers. ## Committee and Ciphernode Management @@ -68,6 +65,8 @@ function request( from the global pool of available Ciphernodes. - Selected nodes coordinate to produce a shared public key with the requested threshold. - The public key is published to the Ciphernode Registry smart contract. +- For bonding, ticket economics, CLI commands, and operational responsibilities, see the + [Ciphernode Operators guide](/ciphernode-operators). ## E3 Activation @@ -94,7 +93,7 @@ function publishInput( ) external ``` -Inputs are accumulated incrementally into a Merkle tree. This allows you to: +Inputs are accumulated incrementally into a Merkle tree (LeanIMT). This allows you to: 1. Use the published Merkle root as part of your E3 Program's Secure Process to ensure all published inputs are processed by the Compute Provider. @@ -139,11 +138,22 @@ to the E3's public key. It is also recommended to bundle in proofs to validate: ```solidity event E3Requested(uint256 indexed e3Id, address indexed requester, address e3ProgramAddress); -event InputSubmitted(uint256 indexed e3Id, address indexed sender, bytes32 inputHash); - -event CiphertextOutputPublished(uint256 indexed e3Id, bytes32 ciphertextHash); - -event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintext); +event InputPublished( + uint256 indexed e3Id, + bytes data, + uint256 inputHash, + uint256 index +); + +event CiphertextOutputPublished( + uint256 indexed e3Id, + bytes ciphertextOutput +); + +event PlaintextOutputPublished( + uint256 indexed e3Id, + bytes plaintextOutput +); ``` ### Result Publication Flow @@ -161,19 +171,21 @@ event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintext); ```javascript const enclaveContract = new ethers.Contract(enclaveAddress, enclaveAbi, signer) -const tx = await enclaveContract.request( - filterAddress, - [thresholdMin, thresholdMax], - [startWindowStart, startWindowEnd], - duration, - e3ProgramAddress, +const requestParams = { + threshold: [3, 5], + startWindow: [startWindowStart, startWindowEnd], + duration: 3600, + e3Program: e3ProgramAddress, e3ProgramParams, computeProviderParams, - { value: computationFee }, -) + customParams: '0x', +} +const tx = await enclaveContract.request(requestParams) const receipt = await tx.wait() -const e3Id = receipt.events.find((e) => e.event === 'E3Requested').args.e3Id +const e3Id = receipt.logs + .map((log) => enclaveContract.interface.parseLog(log)) + .find((parsed) => parsed?.name === 'E3Requested')?.args?.e3Id ``` ### Monitoring Results @@ -219,21 +231,5 @@ the finality of the outcome and to appropriately handle re-orgs. ## Best Practices -1. **Request Management** - - Set appropriate thresholds - - Choose realistic time windows - -2. **Input Handling** - - Encrypt inputs properly - - Include necessary ZKPs - - Submit within time windows - -3. **Result Processing** - - Listen for all relevant events - - Implement timeout handling - - Verify result integrity - -4. **Error Handling** - - Handle contract reverts - - Implement retry logic - - Log errors appropriately +See the dedicated [Best Practices](/best-practices) guide for updated operational playbooks covering +parameter selection, validator design, compute provider trust, and observability. diff --git a/docs/pages/ciphernode-operators.mdx b/docs/pages/ciphernode-operators.mdx new file mode 100644 index 0000000000..9e2b1bee40 --- /dev/null +++ b/docs/pages/ciphernode-operators.mdx @@ -0,0 +1,240 @@ +--- +title: 'Ciphernode Operators' +description: 'How to bond, configure, and operate Ciphernodes on the Enclave network' +--- + +# Ciphernode Operators + +Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key shares, +and keep the Enclave network alive. This guide walks through the economic requirements, on-chain +lifecycle, CLI workflow, networking expectations, and production deployment patterns for running a +Ciphernode. + +## Role overview + +Ciphernodes are expected to: + +- Maintain an online QUIC/libp2p endpoint and participate in the event bus +- Bond license collateral (ENCL) and hold tickets (stablecoin-backed ETK) to earn committee slots +- Submit tickets on-chain during sortition and publish committee key material +- Produce decryption shares for every E3 the node was selected to serve +- Remain slash-aware: missed duties or malicious behavior can lose both ticket collateral and + license bonds + +The protocol is chain-agnostic. Each configured chain entry in `enclave.config.yaml` can track a +different Enclave + registry deployment, and each Ciphernode instance manages the lifecycle for its +configured chains simultaneously. + +## Contract references + +| Contract | Sepolia address | Notes | +| --- | --- | --- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | +| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | + +> ⚠️ Always confirm the latest addresses in +> `packages/enclave-contracts/deployed_contracts.json` or your deployment output before funding a +> node. Addresses differ per network. + +## Economics & staking + +BondingRegistry constants on Sepolia: + +- **Ticket price**: `10_000_000` base units (10 USDC per ticket) +- **License bond requirement**: `100 ENCL` +- **Active license floor**: 80% of the required bond must remain bonded +- **Minimum ticket balance**: 1 ticket (10 USDC) +- **Exit delay**: `604_800 s` (7 days) + +Ticket balances are represented by the non-transferable `EnclaveTicketToken`. To mint tickets: + +1. Acquire the underlying stablecoin (`MockUSDC` on Sepolia) +2. Approve the BondingRegistry to pull funds +3. Call `addTicketBalance(amount)` + +The number of usable tickets is: + +``` +availableTickets = floor(ticketTokenBalance / ticketPrice) +``` + +Tickets control a node's probability of selection via sortition. + +License bonds are denominated in ENCL. Operators must keep at least 80% of `licenseRequiredBond` +bonded to remain `active`. + +SlashingManager penalties can remove both ticket balances and license bonds, and may ban an operator. +Appeals are time-bound by the policy's `appealWindow`. + +Rewards (any ERC20) are pushed by the configured `rewardDistributor` through +`BondingRegistry.distributeRewards`. Only registered operators receive payouts. + +## Lifecycle checklist + +1. **Acquire collateral** + - ENCL for license bonding + - USDC (or the configured fee token) for tickets +2. **Bond the license** + ```bash + cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +3. **Register as a ciphernode** + ```bash + cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +4. **Deposit tickets** + ```bash + cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + ``` +5. **Verify status** + - `BondingRegistry.isRegistered(address)` must be `true` + - `BondingRegistry.isActive(address)` turns `true` after ticket + license thresholds +6. **Stay online** + - Run the CLI (see below) so your node listens for events and participates in sortition +7. **Handle exits** + - Call `deregisterOperator(siblingProof)` to begin exit + - Wait 7 days, then `claimExits(maxTickets, maxLicense)` to withdraw + +> ℹ️ The sibling proof passed to `deregisterOperator` is the path needed to remove the node from the +> registry IMT. Capture it from the Merkle proof emitted in `CiphernodeAdded` events or by querying +> the registry before exit. + +## CLI workflow + +The `enclave` CLI wraps node orchestration, credentials, and repository tooling. + +### Initialize configuration + +```bash +enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS +``` + +This creates `~/.config/enclave/config.yaml` (or the path you pass with `--config`). Most operators +instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass it +with `--config /path/to/config.yaml` on every command. + +### Manage credentials + +| Secret | Command | Notes | +| --- | --- | --- | +| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | +| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | +| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for aggregators or if the node submits committee txs | + +The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config sets +those flags. + +### Run nodes + +```bash +enclave nodes up --detach # start every node profile defined in config +enclave nodes ps # list process status +enclave nodes status cn1 # query single node +enclave nodes restart cn1 # restart one node +enclave nodes down # stop everything +enclave nodes purge # wipe local RocksDB + secrets (irreversible) +``` + +To run a single node profile outside the supervisor, use `enclave start --config /path/to/config.yaml`. +Pass peers with `--peer /dns4/example.com/udp/9091/quic-v1` to override the config at runtime. + +## Networking & configuration + +Every node section in `enclave.config.yaml` defines how the CLI spawns that instance: + +```yaml +node: + address: "0x7099…79C8" + quic_port: 9201 + peers: + - "/dns4/aggregator1.example.com/udp/9094/quic-v1" + autonetkey: true + autopassword: true +chains: + - name: sepolia + rpc_url: "wss://ethereum-sepolia.publicnode.com" + contracts: + enclave: + address: "0x1E8B…FAa6" + deploy_block: 9615399 + ciphernode_registry: + address: "0x11F6…0b1C7" + bonding_registry: + address: "0x5636…406E3" + fee_token: + address: "0xB58B…4De0" +``` + +Notes: + +- `peers` expects libp2p multiaddrs (`/dns4//udp//quic-v1`). Provide at least one + bootstrap peer. For production, run a static bootstrap service (planned: `bootstrap.enclave.gg`). +- `quic_port` must match firewall rules; expose UDP. +- Each node can override `data_dir` and `config_dir` if the defaults under `~/.local/share/enclave` + and `~/.config/enclave` are unsuitable. +- Set `role.type: aggregator` for nodes tasked with publishing plaintext outputs. + +## Deployment manifests & secrets + +The repository ships a Docker Swarm example under `deploy/` that you can adapt: + +- `cn*.yaml` / `agg.yaml`: minimal configs templated with `${ADDRESS}` and `${RPC_URL}` +- `docker-compose.yml`: runs multiple Ciphernodes plus an aggregator with shared overlay network +- Secrets files (`cn1.secrets.json`, etc.) follow: + ```json + { + "password": "changeme", + "private_key": "0x…", + "network_private_key": "0x…" + } + ``` +- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands (`enclave password set`, + `enclave net keypair set`, `enclave wallet set`), then execs `enclave start -v` + +This pattern is also useful for Kubernetes Jobs or systemd units: mount a config, mount an encrypted +secret bundle, run the entrypoint. + +## Sortition & operations + +- Committee requests originate from the Enclave contract. The registry snapshots ticket balances at + `requestBlock - 1`, so topping up tickets after a request starts will not help that round. +- Submission window defaults to 10 seconds on Sepolia (`sortitionSubmissionWindow`). Nodes must call + `submitTicket(e3Id, ticketNumber)` before it expires. The CLI handles this automatically using the + event bus. +- `finalizeCommittee` can be called by anyone once the window closes and at least `threshold_m` + submissions exist. After finalization, nodes publish key shares, aggregate the public key, and + submit it via `publishCommittee`. +- If a node is offline during submission, it misses the round but remains active provided its stake + satisfies the requirements. Repeated failures risk slashing. + +## Rewards, slashing, and exits + +- **Rewards**: Watch for `RewardDistributed` (BondingRegistry) logs. Ensure the operator wallet can + receive the reward token. +- **Slashing**: `SlashingManager` proposals reference reason codes. Operators should monitor + `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is not + required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. +- **Exits**: `deregisterOperator()` burns tickets immediately and queues withdrawals. The exit queue + tracks amounts per operator; call `pendingExits(address)` or `previewClaimable(address)` to view + status. + +## Troubleshooting + +| Symptom | Checks | +| --- | --- | +| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | +| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | +| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | +| Sortition submissions fail | Node must be registered + active *before* `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | +| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | +| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | + +Maintaining high uptime, redundant networking, and alerting on contract events are the best ways to +protect your stake. Use the CLI supervisors plus infrastructure automation to ensure secrets and +configs stay consistent across restarts. diff --git a/docs/pages/ciphernode-operators/_meta.json b/docs/pages/ciphernode-operators/_meta.json new file mode 100644 index 0000000000..1e75cb4c83 --- /dev/null +++ b/docs/pages/ciphernode-operators/_meta.json @@ -0,0 +1,20 @@ +{ + "index": { + "title": "Overview" + }, + "registration": { + "title": "Registration & Licensing" + }, + "tickets-and-sortition": { + "title": "Tickets & Sortition" + }, + "operations": { + "title": "Operations & Responsibilities" + }, + "exits-and-slashing": { + "title": "Exits, Rewards & Slashing" + }, + "scenarios": { + "title": "Runbook Scenarios" + } +} diff --git a/docs/pages/ciphernode-operators/exits-and-slashing.mdx b/docs/pages/ciphernode-operators/exits-and-slashing.mdx new file mode 100644 index 0000000000..8a615d73f6 --- /dev/null +++ b/docs/pages/ciphernode-operators/exits-and-slashing.mdx @@ -0,0 +1,52 @@ +--- +title: 'Exits, Rewards & Slashing' +--- + +# Exits, Rewards & Slashing + +Understand how to collect rewards, respond to slashing proposals, and exit the registry safely. + +## Rewards + +- Distributed via `BondingRegistry.distributeRewards` (any ERC20) +- Watch for `RewardsDistributed(e3Id, nodes, amounts)` events +- Ensure the operator wallet remains funded to claim rewards if additional gas is required + +## Slashing lifecycle + +1. `SlashingManager` emits `SlashProposed` referencing a policy + reason code. +2. Operators inspect the evidence (if any) and the associated `SlashPolicy` parameters. +3. File an appeal with `fileAppeal(e3Id, reason, evidenceURI)` before `appealWindow` expires, if the + policy allows it. +4. Once finalized, penalties may burn tickets, confiscate license bonds, and optionally ban the + operator. + +Stay alert for: + +- `appealWindow` values per policy (some reasons skip appeals entirely) +- `updateBanStatus` (governance must lift bans before re-registration) + +## Exit process + +1. Call `deregisterOperator(bytes32[] calldata siblingProof)` + - The proof removes the operator from the registry's incremental Merkle tree (IMT) + - Capture it via the CLI logs, `CiphernodeAdded` events, or by querying the registry +2. Tickets burn immediately; license bonds enter the exit queue with an unlock timestamp +3. Wait for the configured delay (`exitDelay`, 7 days on Sepolia) +4. Claim funds with `claimExits(uint256 maxTickets, uint256 maxLicense)` + - Use `pendingExits(address)` or `previewClaimable(address)` to check readiness + +## Health checklist + +| Symptom | Actions | +| --- | --- | +| `ExitNotReady` on `claimExits` | Confirm `block.timestamp` passed `exitUnlocksAt` and delay. Call `previewClaimable`. | +| Slashing appeal rejected immediately | Policy likely disables appeals. Review policy metadata. | +| `isActive` toggles false unexpectedly | Check ticket balance (>= 1) and verify bonded ENCL >= 80% requirement. | +| Missed reward payouts | Ensure registry still lists the operator, RPC did not drop events, and reward token address is supported. | + +## Post-exit + +- Securely wipe local secrets (`enclave nodes purge` and delete keystores) +- Revoke RPC credentials and firewall openings +- Document the exit reason for future audits or compliance diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx new file mode 100644 index 0000000000..4aeae39f78 --- /dev/null +++ b/docs/pages/ciphernode-operators/index.mdx @@ -0,0 +1,48 @@ +--- +title: 'Ciphernode Operators' +description: 'Role overview, prerequisites, and quick links for node operators' +--- + +# Ciphernode Operators + +Ciphernodes decrypt committee outputs, publish threshold key shares, and keep the Enclave request +pipeline moving. This section organizes everything operators need—from bonding requirements to exit +procedures—into focused guides. + +## Role overview + +Operators are expected to: + +- Maintain a QUIC/libp2p endpoint that stays reachable 24/7 +- Bond license collateral (ENCL) and hold ticket balances (ETK) to remain eligible for committees +- Stay synced with the event bus so sortition submissions and key shares happen on time +- Produce decryption shares for every E3 assigned to their committee +- Monitor slashing proposals, appeals, and rewards distribution + +Each node profile in `enclave.config.yaml` can point to a different network (mainnet, testnet, or +local dev). The CLI supervises all configured chains concurrently. + +## Contract references + +| Contract | Sepolia address | Notes | +| --- | --- | --- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration + committees | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Manages license bonds + tickets | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash & ban workflow | +| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | + +> ⚠️ Confirm addresses in `packages/enclave-contracts/deployed_contracts.json` or your deployment +> output before funding a node. Values differ per network. + +## Section map + +- [Registration & Licensing](./registration) — economic requirements, bonding steps, CLI commands +- [Tickets & Sortition](./tickets-and-sortition) — how ETK balances influence committee selection +- [Operations & Responsibilities](./operations) — CLI workflow, networking, deployment manifests +- [Exits, Rewards & Slashing](./exits-and-slashing) — life after registration, penalties, exits +- [Runbook Scenarios](./scenarios) — ready-made playbooks for common situations + +Use these pages sequentially when onboarding a new operator or jump to the topic you need. diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx new file mode 100644 index 0000000000..ec30b16a63 --- /dev/null +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -0,0 +1,106 @@ +--- +title: 'Operations & Responsibilities' +--- + +# Operations & Responsibilities + +Staying online matters as much as bonding. Use this checklist to manage daily duties, networking, +and deployment automation. + +## Daily responsibilities + +- Watch `enclave nodes ps` and contract events for liveness +- Keep RPC endpoints funded and redundant. +- Rotate secrets and backups on a defined cadence. +- Capture logs for sortition submissions, key publication, and decryption shares. + +## CLI workflow + +```bash +# Start all nodes defined in config +enclave nodes up --detach + +# Check status +enclave nodes ps + +# Inspect a specific node +enclave nodes status cn1 + +# Restart a node +enclave nodes restart cn1 + +# Stop everything +enclave nodes down + +# Wipe state (irreversible) +enclave nodes purge +``` + +To run a single node profile manually: + +```bash +enclave start --config /path/to/enclave.config.yaml --peer /dns4/bootstrap.enclave.gg/udp/9091/quic-v1 +``` + +Flags such as `--autowallet` and `--autonetkey` will prompt-less configure secrets when the config +contains `autowallet: true` and siblings. + +## Configuration reference + +```yaml +node: + address: "0x7099…79C8" + quic_port: 9201 + peers: + - "/dns4/aggregator1.example.com/udp/9094/quic-v1" + autonetkey: true + autopassword: true + role: + type: aggregator +chains: + - name: sepolia + rpc_url: "wss://ethereum-sepolia.publicnode.com" + contracts: + enclave: + address: "0x1E8B…FAa6" + deploy_block: 9615399 + ciphernode_registry: + address: "0x11F6…0b1C7" + bonding_registry: + address: "0x5636…406E3" + fee_token: + address: "0xB58B…4De0" +``` + +Key notes: + +- Provide at least one bootstrap `peer`. Operate your own static peer for redundancy. +- Open `quic_port` over UDP in firewalls and security groups. +- Override `data_dir` / `config_dir` if running under non-standard users or containers. + +## Deployment manifests & secrets + +The `deploy/` directory includes a Docker Swarm example: + +- `cn*.yaml` and `agg.yaml` template addresses and RPC URLs +- `docker-compose.yml` runs multiple Ciphernodes plus an aggregator +- Secret bundles follow: + +```json +{ + "password": "changeme", + "private_key": "0x…", + "network_private_key": "0x…" +} +``` + +`ciphernode-entrypoint.sh` loads the config, injects secrets via `enclave password/net keypair/wallet`, +then runs `enclave start -v`. Reuse this pattern for Kubernetes Jobs, Nomad, or systemd units. + +## Monitoring & alerting + +- Subscribe to `PlaintextOutputPublished`, `CiphertextOutputPublished`, and `E3Activated` to ensure + duties progress. +- Track CLI logs for `sortition::submitted`, `decryption::share_published`, and errors. +- Export Prometheus metrics from your infrastructure layer (CPU, bandwidth, disk) since the CLI + currently logs to stdout. diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx new file mode 100644 index 0000000000..86970b518f --- /dev/null +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -0,0 +1,72 @@ +--- +title: 'Registration & Licensing' +--- + +# Registration & Licensing + +This guide covers everything required to become an active Ciphernode: collateral, bonding, +registration transactions, and config secrets. + +## Economic requirements + +Sepolia defaults (check `BondingRegistry` on your network): + +- **Ticket price**: `10_000_000` base units (10 USDC per ticket) +- **License bond requirement**: `100 ENCL` +- **Active license floor**: 80% of the required bond must remain locked +- **Minimum ticket balance**: 1 ticket (10 USDC) +- **Exit delay**: `604_800 s` (7 days) + +Tickets live inside the non-transferable `EnclaveTicketToken`. Mint them by depositing the underlying +stablecoin (MockUSDC on Sepolia) via `BondingRegistry.addTicketBalance`. The usable ticket count is: + + +`availableTickets = floor(ticketTokenBalance / ticketPrice)` + +License bonds are denominated in ENCL. Falling below 80% of `licenseRequiredBond` moves the operator +back to `inactive` even if tickets remain. + +## CLI prerequisites + +Before bonding, prepare local secrets: + +```bash +# Set up config (or pass --config later) +enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS + +# Store secrets (optional if using automation) +enclave password set --password "$PASSWORD" +enclave net keypair generate +enclave wallet set --private-key $OPERATOR_KEY +``` + +These commands populate `~/.config/enclave` and `~/.local/share/enclave`. For containerized +deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). + +## Lifecycle checklist + +1. **Acquire collateral** + - ENCL for license bonds + - USDC (or the configured fee token) for tickets +2. **Bond the license** + ```bash + cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +3. **Register the operator** + ```bash + cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +4. **Deposit tickets** + ```bash + cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + ``` +5. **Verify status** + - `BondingRegistry.isRegistered(address)` returns `true` + - `BondingRegistry.isActive(address)` flips `true` once bond + ticket floors are met +6. **Snapshot config for production** + - Commit `enclave.config.yaml` alongside deployment manifests + - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely + +> ℹ️ The CLI supports multiple named wallets. Use `enclave wallet list` to confirm the correct signer +> is active before running bonding transactions. diff --git a/docs/pages/ciphernode-operators/scenarios.mdx b/docs/pages/ciphernode-operators/scenarios.mdx new file mode 100644 index 0000000000..986a40f704 --- /dev/null +++ b/docs/pages/ciphernode-operators/scenarios.mdx @@ -0,0 +1,48 @@ +--- +title: 'Runbook Scenarios' +--- + +# Runbook Scenarios + +Borrowed from incident playbooks across Ritual/Fhenix-style docs, these scenarios show how to apply +Enclave operator procedures under real conditions. + +## Scenario 1 — New operator onboarding + +1. Follow [Registration & Licensing](./registration) to bond ENCL and mint tickets. +2. Use `enclave config-set` with production RPC URLs and bootstrap peers. +3. Dry-run `enclave nodes up` against Sepolia before pointing at mainnet. +4. Set alerts for `isActive` changes and missed sortition submissions. + +## Scenario 2 — Ticket rebalance before a major request + +1. Check `BondingRegistry.ticketPrice()` and current balances. +2. Approve + add tickets at least one block before the anticipated request. +3. Verify snapshots with `bondingRegistry.availableTickets(operator)`. +4. Confirm the CLI logs show `sortition::submitted` for the new ticket numbers. + +## Scenario 3 — Handling a slashing proposal + +1. Fetch the policy via `SlashingManager.reasonPolicies(reason)`. +2. Gather logs around the alleged offense (sortition miss, share mismatch, etc.). +3. File `fileAppeal` if the policy's `requiresProof` is false and `appealWindow > 0`. +4. Increase monitoring frequency to avoid cascading penalties. + +## Scenario 4 — Planned maintenance / temporary exit + +1. Stop nodes gracefully with `enclave nodes down`. +2. If downtime > exit delay, call `deregisterOperator` and reclaim collateral later. +3. Otherwise, keep tickets + license bonded but announce maintenance to aggregators so committee + planners know to expect fewer submissions. +4. After maintenance, double-check config secrets and run `enclave nodes up`. + +## Scenario 5 — Expanding to multiple chains + +1. Duplicate the `chains` section inside `enclave.config.yaml` with new RPC URLs and contract + addresses. +2. Allocate fresh ticket balances per chain (each registry is independent). +3. Run separate CLI supervisors or containers to keep blast radius small. +4. Use labeling/metrics to distinguish logs per chain. + +Adapt these scenarios to your internal runbooks and share improvements via PRs so the community keeps +leveling up—just like the best competitor docs do. diff --git a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx new file mode 100644 index 0000000000..57e23d0615 --- /dev/null +++ b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx @@ -0,0 +1,61 @@ +--- +title: 'Tickets & Sortition' +--- + +# Tickets & Sortition + +Tickets (ETK) express your willingness to perform work; sortition converts those staked tickets into +committee slots. This page explains both the math and the operational workflow. + +## Ticket economics + +- Tickets are priced in stablecoins and wrapped as non-transferable ETK balances. +- Your committee probability scales linearly with `availableTickets`. Doubling tickets roughly +doubles the chance of selection, assuming peers keep balances constant. +- Ticket balances are snapshotted **before** each `Enclave.request` (specifically, at + `requestBlock - 1`). Topping up after the request event does not affect that round. +- Rewards distribute proportional to committee participation, so dormant tickets still incur capital +cost without returns. + +## Sortition phases + +1. **Request created** — `Enclave.request` emits `E3Requested`. The CLI listens and schedules + submissions for operators that are `active` (bonded + tickets + not banned). +2. **Submission window** — The registry exposes `sortitionSubmissionWindow` (10s on Sepolia). During + this period, operators call `submitTicket(e3Id, ticketNumber)` for each ticket they want in the + lottery. The CLI parallelizes submissions. +3. **Committe finalization** — After the window closes and at least `threshold_m` submissions exist, + anyone can call `finalizeCommittee(e3Id)`. Winners publish key shares and assemble the committee + public key via `publishCommittee`. +4. **Duty execution** — Selected nodes produce decryption shares for every ciphertext published in + that E3. + +## How tickets influence selection + +For each ticket submitted, the registry derives a pseudo-random value from the request seed. The top +`t` values (based on threshold) win. Holding more tickets means more entries in that lottery. + +```text +submissionRandom = keccak256(seed, operator, ticketNumber) +``` + +Operators can observe submission health through the CLI logs: + +``` +INFO sortition::submitted e3_id=42 ticket=3 latency_ms=412 +``` + +If you prefer direct contract interaction, query: + +```solidity +function submissions(uint256 e3Id, address operator) external view returns (uint256[] memory); +``` + +## Best practices + +- **Stagger ticket top-ups**: replenish balances ahead of time to avoid gas spikes right before a + request window. +- **Alert on missed submissions**: set log-based alerts when `NodeNotEligible` or + `SubmissionWindowClosed` appears. +- **Batch networks**: if you operate on multiple chains, keep per-chain ETK balances and run + independent CLI supervisors so a congested chain does not block others. diff --git a/docs/pages/computation-flow.mdx b/docs/pages/computation-flow.mdx index 6015c5e4c7..8d01a70291 100644 --- a/docs/pages/computation-flow.mdx +++ b/docs/pages/computation-flow.mdx @@ -11,31 +11,34 @@ Providers, or other network participant. ### Phase 1: Request -1. **Define the E3 Program**: The core FHE logic of your application must be written in a supported - FHE scheme. Currently, Enclave supports the [fhe.rs](https://github.com/gnosisguild/fhe.rs) - implementation of the BFV encryption scheme. -2. **Choose a Compute Provider**: Your E3 program will likely need to be written to explicitly - support your chosen Compute Provider. For our demo application, [CRISP](/CRISP/introduction), we - use [Risc Zero](https://www.risczero.com/) as our Compute Provider. -3. **Specify Parameters**: - - Set the threshold (t/n) for the Ciphernode Committee (CiCo), which defines the number of nodes - that must coordinate to decrypt the computation output. This can be user-defined or - pre-configured based on your application's needs. - - Provide any necessary parameters specific to the Compute Provider. - - Configure E3 Program parameters, including input submission deadlines and computation duration. -4. **Submit the Request**: Call `request` on the Enclave contract to publish the request and - initialize the E3. +1. **Define the E3 Program**: Author your Secure Process using the tooling described in + [Writing the Secure Process](/write-secure-program). Enclave currently ships first-party support + for the BFV scheme via [fhe.rs](https://github.com/gnosisguild/fhe.rs) and the SAFE library. +2. **Choose a Compute Provider**: Your program must align with the execution backend (e.g., + [RISC Zero](https://www.risczero.com/) for [CRISP](/CRISP/introduction) or a custom FHE + coprocessor). +3. **Assemble `E3RequestParams`**: + - `threshold`: the CiCo size/threshold tuple (t/n) used for decryption security + - `startWindow` and `duration`: governs when inputs open/close and how long execution may run + - `e3Program`, `e3ProgramParams`, `computeProviderParams`, and optional `customParams` +4. **Submit the Request**: Call `request` with the struct to publish the new computation. ```solidity function request( - address filter, - uint32[2] calldata threshold, - uint256[2] calldata startWindow, - uint256 duration, - IE3Program e3Program, - bytes memory e3ProgramParams, - bytes memory computeProviderParams - ) external returns (uint256 e3Id, E3 memory e3) + E3RequestParams calldata requestParams + ) external returns (uint256 e3Id, E3 memory e3); + ``` + + ```solidity + struct E3RequestParams { + uint32[2] threshold; + uint256[2] startWindow; + uint256 duration; + IE3Program e3Program; + bytes e3ProgramParams; + bytes computeProviderParams; + bytes customParams; + } ``` ### Phase 2: Node Selection diff --git a/docs/pages/noir-circuits.mdx b/docs/pages/noir-circuits.mdx new file mode 100644 index 0000000000..bc24f210d9 --- /dev/null +++ b/docs/pages/noir-circuits.mdx @@ -0,0 +1,82 @@ +--- +title: 'Noir Circuits' +description: 'Build and reuse Noir circuits for Enclave programs' +--- + +# Noir Circuits & Libraries + +Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge, +polynomial utilities, GRECO hashing, etc.). Use these circuits as-is or vendor them into your own E3 +programs. + +## Workspace layout + +``` +circuits/ +├── Nargo.toml # workspace manifest +├── crates/ +│ └── libs/ +│ ├── safe/ # SAFE sponge implementation +│ ├── greco/ # Poseidon & Merkle helpers +│ └── polynomial/ # polynomial commitments utils +└── target/ # build artifacts (created by nargo) +``` + +Each library has its own `README.md` describing APIs and dependency stanza. Example (`safe`): + +```toml +[dependencies] +safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } +``` + +From `v0.1.6` onward the directory becomes `circuits/crates/libs/safe` (the `packages/` prefix was removed). + +## Tooling requirements + +Install the Noir toolchain: + +```bash +curl -L https://noir-lang.org/install | bash # installs nargo + bb +nargo --version # 1.0.0-beta.11+ +bb --version # v0.87.0+ +``` + +## Formatting & compilation + +Run the helper scripts from the repo root or reproduce them in your project: + +```bash +./scripts/compile-circuits.sh # nargo fmt --check && nargo compile --workspace +./scripts/lint-circuits.sh # format check + warnings +./scripts/test-circuits.sh # run circuit unit tests (nargo test) when available +``` + +These scripts exit early (without failing the whole build) if `nargo` is not installed, which makes CI happy +when Noir is optional. + +## Exporting verifiers + +Projects such as CRISP compile Noir circuits into Solidity verifiers using `bb`: + +```bash +cd examples/CRISP +./scripts/compile_circuits.sh +``` + +The script performs: + +1. `nargo compile` for every circuit in the workspace +2. `bb write_vk` to emit the verification key (`circuits/target/vk`) +3. `bb write_solidity_verifier` to produce `CRISPVerifier.sol` +4. Copies the generated verifier into `packages/crisp-contracts/contracts/` + +Adapt the script for your own circuits and verifiers by changing the output path. + +## Integrating with E3 programs + +- Import the library from `Nargo.toml` or `program/Cargo.toml` +- Generate Solidity verifiers and move them into your contract package +- Reference the compiled artifacts when deploying via the template or CRISP scripts + +When adding new circuits, remember to update `package.json` scripts (e.g., `pnpm dev:all`) so they call your +compile script before spinning up the dev environment. This keeps your verifiers in sync with the Noir source. diff --git a/docs/pages/project-template.mdx b/docs/pages/project-template.mdx new file mode 100644 index 0000000000..ec792a8456 --- /dev/null +++ b/docs/pages/project-template.mdx @@ -0,0 +1,95 @@ +--- +title: 'Project Template' +description: 'What gets generated by `enclave init` and how to customize it' +--- + +# Default Project Template + +Running `enclave init ` clones the `templates/default` workspace into your directory and +adds a tailor-made `enclave.config.yaml`. The goal is to give you a full-stack, reproducible playground +for building and testing E3 programs without copying the entire monorepo. + +## Layout + +``` +my-first-e3/ +├── contracts/ # Hardhat workspace with Enclave adapters + your E3 program contracts +├── program/ # RISC Zero guest code and runner +├── server/ # TypeScript coordination server +├── client/ # React + Vite frontend wired to @enclave-e3/sdk +├── deploy/ # Scripts + ignition configs +├── scripts/ # Helper scripts (start dev stack, ciphernodes, etc.) +├── tests/ # Integration + contract tests +├── enclave.config.yaml # Node + chain config consumed by the CLI +├── package.json # Dev orchestrator scripts +└── .enclave/ # cached CLI state (ignored by git) +``` + +Each workspace shares the same `pnpm` root so dependencies stay in sync. + +## Commands + +| Script | Purpose | +| --- | --- | +| `pnpm dev:all` | Spins up Hardhat, deploys contracts, launches the RISC0 program server, coordination server, frontend, and ciphernodes. | +| `pnpm dev:evm` | Runs `hardhat node` on `http://localhost:8545`. | +| `pnpm dev:program` | Starts the RISC0 guest runner. Pass `--dev` to skip real proving. | +| `pnpm dev:server` | Boots the TypeScript coordination server with hot reload. | +| `pnpm dev:frontend` | Launches the Vite client on `http://localhost:3000`. | +| `pnpm dev:ciphernodes` | Calls the Enclave CLI to launch the nodes defined in `enclave.config.yaml`. | +| `pnpm compile` | Compiles Solidity contracts. | +| `pnpm test` | Runs Hardhat tests. | +| `pnpm test:integration` | Executes the end-to-end flow in `tests/`. | + +Before `dev:all` runs, the `predev:all` hook calls `enclave program compile` so the latest zkVM image +is ready; skip this by exporting `SKIP_PROGRAM_COMPILE=1`. + +## Environment files + +- `client/.env`: contains `VITE_` variables for contract addresses, RPC URLs, and optional feature flags. +- `server/.env`: holds the operator wallet key (never commit), RPC endpoints, and cron API tokens. +- `enclave.config.yaml`: describes your Ciphernodes and aggregator profile. The default file mirrors the + template you saw earlier in this repo. + +## Integrating the SDK + +The template already wires the [Enclave SDK](/sdk): + +- `client/src/sdk.ts` exports a singleton `EnclaveSDK` +- `client/src/hooks/useE3.ts` wraps `useEnclaveSDK` +- `server/src/services/enclave.ts` instantiates a wallet-backed SDK for automation + +Update the `.env` files after every redeploy so the SDK listens to the correct contracts. + +## Noir circuits & Nargo + +Although the template ships with a simple addition circuit, you can plug in Noir circuits by pointing to +this repo's shared libraries (`circuits/crates/libs/*`). Add dependencies in your `program/Cargo.toml` or +your Noir workspace's `Nargo.toml`: + +```toml +[dependencies] +safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } +``` + +Use the helper scripts in the root repo (`scripts/compile-circuits.sh`, `scripts/lint-circuits.sh`) as a +reference for formatting and compiling Noir workspaces via `nargo` and `bb`. Integrate similar scripts in +`my-first-e3/scripts/` if your application publishes verifiers alongside the template contracts. + +## Customizing Ciphernodes + +`enclave.config.yaml` includes multiple node profiles (`cn1`, `cn2`, `cn3`, `ag`). Update the addresses, +peers, and QUIC ports to match your deployment. For production, replace `autonetkey/autopassword` with +explicit secrets and run `enclave nodes up --detach` from a systemd service or container entrypoint. + +## Common tweaks + +- **Alternate compute providers**: edit `server/src/providers` to switch between RISC Zero dev-mode vs + real proving, or wire in a custom prover. +- **Program parameters**: `server/src/config/e3.ts` defines the default thresholds and time windows used + when calling `sdk.requestE3`. Adjust them to match your chain's latency. +- **Frontend UI**: `client/src/components/ResultCard.tsx` renders decrypted outputs—extend it with your + own domain logic. + +The template is intentionally opinionated so you can delete what you do not need while still referencing a +complete working stack. diff --git a/docs/pages/quick-start.mdx b/docs/pages/quick-start.mdx index a215514848..2e6ee355fe 100644 --- a/docs/pages/quick-start.mdx +++ b/docs/pages/quick-start.mdx @@ -105,7 +105,9 @@ Now that you have a working E3 program: 1. **Explore the code**: Check out `./program/src/lib.rs` to see the FHE computation 2. **Modify the computation**: Try changing the addition to multiplication 3. **Update the UI**: Customize the client in `./client/src/` -4. **Deploy**: Learn about production deployment +4. **Run real Ciphernodes**: Follow the [Ciphernode Operators guide](/ciphernode-operators) to bond +tokens, configure nodes, and join the shared network +5. **Deploy**: Learn about production deployment Ready to dive deeper? Continue with our [Hello World Tutorial](/hello-world-tutorial) for a step-by-step breakdown of building E3 programs from scratch. diff --git a/docs/pages/sdk.mdx b/docs/pages/sdk.mdx new file mode 100644 index 0000000000..2e0643b948 --- /dev/null +++ b/docs/pages/sdk.mdx @@ -0,0 +1,156 @@ +--- +title: 'Enclave SDK' +description: 'Use the TypeScript + React SDKs to drive E3 programs from clients and services' +--- + +# Enclave SDK Overview + +The Enclave SDK (`@enclave-e3/sdk`) and React helpers (`@enclave-e3/react`) provide a batteries-included +client stack for requesting E3 computations, subscribing to protocol events, and coordinating custom +frontends or backend services. Both packages ship in this repository (see `packages/enclave-sdk` and +`packages/enclave-react`). + +## Installation + +```bash +pnpm add @enclave-e3/sdk # TypeScript SDK +pnpm add @enclave-e3/react # React hooks (optional) +``` + +For browser projects using WASM (encryption helpers, FHE keygen), configure Vite per the SDK README: + +```ts +// vite.config.ts +import wasm from 'vite-plugin-wasm' +import topLevelAwait from 'vite-plugin-top-level-await' + +export default defineConfig({ + optimizeDeps: { + exclude: ['@enclave-e3/wasm'], + }, + plugins: [wasm(), topLevelAwait()], +}) +``` + +## Core client + +```ts +import { EnclaveSDK, EnclaveEventType, RegistryEventType } from '@enclave-e3/sdk' +import { createPublicClient, createWalletClient, http, custom } from 'viem' + +const publicClient = createPublicClient({ transport: http(import.meta.env.VITE_RPC_URL) }) +const walletClient = createWalletClient({ transport: custom(window.ethereum) }) + +const sdk = new EnclaveSDK({ + publicClient, + walletClient, + contracts: { + enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, + ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, + }, + chainId: 11155111, +}) + +await sdk.initialize() +``` + +### Requesting computations + +```ts +const hash = await sdk.requestE3({ + threshold: [2, 3], + startWindow: [BigInt(Date.now()), BigInt(Date.now() + 5 * 60 * 1000)], + duration: BigInt(1800), + e3Program: '0x...', + e3ProgramParams: '0x', + computeProviderParams: '0x', + customParams: '0x', +}) +``` + +### Event subscriptions + +```ts +sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, (event) => { + console.log('New request', event.data) +}) + +sdk.onEnclaveEvent(RegistryEventType.CIPHERNODE_ADDED, (event) => { + console.log('Operator joined', event.data) +}) + +// Later, remember to clean up +sdk.off(EnclaveEventType.E3_REQUESTED, handler) +``` + +### React hook + +```tsx +import { useEnclaveSDK } from '@enclave-e3/react' + +export function Dashboard() { + const { + isInitialized, + requestE3, + onEnclaveEvent, + EnclaveEventType, + } = useEnclaveSDK({ + autoConnect: true, + contracts: { + enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, + ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, + }, + chainId: 31337, + }) + + useEffect(() => { + if (!isInitialized) return + const handle = (event) => console.log('Activated', event.data) + onEnclaveEvent(EnclaveEventType.E3_ACTIVATED, handle) + return () => off(EnclaveEventType.E3_ACTIVATED, handle) + }, [isInitialized]) + + return +} +``` + +## Configuration contract map + +Provide both the Enclave and CiphernodeRegistry addresses. The template exposes these via +`.env` / `enclave.config.yaml`, and CRISP scripts surface them in deployment logs. For multi-chain +apps, instantiate multiple SDKs or call `sdk.updateConfig({ contracts: { ... }, chainId })` whenever +wallets switch networks. + +## Working with the template + +`enclave init` generates the default template (see [Project Template](/project-template)). The client +already wires `@enclave-e3/sdk` and `@enclave-e3/react`: + +- `client/src/sdk.ts` builds the shared SDK instance +- `client/src/hooks/useE3.ts` uses `useEnclaveSDK` to expose helper hooks throughout the UI +- `server/src/services/enclave.ts` instantiates the SDK with a server wallet using `createWalletClient` + +When you add new contracts or E3 programs, update `client/.env` and `server/.env` with the new +addresses, then restart the dev server so the SDK reconnects. + +## Advanced usage + +- **Historical events**: `sdk.getHistoricalEvents(type, fromBlock, toBlock)` fetches logs without a + WebSocket provider; useful for CRON jobs or health checks. +- **Gas controls**: pass `gasLimit` to `requestE3`, `activateE3`, or `publishInput` if you want fixed + limits when interacting with Enclave on L2s. +- **Event polling**: `sdk.startEventPolling()` is handy in serverless environments where websockets + are unavailable. +- **Custom transports**: on the server, call `createWalletClient({ account, transport: http(rpc) })` + and load the private key from Vaults/KMS. + +## Troubleshooting + +| Symptom | Triage | +| --- | --- | +| `MISSING_PUBLIC_CLIENT` errors | Ensure `createPublicClient` uses an HTTP or WebSocket RPC reachable from the app. | +| `INVALID_ADDRESS` | Double-check contract addresses passed into the SDK match the current chain. | +| Hooks never initialize | Confirm `autoConnect` is true, wallet is connected, and React component is inside a provider that renders on the client. | +| No events arrive | Switch to a WebSocket RPC or call `sdk.startEventPolling()` so logs are polled over HTTP. | + +For additional API surface details see `packages/enclave-sdk/README.md` inside this repo. diff --git a/docs/pages/setting-up-server.mdx b/docs/pages/setting-up-server.mdx index cbbd12f783..ca90ffa313 100644 --- a/docs/pages/setting-up-server.mdx +++ b/docs/pages/setting-up-server.mdx @@ -29,16 +29,16 @@ The Enclave SDK handles much of this complexity for you, providing: ### Install the SDK -For TypeScript/JavaScript applications: +For TypeScript/JavaScript applications install the TypeScript SDK: ```bash -pnpm add @enclave-e3/contracts +pnpm add @enclave-e3/sdk ``` -For React applications: +For React applications add the hook helpers as well: ```bash -pnpm add @enclave-e3/contracts @enclave-e3/react +pnpm add @enclave-e3/sdk @enclave-e3/react ``` ### Basic TypeScript Client diff --git a/docs/pages/use-cases.mdx b/docs/pages/use-cases.mdx new file mode 100644 index 0000000000..f38c769dd6 --- /dev/null +++ b/docs/pages/use-cases.mdx @@ -0,0 +1,62 @@ +--- +title: 'Use Cases' +--- + +# Unlocking Enclave Use Cases + +Leading confidential-compute platforms such as Ritual, Fhenix, and Olas showcase their ecosystems by +highlighting concrete scenarios, personas, and playbooks. This page borrows that structure so you +can quickly map Enclave building blocks to the outcomes you need. + +## Confidential Governance (CRISP-style) + +- **Problem**: Public DAOs struggle to keep tallies, delegations, and vote rationales private during + sensitive decisions. +- **Pattern**: Use the CRISP template (client, Rust server, Noir circuits) with the Enclave SDK. +- **Flow**: DAO admins request an E3 round, contributors encrypt ballots in the browser, and + Ciphernodes publish a verifiable plaintext tally once the compute provider finishes. +- **Extras**: Plug Synpress or Playwright into the client for scripted voting drills. + +## Private Auctions & Matching Markets + +- **Problem**: Sealed-bid auctions or RFQ desks cannot run on public ledgers without leaking prices. +- **Pattern**: Model each bid as an input validated by account-specific ZKPs (range/whitelist) and + aggregate them off-chain using BFV-friendly arithmetic in your Secure Process. +- **Flow**: Traders submit encrypted bids, the compute provider selects the clearing price, and the + plaintext output unlocks settlement logic. +- **Extras**: Pair with Foundry scripts (similar to Fhenix's CoFHE quick starts) to simulate extreme + bidding volumes before mainnet. + +## AI Agent Coordination + +- **Problem**: Networks such as Ritual and Olas expose agent marketplaces; those agents still need a + privacy-preserving substrate for sensitive scoring, routing, or risk checks. +- **Pattern**: Treat each agent as a Data Provider, push policy enforcement into an `IInputValidator`, + and let Enclave host shared state transitions (e.g., allocating budget or updating trust scores). +- **Flow**: Agents encrypt telemetry, the Secure Process derives rankings, and downstream contracts or + marketplaces read the published plaintext. +- **Extras**: Use `customParams` inside `E3RequestParams` to tag rounds per agent vertical (NFT curation, + wallet assistants, on-chain AI retrieval). + +## Identity, Compliance, and Scoring + +- **Problem**: Identity attestations or credit scores leak sensitive attributes when stored directly + on-chain. +- **Pattern**: Build circuits that validate proofs of residency, KYC, or AML results without revealing + raw data; only the computed risk vector is decrypted. +- **Flow**: Validators encrypt attestations, the Secure Process derives the minimal disclosure blob, + and downstream protocols pull the plaintext via `PlaintextOutputPublished`. +- **Extras**: Combine with `customParams` to pin jurisdictional policy, similar to how Fhenix exposes + "Key Considerations" per sector. + +## Solution Matrix + +| Scenario | Typical Inputs | Secure Process Focus | Output Consumers | +| --- | --- | --- | --- | +| Confidential Governance | Wallet + ballot selections | Vote aggregation, quorum, randomness | DAO front-ends, multi-sigs | +| Private Auctions | Bid amount, bidder proofs | Price discovery, winner selection | Settlement contracts | +| AI Agent Coordination | Agent telemetry, task queue | Ranking, budget splits | Agent marketplaces, orchestrators | +| Identity / Compliance | Encrypted attestations | Risk flag derivation | On-chain registries, bridges | + +Next, explore the [Best Practices](/best-practices) and +[Putting It All Together](/putting-it-together) guides to tailor these patterns to your app. From b382ec55d95aee9672c7ca5a5f04ce87adff1bbe Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Sat, 15 Nov 2025 16:33:04 +0500 Subject: [PATCH 02/19] chore: update docs --- .../exits-and-slashing.mdx | 66 +++++++- docs/pages/ciphernode-operators/index.mdx | 56 ++++++ .../pages/ciphernode-operators/operations.mdx | 30 ++++ .../ciphernode-operators/registration.mdx | 51 +++++- docs/pages/ciphernode-operators/scenarios.mdx | 34 ++++ .../tickets-and-sortition.mdx | 160 +++++++++++++----- 6 files changed, 344 insertions(+), 53 deletions(-) diff --git a/docs/pages/ciphernode-operators/exits-and-slashing.mdx b/docs/pages/ciphernode-operators/exits-and-slashing.mdx index 8a615d73f6..7e03bcefe6 100644 --- a/docs/pages/ciphernode-operators/exits-and-slashing.mdx +++ b/docs/pages/ciphernode-operators/exits-and-slashing.mdx @@ -9,8 +9,19 @@ Understand how to collect rewards, respond to slashing proposals, and exit the r ## Rewards - Distributed via `BondingRegistry.distributeRewards` (any ERC20) -- Watch for `RewardsDistributed(e3Id, nodes, amounts)` events -- Ensure the operator wallet remains funded to claim rewards if additional gas is required +- Watch for `RewardsDistributed` events and map them back to the source `e3Id` +- Keep the operator wallet funded; payouts are on-chain transfers and still require gas when + claimed through automation scripts + +Pair reward monitoring with lightweight probes: + +```bash +cast call $BONDING "pendingExits(address)" $OPERATOR +cast call $BONDING "getTicketBalance(address)" $OPERATOR +cast call $BONDING "licenseRequiredBond()" +``` + +Seeing rewards fall while balances remain healthy is an early indicator of missed jobs or RPC issues. ## Slashing lifecycle @@ -26,15 +37,45 @@ Stay alert for: - `appealWindow` values per policy (some reasons skip appeals entirely) - `updateBanStatus` (governance must lift bans before re-registration) +Policy anatomy: + +```solidity +struct SlashPolicy { + uint256 ticketPenalty; + uint256 licensePenalty; + bool requiresProof; + uint64 appealWindow; + bool appealable; +} +``` + +Never assume a slash is appealable without fetching the latest policy via `SlashingManager`. + ## Exit process -1. Call `deregisterOperator(bytes32[] calldata siblingProof)` - - The proof removes the operator from the registry's incremental Merkle tree (IMT) - - Capture it via the CLI logs, `CiphernodeAdded` events, or by querying the registry -2. Tickets burn immediately; license bonds enter the exit queue with an unlock timestamp -3. Wait for the configured delay (`exitDelay`, 7 days on Sepolia) -4. Claim funds with `claimExits(uint256 maxTickets, uint256 maxLicense)` - - Use `pendingExits(address)` or `previewClaimable(address)` to check readiness +1. **Deregister** — Call `deregisterOperator(uint256[] siblingNodes)` with a valid IMT proof. The + CLI logs the proof when you first register; stash it alongside your secrets bundle. +2. **Queue assets** — Ticket balances burn immediately. License bonds slide into the exit queue and + set `exitUnlocksAt = block.timestamp + exitDelay`. +3. **Wait out `exitDelay()`** — Default is 7 days on Sepolia. Automation should poll + `exitUnlocksAt(address)` to know when to attempt a claim. +4. **Claim exits** — Once the unlock timestamp passes, drain the queue: + + ```bash + cast send $BONDING "claimExits(uint256,uint256)" $MAX_TICKETS $MAX_LICENSE \ + --rpc-url $RPC --private-key $OPERATOR_KEY + ``` + + Pass `type(uint256).max` to withdraw the full pending amount. The call reverts with + `ExitNotReady` if neither queue matured yet. +5. **Cancel if needed** — Calling `registerOperator()` before `claimExits` clears the exit and puts + you back into the registry. + +Helpful getters: + +- `pendingExits(address)` → pending ticket + license totals +- `exitUnlocksAt(address)` → timestamp when claims unlock +- `hasExitInProgress(address)` → guard before attempting to re-register ## Health checklist @@ -50,3 +91,10 @@ Stay alert for: - Securely wipe local secrets (`enclave nodes purge` and delete keystores) - Revoke RPC credentials and firewall openings - Document the exit reason for future audits or compliance + +## Slashing prevention checklist + +- Keep `enclave jobs list` empty before scheduled maintenance so you do not abandon active work. +- Alert on `SlashProposed` events tagged with your operator address. +- Archive CLI + RPC logs for every incident; you need them for appeals. +- Double-check `isActive` after any ticket removal or license unbond to avoid accidental downtime. diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx index 4aeae39f78..370af52b21 100644 --- a/docs/pages/ciphernode-operators/index.mdx +++ b/docs/pages/ciphernode-operators/index.mdx @@ -9,6 +9,19 @@ Ciphernodes decrypt committee outputs, publish threshold key shares, and keep th pipeline moving. This section organizes everything operators need—from bonding requirements to exit procedures—into focused guides. +## Responsibilities at a glance + +Operators are expected to cover four concurrent tracks: + +- **Key management**: generate PVSS shares, keep private key material encrypted at rest, and publish + committee public keys once the threshold is met. +- **Decryption work**: watch for ciphertext outputs, craft decryption shares, and ensure plaintext + gets relayed on-chain. +- **Network availability**: run a QUIC/libp2p endpoint that stays reachable, stay synced to the + event bus, and keep RPC endpoints redundant. +- **Operational hygiene**: rotate secrets, snapshot configs, monitor sortition + job logs, and react + to slashing proposals or bans quickly. + ## Role overview Operators are expected to: @@ -22,6 +35,18 @@ Operators are expected to: Each node profile in `enclave.config.yaml` can point to a different network (mainnet, testnet, or local dev). The CLI supervises all configured chains concurrently. +## Why operate a Ciphernode? + +- **Rewards & upside**: committee participation and steady uptime translate to ERC20 payouts through + `distributeRewards`. +- **Governance voice**: active operators are closest to the protocol and shape roadmap + policy + discussions. +- **Visibility**: infra partners highlight high-performing nodes in working group updates and future + customer routes. + +Balance rewards against the capital tied up in ENCL bonds and ETK tickets plus infra costs. The +Scenarios page includes quick ROI checklists. + ## Contract references | Contract | Sepolia address | Notes | @@ -37,6 +62,17 @@ local dev). The CLI supervises all configured chains concurrently. > ⚠️ Confirm addresses in `packages/enclave-contracts/deployed_contracts.json` or your deployment > output before funding a node. Values differ per network. +## Requirements checklist + +| Track | What you need | Notes | +| --- | --- | --- | +| Financial | ≥ `licenseRequiredBond` ENCL, ≥ `minTicketBalance * ticketPrice` USDC, plus gas | Top up + ahead of big request windows | +| Technical | Linux/macOS host, 4 cores / 8 GB RAM minimum, open UDP ports for QUIC | Containers or + bare metal both work | +| Operational | CLI >= current release, secrets storage (password, wallet, net key), monitoring + + pager | Bake into `ciphernode-entrypoint.sh` in `deploy/` | + ## Section map - [Registration & Licensing](./registration) — economic requirements, bonding steps, CLI commands @@ -46,3 +82,23 @@ local dev). The CLI supervises all configured chains concurrently. - [Runbook Scenarios](./scenarios) — ready-made playbooks for common situations Use these pages sequentially when onboarding a new operator or jump to the topic you need. + +## Lifecycle states + +```mermaid +stateDiagram-v2 + [*] --> Unbonded + Unbonded --> Licensed: bondLicense(amount >= requiredBond) + Licensed --> Registered: registerOperator() + Registered --> Active: addTicketBalance(balance >= minBalance) + Active --> Inactive: removeTicketBalance() OR unbondLicense() + Inactive --> Active: addTicketBalance() OR bondLicense() + Active --> ExitPending: deregisterOperator() + Inactive --> ExitPending: deregisterOperator() + Registered --> ExitPending: deregisterOperator() + ExitPending --> [*]: claimExits() after exitDelay + ExitPending --> Registered: registerOperator() (cancels exit) +``` + +Refer back here while reading the rest of the section; each guide calls out which state transitions +it affects. diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx index ec30b16a63..9489e76104 100644 --- a/docs/pages/ciphernode-operators/operations.mdx +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -14,6 +14,21 @@ and deployment automation. - Rotate secrets and backups on a defined cadence. - Capture logs for sortition submissions, key publication, and decryption shares. +## When you're selected for a committee + +1. **Keyshare generation** + - The CLI logs `jobs::selected` when `CommitteeFinalized` includes your operator address. + - Verify `~/.local/share/enclave/jobs//` holds encrypted keyshare material. +2. **Public key aggregation** + - Wait for every member to publish their share; the CLI automatically calls `publishCommittee` once the threshold is met. + - Monitor for `CommitteePublished` and accompanying CLI logs. +3. **Ciphertext + decryption flow** + - Subscribe to `CiphertextOutputPublished` and `PlaintextOutputPublished`. + - Run `enclave jobs status ` to check whether decryption shares were sent. + +Missing any of these steps is the fast path to slashing. Keep short-lived dashboards for the +currently active E3 IDs so you can intervene manually if automation stalls. + ## CLI workflow ```bash @@ -45,6 +60,19 @@ enclave start --config /path/to/enclave.config.yaml --peer /dns4/bootstrap.encla Flags such as `--autowallet` and `--autonetkey` will prompt-less configure secrets when the config contains `autowallet: true` and siblings. +## Job state cheat sheet + +| State | Trigger | What to verify | +| --- | --- | --- | +| `Selected` | Committee finalized | `enclave jobs list` shows new entry | +| `KeyshareGeneration` | CLI deriving PVSS shares | Disk has encrypted secret + public share | +| `WaitingForCiphertext` | Key material ready | Node staying synced to event stream | +| `Decrypting` | Ciphertext output event received | Decryption share stored + submitted | +| `Completed` | Plaintext emitted | Rewards monitoring sees participation | + +Use `enclave jobs details ` for deep dives or to reprint diagnostics when coordinating with +support/governance. + ## Configuration reference ```yaml @@ -104,3 +132,5 @@ then runs `enclave start -v`. Reuse this pattern for Kubernetes Jobs, Nomad, or - Track CLI logs for `sortition::submitted`, `decryption::share_published`, and errors. - Export Prometheus metrics from your infrastructure layer (CPU, bandwidth, disk) since the CLI currently logs to stdout. +- Add alerts for `jobs::error`, `NodeNotEligible`, or `ExitNotReady` so you can correct course + before a slash happens. diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx index 86970b518f..9ed1dafa44 100644 --- a/docs/pages/ciphernode-operators/registration.mdx +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -7,6 +7,17 @@ title: 'Registration & Licensing' This guide covers everything required to become an active Ciphernode: collateral, bonding, registration transactions, and config secrets. +## Before you start + +| Track | Checklist | +| --- | --- | +| Financial | ENCL covering `licenseRequiredBond`, USDC covering at least `minTicketBalance * ticketPrice`, and ETH for gas | +| Technical | Enclave CLI ≥ current release, WebSocket RPC, `enclave password/net keypair/wallet` secrets set | +| Operational | `enclave.config.yaml` committed, secrets mirrored into `deploy/*.secrets.json`, monitoring hooks for registration state | + +Adjust the numbers using `cast call $BONDING` for `licenseRequiredBond()`, `ticketPrice()` and +`minTicketBalance()` on your target network. + ## Economic requirements Sepolia defaults (check `BondingRegistry` on your network): @@ -62,11 +73,45 @@ deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY ``` 5. **Verify status** - - `BondingRegistry.isRegistered(address)` returns `true` - - `BondingRegistry.isActive(address)` flips `true` once bond + ticket floors are met -6. **Snapshot config for production** + ```bash + cast call $BONDING "isRegistered(address)" $OPERATOR + cast call $BONDING "isActive(address)" $OPERATOR + cast call $BONDING "getLicenseBond(address)" $OPERATOR + cast call $BONDING "getTicketBalance(address)" $OPERATOR + ``` +6. **Add buffers (optional)** + - Maintain ≥ 1.1× the minimum license bond so transient unbonds or slashes do not deactivate you + - Keep a few extra tickets so `availableTickets` never dips below the floor +7. **Snapshot config for production** - Commit `enclave.config.yaml` alongside deployment manifests - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely > ℹ️ The CLI supports multiple named wallets. Use `enclave wallet list` to confirm the correct signer > is active before running bonding transactions. + +## One-command bootstrap (optional) + +Hardhat ships with a helper task that strings approvals + bonding + registration together: + +```bash +npx hardhat ciphernode:add \ + --license-bond-amount 100000000000000000000 \ + --ticket-amount 10000000 +``` + +It calls `bondLicense`, `registerOperator`, and `addTicketBalance` under the hood. Production nodes +usually stick with explicit `cast` or `enclave` commands for better observability and auditing. + +## Status probes to monitor + +Once bonded, keep lightweight probes in your monitoring stack: + +```bash +cast call $BONDING "minTicketBalance()" +cast call $BONDING "ticketPrice()" +cast call $BONDING "licenseRequiredBond()" +cast call $BONDING "hasExitInProgress(address)" $OPERATOR +``` + +Pause automation if any probe changes unexpectedly until you reconcile it with a governance action +or migration plan. diff --git a/docs/pages/ciphernode-operators/scenarios.mdx b/docs/pages/ciphernode-operators/scenarios.mdx index 986a40f704..4e9ad7ff9a 100644 --- a/docs/pages/ciphernode-operators/scenarios.mdx +++ b/docs/pages/ciphernode-operators/scenarios.mdx @@ -46,3 +46,37 @@ Enclave operator procedures under real conditions. Adapt these scenarios to your internal runbooks and share improvements via PRs so the community keeps leveling up—just like the best competitor docs do. + +## Lifecycle quick reference + +| State | How you get here | How to leave | +| --- | --- | --- | +| Unbonded | Fresh wallet, zero ENCL locked | `bondLicense(amount)` | +| Licensed | Bonded ≥ required amount but not registered | `registerOperator()` | +| Registered | In the IMT but maybe inactive | `addTicketBalance()` (become active) or `deregisterOperator()` | +| Active | Registered + ticket + bond minimums met | `removeTicketBalance()` / `unbondLicense()` (drops to inactive) | +| Inactive | Registered but missing tickets/bond | Top up tickets/bond | +| ExitPending | `deregisterOperator()` called | `claimExits()` (finish) or `registerOperator()` (cancel) | + +Use this alongside the state diagram in the overview page when debugging transitions. + +## Troubleshooting cheat sheet + +| Symptom | Checks | Fix | +| --- | --- | --- | +| Node fails to start | `enclave config show`, RPC connectivity, wallet + password presence | Re-run `enclave init`, reset secrets, verify WebSocket URL | +| No events flowing | RPC health, `enclave nodes ps`, firewall rules | Switch RPC, restart CLI supervisor, ensure websocket endpoint | +| Keyshare generation fails | Ensure you were actually selected, disk space, permissions on data dir | Restart node after clearing corrupt job folder, re-import secrets | +| Decryption stalls | Confirm `CiphertextOutputPublished` fired, job still active, secret share available | Replay event logs, rehydrate job metadata, escalate before appeal window closes | + +## Monitoring commands + +```bash +enclave nodes ps +enclave jobs list +enclave jobs status +cast call $BONDING "isActive(address)" $OPERATOR +``` + +Pipe these into your favorite exporter or watch scripts so you notice issues before slashing +proposals land. diff --git a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx index 57e23d0615..8c8c14afc0 100644 --- a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx +++ b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx @@ -4,58 +4,136 @@ title: 'Tickets & Sortition' # Tickets & Sortition -Tickets (ETK) express your willingness to perform work; sortition converts those staked tickets into -committee slots. This page explains both the math and the operational workflow. +> Ticket availability: `availableTickets = floor(ticketTokenBalance / ticketPrice)` + +| Stake | Token | Purpose | Key calls | +| ------------ | -------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- | +| License bond | ENCL | Unlock registration + maintain eligibility | `bondLicense`, `unbondLicense`, `getLicenseBond` | +| Tickets | ETK (non-transferable, backed by USDC) | Determine committee probability | `addTicketBalance`, `removeTicketBalance`, `getTicketBalance`, `availableTickets` | + +- Keep ≥ `licenseRequiredBond * 0.8` bonded or `isActive` flips false. +- Hold ≥ `minTicketBalance` tickets so the registry considers you for committees. +- Check `hasExitInProgress` / `pendingExits` before rebonding; queued exits block new registrations. ## Ticket economics -- Tickets are priced in stablecoins and wrapped as non-transferable ETK balances. -- Your committee probability scales linearly with `availableTickets`. Doubling tickets roughly -doubles the chance of selection, assuming peers keep balances constant. -- Ticket balances are snapshotted **before** each `Enclave.request` (specifically, at - `requestBlock - 1`). Topping up after the request event does not affect that round. -- Rewards distribute proportional to committee participation, so dormant tickets still incur capital -cost without returns. - -## Sortition phases - -1. **Request created** — `Enclave.request` emits `E3Requested`. The CLI listens and schedules - submissions for operators that are `active` (bonded + tickets + not banned). -2. **Submission window** — The registry exposes `sortitionSubmissionWindow` (10s on Sepolia). During - this period, operators call `submitTicket(e3Id, ticketNumber)` for each ticket they want in the - lottery. The CLI parallelizes submissions. -3. **Committe finalization** — After the window closes and at least `threshold_m` submissions exist, - anyone can call `finalizeCommittee(e3Id)`. Winners publish key shares and assemble the committee - public key via `publishCommittee`. -4. **Duty execution** — Selected nodes produce decryption shares for every ciphertext published in - that E3. - -## How tickets influence selection - -For each ticket submitted, the registry derives a pseudo-random value from the request seed. The top -`t` values (based on threshold) win. Holding more tickets means more entries in that lottery. - -```text -submissionRandom = keccak256(seed, operator, ticketNumber) -``` +- Tickets are priced in stablecoins, minted into non-transferable ETK balances, and track intent to + work. +- Committee probability scales linearly with `availableTickets`; doubling tickets doubles your odds + if peers stay constant. +- Balances are snapshotted at `requestBlock - 1`. Adding tickets after the request event does not + change that round. +- Rewards accrue only when committees form and you complete duties, so idle tickets still incur the + opportunity cost of locked capital. + +### Managing ticket balance -Operators can observe submission health through the CLI logs: +```bash +# Approve USDC (or configured fee token) +cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY +# Add tickets (mints ETK) +cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + +# Remove tickets (burns ETK, returns USDC) +cast send $BONDING "removeTicketBalance(uint256)" 500e6 --rpc-url $RPC --private-key $OPERATOR_KEY ``` -INFO sortition::submitted e3_id=42 ticket=3 latency_ms=412 + +`removeTicketBalance` takes effect immediately. Dropping below the minimum ticket balance makes you +inactive until you top up again. + +### Rebalancing tips + +- Add tickets one or two requests ahead of anticipated demand to avoid race-condition gas spikes. +- Keep a small ticket buffer so slashing or removals do not instantly deactivate you. +- Monitor `ticketPrice()` and `minTicketBalance()` before automating deposits on multiple networks. + +## Sortition algorithm + +```mermaid +flowchart TD + A[E3Requested event] --> B[Snapshot balances (requestBlock - 1)] + B --> C[CLI filters active + ticketed operators] + C --> D[Submit numbered tickets via submitTicket] + D --> E[TicketSubmitted events expose scores] + E --> F[Finalize committee after submission deadline] + F --> G[Publish committee public key] + G --> H[Execute jobs (keyshares, ciphertext, decryption)] ``` -If you prefer direct contract interaction, query: +### 1. Event intake & eligibility + +1. `Enclave` requests a committee, triggering `CommitteeRequested` with the round seed, threshold, + and submission deadline. +2. Nodes snapshot balances at `requestBlock - 1` and build an **eligible set** where operators are: + - Registered and not banned + - `isActive` (bond + ticket minimums satisfied) + - Not in the middle of an exit + +### 2. Score-based selection + +Sortition is deterministic once the seed and eligible set are known: + +1. Derive per-ticket scores with `keccak256(seed, operator, ticketNumber)`. +2. Sort scores and take the top `threshold_n` entries. +3. Because the same inputs yield the same winners, every honest node converges on the same + committee. + +### 3. Ticket submissions & committee finalization + +1. Operators submit each winning ticket via `submitTicket(e3Id, ticketNumber)` during the + `sortitionSubmissionWindow` (10s on Sepolia). +2. Every submission emits `TicketSubmitted(e3Id, operator, ticketNumber, score)` so you can audit + progress. +3. After the window closes and ≥ `threshold_m` tickets are present, anyone calls + `finalizeCommittee(e3Id)`; the registry emits `CommitteeFinalized`. +4. Once enough key shares are ready, the CLI drives `publishCommittee`, emitting + `CommitteePublished` with the aggregated key. + +### 4. Committee operations + +- Generate and encrypt PVSS key shares for the round. +- Publish the committee public key once the threshold is met. +- Stay online for `CiphertextOutputPublished` and respond with decryption shares until + `PlaintextOutputPublished` confirms completion. + +See the [Operations & Responsibilities](./operations) page for the detailed job lifecycle. + +## Parameter reference ```solidity -function submissions(uint256 e3Id, address operator) external view returns (uint256[] memory); +uint32[2] threshold; // [threshold_m, threshold_n] ``` +- `threshold_m` — Minimum number of operators needed for duties (e.g., 3). +- `threshold_n` — Committee size (e.g., 5). The CLI submits up to this many tickets per E3. +- Use `CiphernodeRegistry.sortitionSubmissionWindow()` to size your submission workers. + +## Monitoring & troubleshooting + +### Signals to watch + +- `CommitteeRequested`, `TicketSubmitted`, `CommitteeFinalized`, and `CommitteePublished` events. +- CLI logs: `sortition::submitted`, `sortition::missed`, `jobs::selected`. +- Contract reads: `submissions(e3Id, operator)` to confirm ticket IDs and `getCommitteeNodes(e3Id)` + post-finalization. + +### Common issues + +| Symptom | Checks | Fix | +| ------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| Not being selected | Verify `isActive`, ticket balance ≥ minimum, no bans, and compare tickets to peers | Add tickets, rebond license, or appeal bans | +| `SubmissionWindowClosed` errors | Ensure submissions start immediately after `CommitteeRequested` and that RPC latency is low | Increase submission workers, reduce per-ticket delays | +| Committee missing operator | Confirm CLI derived the same winners (seed + tickets) and that submissions succeeded | Replay submissions, inspect `TicketSubmitted` logs, retry with correct ticket IDs | + ## Best practices -- **Stagger ticket top-ups**: replenish balances ahead of time to avoid gas spikes right before a - request window. -- **Alert on missed submissions**: set log-based alerts when `NodeNotEligible` or - `SubmissionWindowClosed` appears. -- **Batch networks**: if you operate on multiple chains, keep per-chain ETK balances and run - independent CLI supervisors so a congested chain does not block others. +- **Stagger ticket top-ups** to avoid last-minute gas spikes. +- **Alert on missed submissions** so humans can intervene before committee deadlines. +- **Batch networks** by running separate CLI supervisors per chain; congestion on one network should + not block another. +- **Track governance knobs** like `sortitionSubmissionWindow`, `ticketPrice`, and + `licenseRequiredBond` so automation adapts when values change. + +For deeper visuals, skim `crates/sortition/README` or the ciphernodes architecture docs; they mirror +the same deterministic score-based flow described here. From 2d08a205d3e62bc9ae1bc14dc083330d5e3e28ba Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Sat, 15 Nov 2025 16:34:10 +0500 Subject: [PATCH 03/19] chore: update docs --- docs/pages/ciphernode-operators.mdx | 96 ++++++++++++++--------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/pages/ciphernode-operators.mdx b/docs/pages/ciphernode-operators.mdx index 9e2b1bee40..a8ce6f8fdc 100644 --- a/docs/pages/ciphernode-operators.mdx +++ b/docs/pages/ciphernode-operators.mdx @@ -5,10 +5,10 @@ description: 'How to bond, configure, and operate Ciphernodes on the Enclave net # Ciphernode Operators -Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key shares, -and keep the Enclave network alive. This guide walks through the economic requirements, on-chain -lifecycle, CLI workflow, networking expectations, and production deployment patterns for running a -Ciphernode. +Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key +shares, and keep the Enclave network alive. This guide walks through the economic requirements, +on-chain lifecycle, CLI workflow, networking expectations, and production deployment patterns for +running a Ciphernode. ## Role overview @@ -27,19 +27,17 @@ configured chains simultaneously. ## Contract references -| Contract | Sepolia address | Notes | -| --- | --- | --- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | -| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | +| Contract | Sepolia address | Notes | +| ------------------------ | -------------------------------------------- | -------------------------------- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | +| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | -> ⚠️ Always confirm the latest addresses in -> `packages/enclave-contracts/deployed_contracts.json` or your deployment output before funding a -> node. Addresses differ per network. +> ⚠️ Always confirm the latest addresses from the docs. Addresses differ per network. ## Economics & staking @@ -68,8 +66,8 @@ Tickets control a node's probability of selection via sortition. License bonds are denominated in ENCL. Operators must keep at least 80% of `licenseRequiredBond` bonded to remain `active`. -SlashingManager penalties can remove both ticket balances and license bonds, and may ban an operator. -Appeals are time-bound by the policy's `appealWindow`. +SlashingManager penalties can remove both ticket balances and license bonds, and may ban an +operator. Appeals are time-bound by the policy's `appealWindow`. Rewards (any ERC20) are pushed by the configured `rewardDistributor` through `BondingRegistry.distributeRewards`. Only registered operators receive payouts. @@ -116,19 +114,19 @@ enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS ``` This creates `~/.config/enclave/config.yaml` (or the path you pass with `--config`). Most operators -instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass it -with `--config /path/to/config.yaml` on every command. +instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass +it with `--config /path/to/config.yaml` on every command. ### Manage credentials -| Secret | Command | Notes | -| --- | --- | --- | -| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | -| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | -| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for aggregators or if the node submits committee txs | +| Secret | Command | Notes | +| ---------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------- | +| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | +| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | +| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for aggregators or if the node submits committee txs | -The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config sets -those flags. +The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config +sets those flags. ### Run nodes @@ -141,8 +139,9 @@ enclave nodes down # stop everything enclave nodes purge # wipe local RocksDB + secrets (irreversible) ``` -To run a single node profile outside the supervisor, use `enclave start --config /path/to/config.yaml`. -Pass peers with `--peer /dns4/example.com/udp/9091/quic-v1` to override the config at runtime. +To run a single node profile outside the supervisor, use +`enclave start --config /path/to/config.yaml`. Pass peers with +`--peer /dns4/example.com/udp/9091/quic-v1` to override the config at runtime. ## Networking & configuration @@ -150,25 +149,25 @@ Every node section in `enclave.config.yaml` defines how the CLI spawns that inst ```yaml node: - address: "0x7099…79C8" + address: '0x7099…79C8' quic_port: 9201 peers: - - "/dns4/aggregator1.example.com/udp/9094/quic-v1" + - '/dns4/aggregator1.example.com/udp/9094/quic-v1' autonetkey: true autopassword: true chains: - name: sepolia - rpc_url: "wss://ethereum-sepolia.publicnode.com" + rpc_url: 'wss://ethereum-sepolia.publicnode.com' contracts: enclave: - address: "0x1E8B…FAa6" + address: '0x1E8B…FAa6' deploy_block: 9615399 ciphernode_registry: - address: "0x11F6…0b1C7" + address: '0x11F6…0b1C7' bonding_registry: - address: "0x5636…406E3" + address: '0x5636…406E3' fee_token: - address: "0xB58B…4De0" + address: '0xB58B…4De0' ``` Notes: @@ -194,8 +193,9 @@ The repository ships a Docker Swarm example under `deploy/` that you can adapt: "network_private_key": "0x…" } ``` -- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands (`enclave password set`, - `enclave net keypair set`, `enclave wallet set`), then execs `enclave start -v` +- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands + (`enclave password set`, `enclave net keypair set`, `enclave wallet set`), then execs + `enclave start -v` This pattern is also useful for Kubernetes Jobs or systemd units: mount a config, mount an encrypted secret bundle, run the entrypoint. @@ -218,22 +218,22 @@ secret bundle, run the entrypoint. - **Rewards**: Watch for `RewardDistributed` (BondingRegistry) logs. Ensure the operator wallet can receive the reward token. - **Slashing**: `SlashingManager` proposals reference reason codes. Operators should monitor - `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is not - required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. + `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is + not required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. - **Exits**: `deregisterOperator()` burns tickets immediately and queues withdrawals. The exit queue tracks amounts per operator; call `pendingExits(address)` or `previewClaimable(address)` to view status. ## Troubleshooting -| Symptom | Checks | -| --- | --- | -| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | -| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | -| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | -| Sortition submissions fail | Node must be registered + active *before* `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | -| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | -| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | +| Symptom | Checks | +| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | +| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | +| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | +| Sortition submissions fail | Node must be registered + active _before_ `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | +| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | +| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | Maintaining high uptime, redundant networking, and alerting on contract events are the best ways to protect your stake. Use the CLI supervisors plus infrastructure automation to ensure secrets and From faf96205116c3ebb1a0b00592705ca1eb70b4906 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 19 Nov 2025 19:40:07 +0500 Subject: [PATCH 04/19] chore: update docs --- docs/pages/ciphernode-operators.mdx | 18 +- docs/pages/ciphernode-operators/_meta.json | 5 +- .../pages/ciphernode-operators/operations.mdx | 293 ++++++++++++------ docs/pages/ciphernode-operators/scenarios.mdx | 82 ----- 4 files changed, 204 insertions(+), 194 deletions(-) delete mode 100644 docs/pages/ciphernode-operators/scenarios.mdx diff --git a/docs/pages/ciphernode-operators.mdx b/docs/pages/ciphernode-operators.mdx index a8ce6f8fdc..461a1a8211 100644 --- a/docs/pages/ciphernode-operators.mdx +++ b/docs/pages/ciphernode-operators.mdx @@ -14,7 +14,7 @@ running a Ciphernode. Ciphernodes are expected to: -- Maintain an online QUIC/libp2p endpoint and participate in the event bus +- Maintain an online endpoint and participate in the event bus - Bond license collateral (ENCL) and hold tickets (stablecoin-backed ETK) to earn committee slots - Submit tickets on-chain during sortition and publish committee key material - Produce decryption shares for every E3 the node was selected to serve @@ -119,11 +119,11 @@ it with `--config /path/to/config.yaml` on every command. ### Manage credentials -| Secret | Command | Notes | -| ---------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------- | -| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | -| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | -| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for aggregators or if the node submits committee txs | +| Secret | Command | Notes | +| ---------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | +| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | +| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | +| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for the node to submit on-chain txs | The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config sets those flags. @@ -136,12 +136,12 @@ enclave nodes ps # list process status enclave nodes status cn1 # query single node enclave nodes restart cn1 # restart one node enclave nodes down # stop everything -enclave nodes purge # wipe local RocksDB + secrets (irreversible) +enclave nodes purge # wipe local db + secrets (irreversible) ``` To run a single node profile outside the supervisor, use `enclave start --config /path/to/config.yaml`. Pass peers with -`--peer /dns4/example.com/udp/9091/quic-v1` to override the config at runtime. +`--peer /dns4/bootstrap.enclave.gg/udp/5901/quic-v1` to override the config at runtime. ## Networking & configuration @@ -152,7 +152,7 @@ node: address: '0x7099…79C8' quic_port: 9201 peers: - - '/dns4/aggregator1.example.com/udp/9094/quic-v1' + - '/dns4/bootstrap.enclave.gg/udp/5901/quic-v1' autonetkey: true autopassword: true chains: diff --git a/docs/pages/ciphernode-operators/_meta.json b/docs/pages/ciphernode-operators/_meta.json index 1e75cb4c83..f9a426696c 100644 --- a/docs/pages/ciphernode-operators/_meta.json +++ b/docs/pages/ciphernode-operators/_meta.json @@ -9,12 +9,9 @@ "title": "Tickets & Sortition" }, "operations": { - "title": "Operations & Responsibilities" + "title": "Running a Ciphernode" }, "exits-and-slashing": { "title": "Exits, Rewards & Slashing" - }, - "scenarios": { - "title": "Runbook Scenarios" } } diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx index 9489e76104..9027c2a891 100644 --- a/docs/pages/ciphernode-operators/operations.mdx +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -1,136 +1,231 @@ --- -title: 'Operations & Responsibilities' +title: 'Running a Ciphernode' --- -# Operations & Responsibilities +# Running a Ciphernode -Staying online matters as much as bonding. Use this checklist to manage daily duties, networking, -and deployment automation. +This guide walks you through setting up and running a ciphernode, then explains the complete +computation flow from E3 request to plaintext decryption. -## Daily responsibilities +## Setup: Initialize Your Ciphernode -- Watch `enclave nodes ps` and contract events for liveness -- Keep RPC endpoints funded and redundant. -- Rotate secrets and backups on a defined cadence. -- Capture logs for sortition submissions, key publication, and decryption shares. - -## When you're selected for a committee - -1. **Keyshare generation** - - The CLI logs `jobs::selected` when `CommitteeFinalized` includes your operator address. - - Verify `~/.local/share/enclave/jobs//` holds encrypted keyshare material. -2. **Public key aggregation** - - Wait for every member to publish their share; the CLI automatically calls `publishCommittee` once the threshold is met. - - Monitor for `CommitteePublished` and accompanying CLI logs. -3. **Ciphertext + decryption flow** - - Subscribe to `CiphertextOutputPublished` and `PlaintextOutputPublished`. - - Run `enclave jobs status ` to check whether decryption shares were sent. - -Missing any of these steps is the fast path to slashing. Keep short-lived dashboards for the -currently active E3 IDs so you can intervene manually if automation stalls. - -## CLI workflow +Start by running `enclave init` to create the initial configuration: ```bash -# Start all nodes defined in config -enclave nodes up --detach - -# Check status -enclave nodes ps - -# Inspect a specific node -enclave nodes status cn1 - -# Restart a node -enclave nodes restart cn1 - -# Stop everything -enclave nodes down - -# Wipe state (irreversible) -enclave nodes purge +enclave init ``` -To run a single node profile manually: +This command will: -```bash -enclave start --config /path/to/enclave.config.yaml --peer /dns4/bootstrap.enclave.gg/udp/9091/quic-v1 -``` +- Create `~/.config/enclave/config.yaml` with your node configuration +- Generate a network keypair in `~/.config/enclave/key` +- Set up the data directory at `~/.local/share/enclave/` + +During initialization, you'll be prompted for: -Flags such as `--autowallet` and `--autonetkey` will prompt-less configure secrets when the config -contains `autowallet: true` and siblings. +- Your Ethereum address (the address that will participate in committees) +- A password to encrypt sensitive data +- RPC URL for the chain you want to connect to -## Job state cheat sheet +## Configuration -| State | Trigger | What to verify | -| --- | --- | --- | -| `Selected` | Committee finalized | `enclave jobs list` shows new entry | -| `KeyshareGeneration` | CLI deriving PVSS shares | Disk has encrypted secret + public share | -| `WaitingForCiphertext` | Key material ready | Node staying synced to event stream | -| `Decrypting` | Ciphertext output event received | Decryption share stored + submitted | -| `Completed` | Plaintext emitted | Rewards monitoring sees participation | +After initialization, edit your `~/.config/enclave/config.yaml` to configure: -Use `enclave jobs details ` for deep dives or to reprint diagnostics when coordinating with -support/governance. +### 1. Contract Addresses -## Configuration reference +Update the contract addresses to match the network you're connecting to: ```yaml -node: - address: "0x7099…79C8" - quic_port: 9201 - peers: - - "/dns4/aggregator1.example.com/udp/9094/quic-v1" - autonetkey: true - autopassword: true - role: - type: aggregator chains: - name: sepolia - rpc_url: "wss://ethereum-sepolia.publicnode.com" + rpc_url: 'wss://ethereum-sepolia.publicnode.com' contracts: enclave: - address: "0x1E8B…FAa6" + address: '0x1E8B…FAa6' deploy_block: 9615399 ciphernode_registry: - address: "0x11F6…0b1C7" + address: '0x11F6…0b1C7' bonding_registry: - address: "0x5636…406E3" + address: '0x5636…406E3' fee_token: - address: "0xB58B…4De0" + address: '0xB58B…4De0' +``` + +### 2. Bootstrap Peers + +Add at least one bootstrap peer to join the network: + +```yaml +node: + address: '0xYourAddress' + quic_port: 9201 + peers: + - '/dns4/bootstrap.enclave.gg/udp/9091/quic-v1' + autonetkey: true + autopassword: true ``` -Key notes: +### 3. Set Your Wallet -- Provide at least one bootstrap `peer`. Operate your own static peer for redundancy. -- Open `quic_port` over UDP in firewalls and security groups. -- Override `data_dir` / `config_dir` if running under non-standard users or containers. +Configure your private key to sign transactions: -## Deployment manifests & secrets +```bash +enclave wallet set --private-key "0xYourPrivateKey" +``` -The `deploy/` directory includes a Docker Swarm example: +**Warning:** Never share your private key. Keep it secure. -- `cn*.yaml` and `agg.yaml` template addresses and RPC URLs -- `docker-compose.yml` runs multiple Ciphernodes plus an aggregator -- Secret bundles follow: +## Starting Your Node -```json -{ - "password": "changeme", - "private_key": "0x…", - "network_private_key": "0x…" -} +Once configured, start your ciphernode: + +```bash +enclave start ``` -`ciphernode-entrypoint.sh` loads the config, injects secrets via `enclave password/net keypair/wallet`, -then runs `enclave start -v`. Reuse this pattern for Kubernetes Jobs, Nomad, or systemd units. +Your node will: + +- Connect to the bootstrap peer(s) +- Subscribe to blockchain events +- Begin participating in sortition when E3s are requested + +## The Complete E3 Flow + +Here's what happens when an E3 (Encrypted Execution Environment) computation is requested: + +### Phase 1: E3 Request + +1. Someone calls `request()` on the Enclave contract with computation parameters +2. A new E3 ID is created with a random seed +3. The contract emits an `E3Requested` event + +### Phase 2: Committee Selection (Sortition) + +1. **Ticket Submission**: Your ciphernode listens for `E3Requested` events +2. **Score Calculation**: Your node calculates a sortition score based on: + - The E3 seed + - Your tickets/stake + - Your node's tickets +3. **Committee Finalization**: The top N nodes with the best scores are selected +4. If selected, you'll receive a `CommitteeFinalized` event with your party ID + +### Phase 3: Keyshare Generation + +When your node is selected for a committee: + +1. **Generate Secret**: Your node generates a secret key share and public key share +2. **Publish Keyshare**: The public key share is broadcast via libp2p and published onchain +3. **Storage**: The secret is encrypted and stored in `~/.local/share/enclave/jobs//` + +### Phase 4: Public Key Aggregation + +1. **Collect Keyshares**: An aggregator node collects all N public key shares from the committee +2. **Aggregate**: Once all shares are received, they're combined into a single public encryption key +3. **Publish**: The aggregated public key is published onchain via `publishPublicKey()` +4. The contract emits `PublicKeyAggregated` event +5. The E3 is now activated and ready to receive encrypted inputs + +### Phase 5: Input Window + +During this phase: + +1. Data providers encrypt their inputs using the aggregated public key +2. They submit encrypted data to the contract via `publishInput()` +3. The E3 Program validates each input +4. Input hashes are added to a Merkle tree onchain + +### Phase 6: Computation + +1. **Deadline Passes**: Once the input window closes, computation can begin +2. **Compute Provider Execution**: A compute provider (or E3 program) retrieves all encrypted inputs +3. **FHE Computation**: The computation runs entirely on encrypted data +4. **Output Generation**: The result is produced as encrypted ciphertext with a ZK proof + +### Phase 7: Ciphertext Publishing + +1. The compute provider calls `publishCiphertextOutput()` with the encrypted result and proof +2. The contract verifies the proof +3. Contract emits `CiphertextOutputPublished` event +4. All committee members are notified to begin decryption + +### Phase 8: Decryption Share Generation + +When your ciphernode receives `CiphertextOutputPublished`: + +1. **Load Secret**: Your node retrieves the encrypted secret key share from storage +2. **Decrypt Secret**: The secret is decrypted using your node's cipher +3. **Generate Share**: Your node creates a decryption share by partially decrypting the ciphertext +4. **Publish Share**: The decryption share is broadcast via libp2p and published onchain +5. Your node emits `DecryptionshareCreated` event + +### Phase 9: Plaintext Aggregation + +1. **Collect Shares**: An aggregator node collects decryption shares from committee members +2. **Threshold Met**: Once M-of-N threshold shares are received (e.g., 3 of 5) +3. **Aggregate**: The aggregator combines the shares to decrypt the final plaintext +4. **Publish Result**: The plaintext is published onchain via `publishPlaintextOutput()` +5. Contract emits `PlaintextOutputPublished` event +6. **Rewards**: Committee members receive their rewards for successful completion + +### Phase 10: Completion + +1. The plaintext output is now available onchain +2. Anyone can query `getE3()` to retrieve the result +3. Your node clears the secret from memory +4. The E3 round is complete + +## Monitoring Your Node + +### Check Node Status + +```bash +# View logs +journalctl -u enclave -f + +# Check if your node is running +ps aux | grep enclave +``` + +### What to Watch For + +Your node logs will show: + +- `E3Requested` - New computation request detected +- `TicketGenerated` - Your sortition ticket was calculated +- `CiphernodeSelected` - You were selected for a committee +- `KeyshareCreated` - Your keyshare was generated +- `PublicKeyAggregated` - Committee public key is ready +- `CiphertextOutputPublished` - Time to generate decryption share +- `DecryptionshareCreated` - Your decryption share was published +- `PlaintextAggregated` - Final result is available + +## Important Notes + +### Stay Online + +- Your node must be online and responsive during all phases of an E3 you're selected for +- Missing keyshare publication or decryption share submission may result in slashing + +### Network Connectivity + +- Ensure your `quic_port` (UDP) is accessible from the internet +- Maintain stable connections to bootstrap peers +- Consider running your own bootstrap node for redundancy + +### RPC Reliability + +- Use reliable RPC endpoints (consider running your own node) +- Have backup RPC URLs configured +- Monitor RPC connectivity and switch if needed + +### Data Persistence + +- The `~/.local/share/enclave/` directory contains critical job data +- Back up this directory regularly +- Do not delete data for active E3s -## Monitoring & alerting +### Key Security -- Subscribe to `PlaintextOutputPublished`, `CiphertextOutputPublished`, and `E3Activated` to ensure - duties progress. -- Track CLI logs for `sortition::submitted`, `decryption::share_published`, and errors. -- Export Prometheus metrics from your infrastructure layer (CPU, bandwidth, disk) since the CLI - currently logs to stdout. -- Add alerts for `jobs::error`, `NodeNotEligible`, or `ExitNotReady` so you can correct course - before a slash happens. +- Your network keypair is stored in `~/.config/enclave/key` +- Your wallet private key is encrypted in the config +- Never share these files or your private keys diff --git a/docs/pages/ciphernode-operators/scenarios.mdx b/docs/pages/ciphernode-operators/scenarios.mdx deleted file mode 100644 index 4e9ad7ff9a..0000000000 --- a/docs/pages/ciphernode-operators/scenarios.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: 'Runbook Scenarios' ---- - -# Runbook Scenarios - -Borrowed from incident playbooks across Ritual/Fhenix-style docs, these scenarios show how to apply -Enclave operator procedures under real conditions. - -## Scenario 1 — New operator onboarding - -1. Follow [Registration & Licensing](./registration) to bond ENCL and mint tickets. -2. Use `enclave config-set` with production RPC URLs and bootstrap peers. -3. Dry-run `enclave nodes up` against Sepolia before pointing at mainnet. -4. Set alerts for `isActive` changes and missed sortition submissions. - -## Scenario 2 — Ticket rebalance before a major request - -1. Check `BondingRegistry.ticketPrice()` and current balances. -2. Approve + add tickets at least one block before the anticipated request. -3. Verify snapshots with `bondingRegistry.availableTickets(operator)`. -4. Confirm the CLI logs show `sortition::submitted` for the new ticket numbers. - -## Scenario 3 — Handling a slashing proposal - -1. Fetch the policy via `SlashingManager.reasonPolicies(reason)`. -2. Gather logs around the alleged offense (sortition miss, share mismatch, etc.). -3. File `fileAppeal` if the policy's `requiresProof` is false and `appealWindow > 0`. -4. Increase monitoring frequency to avoid cascading penalties. - -## Scenario 4 — Planned maintenance / temporary exit - -1. Stop nodes gracefully with `enclave nodes down`. -2. If downtime > exit delay, call `deregisterOperator` and reclaim collateral later. -3. Otherwise, keep tickets + license bonded but announce maintenance to aggregators so committee - planners know to expect fewer submissions. -4. After maintenance, double-check config secrets and run `enclave nodes up`. - -## Scenario 5 — Expanding to multiple chains - -1. Duplicate the `chains` section inside `enclave.config.yaml` with new RPC URLs and contract - addresses. -2. Allocate fresh ticket balances per chain (each registry is independent). -3. Run separate CLI supervisors or containers to keep blast radius small. -4. Use labeling/metrics to distinguish logs per chain. - -Adapt these scenarios to your internal runbooks and share improvements via PRs so the community keeps -leveling up—just like the best competitor docs do. - -## Lifecycle quick reference - -| State | How you get here | How to leave | -| --- | --- | --- | -| Unbonded | Fresh wallet, zero ENCL locked | `bondLicense(amount)` | -| Licensed | Bonded ≥ required amount but not registered | `registerOperator()` | -| Registered | In the IMT but maybe inactive | `addTicketBalance()` (become active) or `deregisterOperator()` | -| Active | Registered + ticket + bond minimums met | `removeTicketBalance()` / `unbondLicense()` (drops to inactive) | -| Inactive | Registered but missing tickets/bond | Top up tickets/bond | -| ExitPending | `deregisterOperator()` called | `claimExits()` (finish) or `registerOperator()` (cancel) | - -Use this alongside the state diagram in the overview page when debugging transitions. - -## Troubleshooting cheat sheet - -| Symptom | Checks | Fix | -| --- | --- | --- | -| Node fails to start | `enclave config show`, RPC connectivity, wallet + password presence | Re-run `enclave init`, reset secrets, verify WebSocket URL | -| No events flowing | RPC health, `enclave nodes ps`, firewall rules | Switch RPC, restart CLI supervisor, ensure websocket endpoint | -| Keyshare generation fails | Ensure you were actually selected, disk space, permissions on data dir | Restart node after clearing corrupt job folder, re-import secrets | -| Decryption stalls | Confirm `CiphertextOutputPublished` fired, job still active, secret share available | Replay event logs, rehydrate job metadata, escalate before appeal window closes | - -## Monitoring commands - -```bash -enclave nodes ps -enclave jobs list -enclave jobs status -cast call $BONDING "isActive(address)" $OPERATOR -``` - -Pipe these into your favorite exporter or watch scripts so you notice issues before slashing -proposals land. From 7b332e67b0af6ed760478ee8e0ab508252296f75 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 19 Nov 2025 19:40:37 +0500 Subject: [PATCH 05/19] chore: update docs --- docs/pages/ciphernode-operators/_meta.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/ciphernode-operators/_meta.json b/docs/pages/ciphernode-operators/_meta.json index f9a426696c..cbb6227cc7 100644 --- a/docs/pages/ciphernode-operators/_meta.json +++ b/docs/pages/ciphernode-operators/_meta.json @@ -5,12 +5,12 @@ "registration": { "title": "Registration & Licensing" }, - "tickets-and-sortition": { - "title": "Tickets & Sortition" - }, "operations": { "title": "Running a Ciphernode" }, + "tickets-and-sortition": { + "title": "Tickets & Sortition" + }, "exits-and-slashing": { "title": "Exits, Rewards & Slashing" } From 8d28b2e7997c52ab61529549fbdeb0ab93782a51 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 2 Dec 2025 03:42:52 +0500 Subject: [PATCH 06/19] chore: update docs --- docs/pages/CRISP/setup.mdx | 358 +++++------------- .../exits-and-slashing.mdx | 4 +- .../pages/ciphernode-operators/operations.mdx | 13 +- .../ciphernode-operators/registration.mdx | 6 +- docs/pages/compute-provider.mdx | 25 +- docs/pages/write-secure-program.mdx | 5 +- examples/CRISP/Readme.md | 57 +-- examples/CRISP/program/README.md | 6 +- tests/integration/enclave.config.yaml | 10 +- 9 files changed, 184 insertions(+), 300 deletions(-) diff --git a/docs/pages/CRISP/setup.mdx b/docs/pages/CRISP/setup.mdx index ec7059bb4d..5bac24d89e 100644 --- a/docs/pages/CRISP/setup.mdx +++ b/docs/pages/CRISP/setup.mdx @@ -13,10 +13,12 @@ contracts, frontend applications, and secure computation components. The setup includes the following: -- **CRISP contracts**: Smart contracts located in the `contracts/` directory -- **Applications**: Frontend, server, and computation programs in the `apps/` directory -- **Ciphernodes**: Distributed nodes managed through the Enclave CLI -- **Development environment**: Hardhat + Foundry hybrid setup +- **CRISP contracts**: Smart contracts located in the `packages/crisp-contracts/` directory +- **Client**: React frontend application in the `client/` directory +- **Server**: Rust coordination server in the `server/` directory +- **Program**: RISC Zero computation program in the `program/` directory +- **Ciphernodes**: Distributed nodes managed through the Enclave CLI via `enclave.config.yaml` +- **Development environment**: Hardhat for contracts, Cargo for Rust components ## Prerequisites @@ -49,88 +51,73 @@ You can add Metamask as extension to your browser following the official You need to install Rust and Foundry first. After installation, restart your terminal. ```sh +# Install Rust +curl https://sh.rustup.rs -sSf | sh -```bash -# Prepare the workspace (installs deps, builds server binaries, copies .env files, ensures enclave CLI) -VITE_E3_PROGRAM_ADDRESS=0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44 # Default E3 program address from anvil +# Install Foundry +curl -L https://foundry.paradigm.xyz | bash +foundryup +``` -# Launch Hardhat, deploy contracts, start ciphernodes, the program server, coordination server, and UI -pnpm dev:up +### Install RISC Zero Toolchain -# Rebuild client/server/crates without re-running setup each time -pnpm dev:build +Install `rzup` for the `cargo-risczero` toolchain: -# (Optional) Recompile Noir circuits + verifiers -pnpm compile:circuit +```sh +# Install rzup +curl -L https://risczero.com/install | bash -# Open the interactive CLI to start rounds -pnpm cli +# Install RISC Zero toolchain +rzup install cargo-risczero ``` -`dev:up` runs `scripts/dev.sh`, which in turn: +Verify the installation: -- Starts the Hardhat node (`packages/crisp-contracts`) -- Deploys the full contract stack (Enclave, CRISPProgram, validators, registries) -- Boots ciphernodes using the provided `enclave.config.yaml` -- Launches the program server (RISC Zero) -- Starts the coordination server (Rust) and waits for it to expose port `4000` -- Starts the client once the server and nodes are ready -VITE_SEMAPHORE_ADDRESS=0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE +```sh +cargo risczero --version ``` -### Server - -```bash -ENCLAVE_ADDRESS="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" -CIPHERNODE_REGISTRY_ADDRESS="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" -NAIVE_REGISTRY_FILTER_ADDRESS="0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" -E3_PROGRAM_ADDRESS="0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44" # CRISPProgram Contract Address -``` +## Quick Start -These address will be displayed after successfully running the `pnpm dev:up` command in a log that -will look like the following: +The simplest way to run CRISP is: ```bash -[DEPLOY] Script ran successfully. -[DEPLOY] -[DEPLOY] == Logs == -[DEPLOY] Deploying on ChainID 31337 -[DEPLOY] Using config profile: custom -[DEPLOY] Using MockRISC0Verifier -[DEPLOY] Deployed MockRISC0Verifier to 0x0B306BF915C4d645ff596e518fAf3F9669b97016 -[DEPLOY] Enclave Address: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 -[DEPLOY] Verifier Address: 0x0B306BF915C4d645ff596e518fAf3F9669b97016 -[DEPLOY] Deployed SemaphoreNoirVerifier to 0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1 -[DEPLOY] Deployed Semaphore to 0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE -[DEPLOY] Deployed CRISPCheckerFactory to 0x68B1D87F95878fE05B998F19b66F4baba5De1aed -[DEPLOY] Deployed CRISPPolicyFactory to 0x3Aa5ebB10DC797CAC828524e59A333d0A371443c -[DEPLOY] Deployed HonkVerifier to 0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1 -[DEPLOY] Deployed CRISPProgram to 0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44 -[DEPLOY] Enabled E3 Program on Enclave +# Install dependencies and build everything +pnpm dev:setup + +# Start all services (Hardhat, contracts, ciphernodes, program server, coordination server, and UI) +pnpm dev:up ``` -If you find any inconsistency with the addresses on the environment, you must update them and run -the script again (they must match). +`dev:up` runs `scripts/dev.sh`, which: -## Quick Start +1. Starts the Hardhat node in `packages/crisp-contracts` +2. Deploys all contracts (Enclave, CRISPProgram, verifiers, registries) via `scripts/crisp_deploy.sh` +3. Starts ciphernodes using `enclave.config.yaml` via `scripts/dev_cipher.sh` +4. Launches the program server (RISC Zero) via `scripts/dev_program.sh` +5. Starts the coordination server (Rust) via `scripts/dev_server.sh` on port `4000` +6. Starts the React client via `scripts/dev_client.sh` on port `3000` -The fastest way to get CRISP running is using the scripts provided in the `scripts/` directory: +All services run concurrently and will automatically restart if needed. + +### Additional Commands ```bash -# Setup and build the development environment -pnpm dev:setup +# Recompile Noir circuits and generate verifiers +pnpm compile:circuit -# Start all services (Hardhat, Ciphernodes, Applications) -pnpm dev:up +# Open the interactive CLI to start voting rounds +pnpm cli + +# Run end-to-end tests +pnpm test:e2e ``` -This will start all CRISP components: +### Deployed Contract Addresses -- Hardhat (local blockchain) -- Deploy all contracts -- Compile all ZK circuits -- Ciphernodes network -- CRISP applications (server, client) +The contract addresses are automatically configured in `enclave.config.yaml` and the server `.env` file. After running `pnpm dev:up`, the deployment logs will show the deployed contract addresses, which are also saved in `packages/crisp-contracts/deployed_contracts.json`. + +### Using the Application Once everything is running, you can: @@ -144,226 +131,89 @@ Once everything is running, you can: 5. Open a new terminal, run `pnpm cli` and start a new E3 Round. 6. Refresh and interact with the round following the Client interface. -## Manual Start - -If you prefer to set up CRISP manually or want to understand each component: +## Configuration -### Setting Up the project +### Ciphernode Configuration -1. Navigate to the root directory: +The `enclave.config.yaml` file in the CRISP root directory configures the ciphernode network. By default, it runs in development mode with fake proofs for fast local development: - ```sh - cd examples/CRISP - ``` - -2. Install dependencies: - - ```sh - pnpm install - ``` - -### Setting Up the Web App - -To set up the CRISP dApp in your local environment, follow these steps: - -1. Navigate to the `client` directory: - - ```sh - cd examples/CRISP/client - ``` - -2. Start the development server: - - ```sh - pnpm dev - ``` - -### Setting Up the CRISP Server - -Setting up the CRISP server involves several components, but this guide will walk you through each -step. - -### Step 1: Start a Local Testnet with Anvil - -```sh -anvil +```yaml +program: + dev: true # Uses fake proofs (fast for development) ``` -Keep Anvil running in the terminal, and open a new terminal for the next steps. - -### Step 2: Setting Up the Ciphernodes - -1. Clone the [Enclave Repo](https://github.com/gnosisguild/enclave): - - ```sh - git clone https://github.com/gnosisguild/enclave.git - ``` - -2. Navigate to the `enclave-contracts` directory: - - ```sh - cd enclave/packages/enclave-contracts - ``` - -3. Install dependencies: - - ```sh - pnpm install - ``` - -4. Delete any previous local deployment (if any): - - ```sh - rm -rf deployments/localhost/ - ``` - -5. Deploy the contracts on the local testnet: - - ```sh - pnpm deploy:mocks --network localhost - ``` - -After deployment, you will see the addresses for the following contracts: - -- Enclave -- Ciphernode Registry -- Naive Registry Filter -- Mock Input Validator -- Mock E3 Program -- Mock Decryption Verifier -- Mock Compute Provider - -Note down the first four addresses as they will be needed to configure `risc0`, `local_testnet` and -the `server`. - -### Step 3: Deploy the RISC Zero Contracts - -> Please note that this step is optional for development only. You can run the program server in dev -> mode which does not use Risc0. - -1. Navigate to the `CRISP/lib/risc0-ethereum` directory. - ---- - -**Faster Proving w/ Bonsai** - -The following steps are optional. You can config -[Bonsai](https://dev.risczero.com/api/generating-proofs/remote-proving) for faster proving. - -- Set up environment variables by creating a `.cargo` directory and `config.toml` file: - - ```sh - mkdir .cargo && cd .cargo && touch config.toml - ``` +### Boundless Configuration (Production Proving) + +For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update `enclave.config.yaml`: + +```yaml +program: + dev: false # Disable dev mode to use real proofs + risc0: + risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode + boundless: + rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" # RPC endpoint + private_key: "YOUR_PRIVATE_KEY" # Wallet with funds for proving + pinata_jwt: "YOUR_PINATA_JWT" # Required for uploading programs to IPFS + program_url: "https://gateway.pinata.cloud/ipfs/YOUR_CID" # Pre-uploaded program URL + onchain: true # true = onchain requests, false = offchain +``` -- Add the following configuration to `config.toml`: +> **_Note:_** For production proving with Boundless, you need: +> - An RPC endpoint (e.g., Infura, Alchemy) with funds +> - A private key with sufficient ETH/tokens for proof generation +> - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) +> - Pre-uploaded program URL to avoid uploading the ~40MB program at runtime - > **_Note:_** _This requires having access to a Bonsai API Key. To request an API key - > [complete the form here](https://bonsai.xyz/apply)._ +#### Uploading Your Program to IPFS - ```toml - [env] - BONSAI_API_KEY="your_api_key" - BONSAI_API_URL="your_api_url" - ``` +When you make changes to the guest program in `program/`, you need to upload it to IPFS to get a program URL: ---- +1. First, configure your Pinata JWT in `enclave.config.yaml` (as shown above) -2. In the `risc0/script` directory, update the `config.toml` with the deployed contract addresses. - The following configuration is based on default deployment addresses using local Anvil node: +2. Build and upload your program: - ```toml - [profile.custom] - chainId = 31337 - riscZeroVerifierAddress = "0x0000000000000000000000000000000000000000" - enclaveAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + ```bash + # This compiles the guest program and uploads it to IPFS via Pinata + enclave program upload --pinata-jwt YOUR_PINATA_JWT ``` -3. Export the ETH_WALLET_PRIVATE_KEY environment variable (Anvil's default private key): +3. The command will output an IPFS hash like `QmXxx...`. Update your `enclave.config.yaml` with the full URL: - ```sh - export ETH_WALLET_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + ```yaml + program_url: "https://gateway.pinata.cloud/ipfs/QmXxx..." ``` -4. Deploy the contracts: +> **_Important:_** Every time you modify the guest program code in `program/`, you must rebuild and re-upload it to IPFS, then update the `program_url` in your configuration. This ensures Boundless uses your latest program version. - ```sh - forge script --rpc-url http://localhost:8545 --broadcast script/Deploy.s.sol - ``` +### Environment Variables -Note down the `CRISPProgram` contract Address, which will be used as the E3 Program Address. +The `pnpm dev:setup` command automatically creates `.env` files for the server and client from the `.env.example` templates. The server's `.env` file is automatically populated with contract addresses after deployment. -### Step 4: Set up Environment Variables +## Running Individual Components -Create a `.env` file in the `server` directory with the following: +While `pnpm dev:up` runs everything together, you can also run components separately: -```sh -# Private key for the enclave server -PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 -ENCLAVE_SERVER_URL=http://0.0.0.0:4000 -HTTP_RPC_URL=http://127.0.0.1:8545 -PROGRAM_SERVER_URL=http://127.0.0.1:13151 -WS_RPC_URL=ws://127.0.0.1:8545 -CHAIN_ID=31337 - -# Cron-job API key to trigger new rounds -CRON_API_KEY=1234567890 - -# Based on Default Anvil Deployments (Only for testing) -ENCLAVE_ADDRESS="0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" -CIPHERNODE_REGISTRY_ADDRESS="0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9" -NAIVE_REGISTRY_FILTER_ADDRESS="0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9" -E3_PROGRAM_ADDRESS="0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44" # CRISPProgram Contract Address - -# E3 Config -E3_WINDOW_SIZE=40 -E3_THRESHOLD_MIN=1 -E3_THRESHOLD_MAX=2 -E3_DURATION=160 - -# E3 Compute Provider Config -E3_COMPUTE_PROVIDER_NAME="RISC0" -E3_COMPUTE_PROVIDER_PARALLEL=false -E3_COMPUTE_PROVIDER_BATCH_SIZE=4 # Must be a power of 2 -``` - -## Running Ciphernodes - -To run three ciphernodes, use the following command inside the CRISP directory: +```bash +# Start only the Hardhat node +cd packages/crisp-contracts && pnpm hardhat node -```sh +# Start only the ciphernodes (requires Hardhat running) ./scripts/dev_cipher.sh -``` -This script will start the ciphernodes, add the ciphernodes to the registry on chain. +# Start only the program server (requires ciphernodes) +./scripts/dev_program.sh -## Running the CRISP Server +# Start only the coordination server (requires program server) +./scripts/dev_server.sh -To run the CRISP Server, open a new terminal and navigate to the `server` directory. Then, execute -the following command: +# Start only the client (requires coordination server) +./scripts/dev_client.sh -```sh -cargo run --bin server -``` - -## Interacting with CRISP via CLI - -Open a new terminal and navigate to the `server` directory. Then, execute the following command: - -```sh -cargo run --bin cli +# Run the CLI (requires all services) +pnpm cli ``` -Once the CLI client is running, you can interact with the CRISP voting protocol by following these -steps: - -1. Select `CRISP: Voting Protocol (ETH)` from the menu. - -2. To initiate a new CRISP round, choose the option `Initialize new CRISP round`. - -Ensure all services are running correctly and that components are communicating as expected before -starting a new CRISP round. - ## Next Steps Once you have completed the setup, you can proceed to [Running an E3 Program](/CRISP/running-e3) to diff --git a/docs/pages/ciphernode-operators/exits-and-slashing.mdx b/docs/pages/ciphernode-operators/exits-and-slashing.mdx index 7e03bcefe6..cc0ba7c2ab 100644 --- a/docs/pages/ciphernode-operators/exits-and-slashing.mdx +++ b/docs/pages/ciphernode-operators/exits-and-slashing.mdx @@ -88,13 +88,13 @@ Helpful getters: ## Post-exit -- Securely wipe local secrets (`enclave nodes purge` and delete keystores) +- Securely wipe local secrets (`enclave purge-all` to clear caches and databases, delete keystores) - Revoke RPC credentials and firewall openings - Document the exit reason for future audits or compliance ## Slashing prevention checklist -- Keep `enclave jobs list` empty before scheduled maintenance so you do not abandon active work. +- Monitor active jobs before scheduled maintenance to avoid abandoning active work. - Alert on `SlashProposed` events tagged with your operator address. - Archive CLI + RPC logs for every incident; you need them for appeals. - Double-check `isActive` after any ticket removal or license unbond to avoid accidental downtime. diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx index 9027c2a891..0bf1a3ae21 100644 --- a/docs/pages/ciphernode-operators/operations.mdx +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -53,14 +53,14 @@ chains: ### 2. Bootstrap Peers -Add at least one bootstrap peer to join the network: +Add the bootstrap peer to join the network: ```yaml node: address: '0xYourAddress' quic_port: 9201 peers: - - '/dns4/bootstrap.enclave.gg/udp/9091/quic-v1' + - '/dnsaddr/bootstrap.enclave.gg' autonetkey: true autopassword: true ``` @@ -178,12 +178,17 @@ When your ciphernode receives `CiphertextOutputPublished`: ### Check Node Status +View your node's logs depending on how you're running it: + ```bash -# View logs +# If running as a systemd service journalctl -u enclave -f -# Check if your node is running +# If running directly or in a container, check the process ps aux | grep enclave + +# Or check container logs if using Docker +docker logs -f ``` ### What to Watch For diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx index 9ed1dafa44..130e8b2404 100644 --- a/docs/pages/ciphernode-operators/registration.mdx +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -47,7 +47,7 @@ enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS # Store secrets (optional if using automation) enclave password set --password "$PASSWORD" -enclave net keypair generate +enclave net keypair enclave wallet set --private-key $OPERATOR_KEY ``` @@ -86,8 +86,8 @@ deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). - Commit `enclave.config.yaml` alongside deployment manifests - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely -> ℹ️ The CLI supports multiple named wallets. Use `enclave wallet list` to confirm the correct signer -> is active before running bonding transactions. +> The wallet private key is encrypted and stored in the config. Ensure you have set the correct +> operator key with `enclave wallet set` before running bonding transactions. ## One-command bootstrap (optional) diff --git a/docs/pages/compute-provider.mdx b/docs/pages/compute-provider.mdx index e2ee3c0479..19fe453f76 100644 --- a/docs/pages/compute-provider.mdx +++ b/docs/pages/compute-provider.mdx @@ -52,14 +52,14 @@ the [Writing the Secure Process](./write-secure-program.mdx) guide. ### Setup -In this guide, we'll go over setting up [RISC Zero](https://www.risczero.com/) as the CP. +In this guide, we'll go over setting up [RISC Zero](https://www.risczero.com/) with [Boundless](https://docs.beboundless.xyz/) as the CP. -RISC Zero provides a [Foundry template](https://github.com/risc0/risc0-foundry-template) that can be -used to run the Secure Process and create a ZK proof. The template includes a basic program that can +Boundless provides a [Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) that can be +used to run the Secure Process and create a ZK proof using RISC Zero's zkVM. The template includes a basic program that can be used to get started with the smart contract code to verify the proof. -Follow the instructions in the [Foundry template](https://github.com/risc0/risc0-foundry-template) -to setup RISC Zero. +Follow the instructions in the [Boundless Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) +to setup RISC Zero with Boundless. Ensure the following tools are installed: @@ -93,4 +93,17 @@ You can verify the installation was successful by running: cargo risczero --version ``` -Now you're ready to develop and deploy applications using RISC Zero as your CP. +Now you're ready to develop and deploy applications using RISC Zero with Boundless as your CP. + +### Boundless Configuration + +Boundless is a decentralized proving marketplace for RISC Zero programs. Instead of running proofs locally, you can submit them to Boundless for faster, distributed proving. + +To use Boundless: + +1. Get access to an RPC endpoint (e.g., Infura, Alchemy) with funds +2. Obtain a private key with sufficient ETH/tokens for proof generation +3. (Optional) Get a Pinata JWT from [pinata.cloud](https://pinata.cloud) for uploading programs to IPFS +4. Configure your `enclave.config.yaml` as shown in the [CRISP setup guide](/CRISP/setup#boundless-configuration-production-proving) + +For more details, see the [Boundless documentation](https://docs.beboundless.xyz/). diff --git a/docs/pages/write-secure-program.mdx b/docs/pages/write-secure-program.mdx index 34b60cc5bd..2f8d8ea84d 100644 --- a/docs/pages/write-secure-program.mdx +++ b/docs/pages/write-secure-program.mdx @@ -39,7 +39,8 @@ impl ComputeProvider for Risc0Provider { type Output = Risc0Output; fn prove(&self, input: &ComputeInput) -> Self::Output { - // Implement proof generation using RISC Zero / SP1 or any other provider + // Implement proof generation using RISC Zero with Boundless / SP1 or any other provider + // See https://docs.beboundless.xyz/ for production proving // ... } } @@ -59,7 +60,7 @@ environment. Below are the key steps to implement it effectively: 4. **Focus on Computation**: Use the Compute Provider package to handle additional tasks like Merkle tree verification and proof verification, so you can focus on your computation logic. -**Example (Rust with RISC Zero):** +**Example (Rust with RISC Zero + Boundless):** ```rust use fhe::bfv::{BfvParameters, Ciphertext}; diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index 617ba1a100..76dcf2897e 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -204,37 +204,48 @@ After deployment, you will see the addresses for the following contracts: - CRISP Input Validator Factory - CRISP Program -#### Step 3: RISC0 Setup (Optional) - -> Please note that this step is optional for development only. You can run the program server in dev -> mode which does not use Risc0. The smart contracts would have already been deployed at the -> previous step. - ---- +#### Step 3: Configure Boundless (Optional) + +> Please note that this step is optional for development only. By default, the program server runs in dev mode which uses fake proofs for fast local development. + +For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update the `enclave.config.yaml` file in the CRISP root directory: + +```yaml +program: + dev: false # Disable dev mode to use real proofs + risc0: + risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode + boundless: + rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" # RPC endpoint + private_key: "YOUR_PRIVATE_KEY" # Wallet with funds for proving + pinata_jwt: "YOUR_PINATA_JWT" # Required for uploading programs to IPFS + program_url: "https://gateway.pinata.cloud/ipfs/YOUR_CID" # Pre-uploaded program URL + onchain: true # true = onchain requests, false = offchain +``` -**Faster Proving w/ Bonsai** +> **_Note:_** For production proving with Boundless, you need: +> - An RPC endpoint (e.g., Infura, Alchemy) with funds +> - A private key with sufficient ETH/tokens for proof generation +> - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) +> - Pre-uploaded program URL to avoid uploading the ~40MB program at runtime -The following steps are optional. You can config -[Bonsai](https://dev.risczero.com/api/generating-proofs/remote-proving) for faster proving. +**Uploading Your Program to IPFS** -- Set up environment variables by creating a `.cargo` directory and `config.toml` file: +When you make changes to the guest program in `program/`, you need to upload it to IPFS: - ```sh - mkdir .cargo && cd .cargo && touch config.toml - ``` +1. Build and upload your program: -- Add the following configuration to `config.toml`: + ```bash + enclave program upload + ``` - > **_Note:_** _This requires having access to a Bonsai API Key. To request an API key - > [complete the form here](https://bonsai.xyz/apply)._ +2. The command outputs an IPFS hash. Update `enclave.config.yaml` with the full URL: - ```toml - [env] - BONSAI_API_KEY="your_api_key" - BONSAI_API_URL="your_api_url" - ``` + ```yaml + program_url: "https://gateway.pinata.cloud/ipfs/QmXxx..." + ``` ---- +> **_Important:_** Every time you modify the guest program, rebuild and re-upload it to IPFS, then update the `program_url` in your configuration. #### Step 4: Set up Environment Variables diff --git a/examples/CRISP/program/README.md b/examples/CRISP/program/README.md index eed946beb9..63abac4784 100644 --- a/examples/CRISP/program/README.md +++ b/examples/CRISP/program/README.md @@ -18,12 +18,12 @@ graph TD server --HTTP--> program end subgraph thirdparty["3rd PARTY"] - bonsai + boundless end client --"HTTP"--> server - program ---> bonsai + program ---> boundless - bonsai["bonsai (risc0)"] + boundless["boundless (risc0)"] server --"publishInput()"--> evm subgraph evm["EVM"] diff --git a/tests/integration/enclave.config.yaml b/tests/integration/enclave.config.yaml index 4a5481c3a1..629a1bd097 100644 --- a/tests/integration/enclave.config.yaml +++ b/tests/integration/enclave.config.yaml @@ -21,9 +21,13 @@ chains: program: dev: true # risc0: - # risc0_dev_mode: 1 # 0 = real groth16 proofs, 1 = fake proofs (dev mode) - # bonsai_api_key: xxxxxxxxxxxxxxxx - # bonsai_api_url: xxxxxxxxxxxxxxxx + # risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode (fake proofs) + # boundless: + # rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" + # private_key: "PRIVATE_KEY" # Use env vars for secrets + # pinata_jwt: "PINATA_JWT" # For uploading programs + # program_url: "https://gateway.pinata.cloud/ipfs/QmNMRAB7DW43JSmENfzGmD96G6sqaeBBNfTVrrq5WQae3D" # Pre-uploaded program + # onchain: true # true = onchain requests, false = offchain nodes: cn1: From db1c9be8b49a0b48932670f6fa5ff8b90054e1d4 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 9 Dec 2025 07:16:47 +0500 Subject: [PATCH 07/19] chore: update docs --- .../pages/ciphernode-operators/operations.mdx | 123 +++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx index 0bf1a3ae21..109057620c 100644 --- a/docs/pages/ciphernode-operators/operations.mdx +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -7,7 +7,102 @@ title: 'Running a Ciphernode' This guide walks you through setting up and running a ciphernode, then explains the complete computation flow from E3 request to plaintext decryption. -## Setup: Initialize Your Ciphernode +## Deployment paths + +### DAppNode UI (IPFS package) + +If you're already running DAppNode, install the packaged service instead of hand-building +containers: + +1. Open **Packages → Install from IPFS hash** in the DAppNode UI, then paste + `QmeX7jxDFcwbW7kAbs8Tgn5T4vonYxe4WmemUQsaca8xDQ`. This pulls + `enclave-ciphernode.public.dappnode.eth@0.1.0`. +2. After the download finishes, click **Configure** on the package tile to launch the wizard. +3. Fill the wizard fields with the same addresses listed in the contract table on this page. The + following values keep you in-sync with the public Sepolia network: + +| Wizard field | Value / Notes | +| --- | --- | +| `Network` | `sepolia` (mainnet + localhost are also available) | +| `RPC URL` | WebSocket endpoint, e.g. `wss://ethereum-sepolia.publicnode.com` | +| `Node Address` | Operator address funded with ENCL and the stable token (ETK backing) | +| `Private Key` | Matches `Node Address`; stored as a secret in the container | +| `Bootstrap Peers` | `/dnsaddr/bootstrap.enclave.gg` (add more comma-separated peers as needed) | +| `Node Role` | `ciphernode` (switch to `aggregator` only if this host should aggregate plaintext) | +| `Enclave / CiphernodeRegistry / BondingRegistry` | Use the Sepolia addresses from this doc or your deployment artifact | +| `*_DEPLOY_BLOCK` | Block numbers for each contract (Sepolia example: Enclave `9615399`) | +| `ENCRYPTION_PASSWORD`, `NETWORK_PRIVATE_KEY` | Provide values to keep deterministic peer IDs across restarts; leave blank to auto-generate | + +The wizard writes `config.yaml` from `config.template.yaml`, injects your answers as environment +variables, and persists `/data` so restarts do not erase the node database. After the wizard +completes: + +- Click **Start** to boot the service. DAppNode automatically runs `enclave start -v` with your + config. +- Use the **Logs** tab or `docker logs -f enclave-ciphernode.public.dappnode.eth` to watch the + bootstrap process. +- To override CLI arguments, edit the package's `EXTRA_OPTS` field (for example, to add + `--peer /dnsaddr/bootstrap.enclave.gg` while testing new peers). +- When you need to refresh secrets, stop the service, update the wizard values, and start it again. + +### Standalone Docker container + +Prefer to run a single node outside DAppNode? Build from the repo and mount your config + secrets: + +```bash +# From the repository root +docker build -f crates/Dockerfile -t enclave-ciphernode:latest . + +mkdir -p ops/enclave/config ops/enclave/data +cat <<'EOF' > ops/enclave/config/enclave.config.yaml +node: + address: '0xYourOperator' + quic_port: 9201 + peers: + - '/dnsaddr/bootstrap.enclave.gg' + autonetkey: true + autopassword: true +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia.publicnode.com' + contracts: + enclave: + address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + bonding_registry: + address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' + fee_token: + address: '0xB58B762748c64f1a36B34012d1C52503617f4De0' +EOF + +cat <<'EOF' > ops/enclave/secrets.json +{ + "password": "choose-a-long-passphrase", + "private_key": "0x", + "network_private_key": "0x" +} +EOF + +docker run -d --name enclave-cn1 --restart unless-stopped \ + -p 9201:9201/udp \ + -v $PWD/ops/enclave/config:/home/ciphernode/.config/enclave \ + -v $PWD/ops/enclave/data:/home/ciphernode/.local/share/enclave \ + -v $PWD/ops/enclave/secrets.json:/run/secrets/secrets.json:ro \ + -e AGGREGATOR=false \ + enclave-ciphernode:latest +``` + +- The entrypoint reads `/run/secrets/secrets.json`, sets your password + keys, and then runs + `enclave start -v --config /home/ciphernode/.config/enclave/config.yaml`. +- Switch `AGGREGATOR=true` for plaintext aggregators. +- Mount any additional configs (TLS certs, Grafana agents, etc.) under the same directory and + reference them from `enclave.config.yaml`. +- To run CLI commands inside the container, use + `docker exec -it enclave-cn1 enclave ciphernode status --chain sepolia`. + +## Manual setup: initialize your ciphernode Start by running `enclave init` to create the initial configuration: @@ -89,6 +184,32 @@ Your node will: - Subscribe to blockchain events - Begin participating in sortition when E3s are requested +## CLI lifecycle after deployment + +With the node running (via DAppNode, Docker, or bare metal) and your wallet already funded with the +required ENCL + stable tokens, move through the registry lifecycle using the CLI. Every command +accepts `--chain ` to select the chain entry from your config file and `--config ` if you +store configs outside the default. + +| Goal | Command | Result | +| --- | --- | --- | +| Bond ENCL license collateral | `enclave ciphernode license bond --amount 100 --chain sepolia` | Approves + bonds ENCL into the BondingRegistry | +| Deposit ticket backing (stablecoin) | `enclave ciphernode tickets buy --amount 100 --chain sepolia` | Approves fee token, mints ETK tickets | +| Register the operator | `enclave ciphernode register --chain sepolia` | Calls `registerOperator()` and unlocks sortition eligibility | +| Force an activation check | `enclave ciphernode activate --chain sepolia` | Replays `registerOperator()` if status drifted | +| Inspect state | `enclave ciphernode status --chain sepolia` | Prints bonded amounts, tickets, exits, and requirements | +| Remove stake during an exit | `enclave ciphernode deactivate --tickets 10 --license 20 --chain sepolia` | Withdraws tickets / unbonds license into the exit queue | +| Deregister completely | `enclave ciphernode deregister --proof 0xabc,0xdef --chain sepolia` | Calls `deregisterOperator()`, burning tickets immediately | +| Claim finished exits | `enclave ciphernode license claim --max-ticket 100 --max-license 100 --chain sepolia` | Calls `claimExits()` to pull unlocked funds | + +- For `tickets buy` and `license bond`, the CLI automatically checks ERC20 allowances and submits + approvals before calling the BondingRegistry. +- Capture the IMT siblings emitted in `CiphernodeAdded` to reuse later with the `--proof` flag. +- When running inside Docker/DAppNode, wrap commands with `docker exec -it ` so they can + access the mounted config and keystore. +- The lifecycle diagram in `ciphernode-operators/index.mdx` matches the sequence above: bond → + register → add tickets → stay active → deactivate/deregister → claim exits. + ## The Complete E3 Flow Here's what happens when an E3 (Encrypted Execution Environment) computation is requested: From 51a54d7481415dee67f7824242e6a1a1441c4f6d Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 9 Dec 2025 07:39:34 +0500 Subject: [PATCH 08/19] chore: update docs --- docs/pages/CRISP/running-e3.mdx | 6 +- docs/pages/CRISP/setup.mdx | 49 +- docs/pages/best-practices.mdx | 130 ++-- docs/pages/building-with-enclave.mdx | 21 +- docs/pages/ciphernode-operators.mdx | 480 ++++++------ docs/pages/ciphernode-operators/_meta.json | 34 +- .../exits-and-slashing.mdx | 202 ++--- docs/pages/ciphernode-operators/index.mdx | 208 ++--- .../pages/ciphernode-operators/operations.mdx | 714 +++++++++--------- .../ciphernode-operators/registration.mdx | 234 +++--- .../tickets-and-sortition.mdx | 278 +++---- docs/pages/computation-flow.mdx | 16 +- docs/pages/compute-provider.mdx | 24 +- docs/pages/noir-circuits.mdx | 166 ++-- docs/pages/project-template.mdx | 193 ++--- docs/pages/quick-start.mdx | 2 +- docs/pages/sdk.mdx | 308 ++++---- docs/pages/use-cases.mdx | 125 +-- examples/CRISP/Readme.md | 28 +- 19 files changed, 1617 insertions(+), 1601 deletions(-) diff --git a/docs/pages/CRISP/running-e3.mdx b/docs/pages/CRISP/running-e3.mdx index 7aa075efd4..e724316d32 100644 --- a/docs/pages/CRISP/running-e3.mdx +++ b/docs/pages/CRISP/running-e3.mdx @@ -19,6 +19,7 @@ complete voting round of CRISP and do the following: Please make sure you have followed the [CRISP Setup](/CRISP/setup) guide before proceeding. enclave nodes up -v + ### Prep Once per Checkout @@ -51,8 +52,7 @@ Behind the scenes `scripts/dev.sh` calls `scripts/dev_services.sh`, which: - Launches the Rust server with `cargo run --bin server` - Starts the React client via `pnpm dev-static` -Keep this terminal open; logs from every service are multiplexed with -`pnpm concurrently`. +Keep this terminal open; logs from every service are multiplexed with `pnpm concurrently`. ### (Optional) Build Once for Production @@ -197,7 +197,7 @@ The CRISP voting process involves several key steps: - **MetaMask connection issues**: Check that you're connected to the correct network (Chain ID: 31337) - **Transaction failures**: Verify you have sufficient ETH balance from the Hardhat faucet (the - account with the imported deployer key starts funded) + account with the imported deployer key starts funded) - **Server errors**: Monitor the server logs for detailed error messages - **Ciphernode issues**: Ensure all ciphernode processes are running and connected diff --git a/docs/pages/CRISP/setup.mdx b/docs/pages/CRISP/setup.mdx index 5bac24d89e..e3669757c5 100644 --- a/docs/pages/CRISP/setup.mdx +++ b/docs/pages/CRISP/setup.mdx @@ -30,7 +30,8 @@ Before getting started, ensure you have installed: - [NodeJS](https://nodejs.org/en/download) - [pnpm](https://pnpm.io) - [MetaMask](https://metamask.io) -- [Noir toolchain (`nargo`, `bb`)](https://noir-lang.org/docs/getting_started/installation) — required when you recompile the circuits +- [Noir toolchain (`nargo`, `bb`)](https://noir-lang.org/docs/getting_started/installation) — + required when you recompile the circuits ### Install Node @@ -92,7 +93,8 @@ pnpm dev:up `dev:up` runs `scripts/dev.sh`, which: 1. Starts the Hardhat node in `packages/crisp-contracts` -2. Deploys all contracts (Enclave, CRISPProgram, verifiers, registries) via `scripts/crisp_deploy.sh` +2. Deploys all contracts (Enclave, CRISPProgram, verifiers, registries) via + `scripts/crisp_deploy.sh` 3. Starts ciphernodes using `enclave.config.yaml` via `scripts/dev_cipher.sh` 4. Launches the program server (RISC Zero) via `scripts/dev_program.sh` 5. Starts the coordination server (Rust) via `scripts/dev_server.sh` on port `4000` @@ -115,7 +117,9 @@ pnpm test:e2e ### Deployed Contract Addresses -The contract addresses are automatically configured in `enclave.config.yaml` and the server `.env` file. After running `pnpm dev:up`, the deployment logs will show the deployed contract addresses, which are also saved in `packages/crisp-contracts/deployed_contracts.json`. +The contract addresses are automatically configured in `enclave.config.yaml` and the server `.env` +file. After running `pnpm dev:up`, the deployment logs will show the deployed contract addresses, +which are also saved in `packages/crisp-contracts/deployed_contracts.json`. ### Using the Application @@ -135,31 +139,34 @@ Once everything is running, you can: ### Ciphernode Configuration -The `enclave.config.yaml` file in the CRISP root directory configures the ciphernode network. By default, it runs in development mode with fake proofs for fast local development: +The `enclave.config.yaml` file in the CRISP root directory configures the ciphernode network. By +default, it runs in development mode with fake proofs for fast local development: ```yaml program: - dev: true # Uses fake proofs (fast for development) + dev: true # Uses fake proofs (fast for development) ``` ### Boundless Configuration (Production Proving) -For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update `enclave.config.yaml`: +For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update +`enclave.config.yaml`: ```yaml program: - dev: false # Disable dev mode to use real proofs + dev: false # Disable dev mode to use real proofs risc0: - risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode + risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode boundless: - rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" # RPC endpoint - private_key: "YOUR_PRIVATE_KEY" # Wallet with funds for proving - pinata_jwt: "YOUR_PINATA_JWT" # Required for uploading programs to IPFS - program_url: "https://gateway.pinata.cloud/ipfs/YOUR_CID" # Pre-uploaded program URL - onchain: true # true = onchain requests, false = offchain + rpc_url: 'https://sepolia.infura.io/v3/YOUR_KEY' # RPC endpoint + private_key: 'YOUR_PRIVATE_KEY' # Wallet with funds for proving + pinata_jwt: 'YOUR_PINATA_JWT' # Required for uploading programs to IPFS + program_url: 'https://gateway.pinata.cloud/ipfs/YOUR_CID' # Pre-uploaded program URL + onchain: true # true = onchain requests, false = offchain ``` > **_Note:_** For production proving with Boundless, you need: +> > - An RPC endpoint (e.g., Infura, Alchemy) with funds > - A private key with sufficient ETH/tokens for proof generation > - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) @@ -167,7 +174,8 @@ program: #### Uploading Your Program to IPFS -When you make changes to the guest program in `program/`, you need to upload it to IPFS to get a program URL: +When you make changes to the guest program in `program/`, you need to upload it to IPFS to get a +program URL: 1. First, configure your Pinata JWT in `enclave.config.yaml` (as shown above) @@ -178,17 +186,22 @@ When you make changes to the guest program in `program/`, you need to upload it enclave program upload --pinata-jwt YOUR_PINATA_JWT ``` -3. The command will output an IPFS hash like `QmXxx...`. Update your `enclave.config.yaml` with the full URL: +3. The command will output an IPFS hash like `QmXxx...`. Update your `enclave.config.yaml` with the + full URL: ```yaml - program_url: "https://gateway.pinata.cloud/ipfs/QmXxx..." + program_url: 'https://gateway.pinata.cloud/ipfs/QmXxx...' ``` -> **_Important:_** Every time you modify the guest program code in `program/`, you must rebuild and re-upload it to IPFS, then update the `program_url` in your configuration. This ensures Boundless uses your latest program version. +> **_Important:_** Every time you modify the guest program code in `program/`, you must rebuild and +> re-upload it to IPFS, then update the `program_url` in your configuration. This ensures Boundless +> uses your latest program version. ### Environment Variables -The `pnpm dev:setup` command automatically creates `.env` files for the server and client from the `.env.example` templates. The server's `.env` file is automatically populated with contract addresses after deployment. +The `pnpm dev:setup` command automatically creates `.env` files for the server and client from the +`.env.example` templates. The server's `.env` file is automatically populated with contract +addresses after deployment. ## Running Individual Components diff --git a/docs/pages/best-practices.mdx b/docs/pages/best-practices.mdx index 1b1c91f7a0..546f5a108e 100644 --- a/docs/pages/best-practices.mdx +++ b/docs/pages/best-practices.mdx @@ -1,65 +1,65 @@ ---- -title: 'Best Practices' ---- - -# Design & Operations Best Practices - -Competitor docs such as Fhenix's "Key Considerations" and Ritual's architecture primers emphasize -clear guardrails for confidential compute. This guide distills the equivalent playbook for Enclave. - -## Parameter Strategy - -- **Thresholds**: Choose `threshold = [t, n]` so that `t` withstands your adversary model while `n` - matches available Ciphernodes. Higher thresholds improve collusion resistance but increase fees. -- **Timing Windows**: Ensure `startWindow` leaves enough time for committee selection (a few blocks) - and `duration` matches the longest credible compute time plus buffer. -- **Custom Params**: Use `customParams` in `E3RequestParams` to tag jurisdiction, use case, or feature - toggles without redeploying contracts. - -## Input Validation - -- **Push logic to validators**: Implement `IInputValidator.validate` so ZK proofs and policy checks - happen before the Secure Process. This mirrors how CoFHE tutorials offload range proofs from the - heavy computation path. -- **Replay protection**: Include round identifiers or nullifiers inside inputs before you hash them - into the Lean IMT. -- **Access control**: Gate inputs via registries (e.g., DAO membership) or staking requirements to - keep spam out of the queue. - -## Secure Process & Compute Providers - -- **Determinism**: Reconstruct the on-chain Merkle root inside the Secure Process, then assert - equality prior to any heavy math. -- **Proof hooks**: When using RISC Zero or other verifiable CPs, keep witness blobs small and reserve - `computeProviderParams` for runtime toggles (precision, chunk size, etc.). -- **Failover**: Decide how your app reacts if `CiphertextOutputPublished` never arrives—e.g., allow a - guardian to cancel the round and refund deposits. - -## Key Material & Ciphernodes - -- **Key hygiene**: `dev:setup` wipes `.enclave` directories for you; mimic that behavior in production - by rotating committee keys when nodes churn. -- **Monitoring**: Subscribe to `E3Activated` and `PlaintextOutputPublished` events to ensure the CiCo - publishes keys and decryptions on schedule. -- **Operator docs**: Keep the [Ciphernode Operators](/ciphernode-operators) runbooks close to your app - documentation so node providers can mirror your expectations. - -## Observability & Tooling - -- **Structured logs**: Adopt the logging schema from the CRISP server (JSON with `e3_id` and phase) - so you can stitch together end-to-end traces. -- **Synthetic tests**: Reuse `pnpm dev:up` + Playwright to run rehearsal rounds on CI before shipping - new circuits or SDK releases. -- **Dashboarding**: Track request fees, committee saturation, and mean time from `request` to - `PlaintextOutputPublished` just like Ritual exposes node specialization metrics. - -## Deployment Checklist - -1. Run `pnpm dev:build` to preflight the entire stack. -2. Execute integration tests that cover `request → publishInput → publishCiphertextOutput` with mock - proofs. -3. Verify wallet funding for any automation (enclave CLI, Hardhat deployers). -4. Update onboarding docs (MetaMask, scripts) when RPC URLs or ports change. -5. Publish a postmortem template so incidents have consistent follow-up. - -Pair these practices with the [Use Cases](/use-cases) catalog to craft predictable launch plans. +--- +title: 'Best Practices' +--- + +# Design & Operations Best Practices + +Competitor docs such as Fhenix's "Key Considerations" and Ritual's architecture primers emphasize +clear guardrails for confidential compute. This guide distills the equivalent playbook for Enclave. + +## Parameter Strategy + +- **Thresholds**: Choose `threshold = [t, n]` so that `t` withstands your adversary model while `n` + matches available Ciphernodes. Higher thresholds improve collusion resistance but increase fees. +- **Timing Windows**: Ensure `startWindow` leaves enough time for committee selection (a few blocks) + and `duration` matches the longest credible compute time plus buffer. +- **Custom Params**: Use `customParams` in `E3RequestParams` to tag jurisdiction, use case, or + feature toggles without redeploying contracts. + +## Input Validation + +- **Push logic to validators**: Implement `IInputValidator.validate` so ZK proofs and policy checks + happen before the Secure Process. This mirrors how CoFHE tutorials offload range proofs from the + heavy computation path. +- **Replay protection**: Include round identifiers or nullifiers inside inputs before you hash them + into the Lean IMT. +- **Access control**: Gate inputs via registries (e.g., DAO membership) or staking requirements to + keep spam out of the queue. + +## Secure Process & Compute Providers + +- **Determinism**: Reconstruct the on-chain Merkle root inside the Secure Process, then assert + equality prior to any heavy math. +- **Proof hooks**: When using RISC Zero or other verifiable CPs, keep witness blobs small and + reserve `computeProviderParams` for runtime toggles (precision, chunk size, etc.). +- **Failover**: Decide how your app reacts if `CiphertextOutputPublished` never arrives—e.g., allow + a guardian to cancel the round and refund deposits. + +## Key Material & Ciphernodes + +- **Key hygiene**: `dev:setup` wipes `.enclave` directories for you; mimic that behavior in + production by rotating committee keys when nodes churn. +- **Monitoring**: Subscribe to `E3Activated` and `PlaintextOutputPublished` events to ensure the + CiCo publishes keys and decryptions on schedule. +- **Operator docs**: Keep the [Ciphernode Operators](/ciphernode-operators) runbooks close to your + app documentation so node providers can mirror your expectations. + +## Observability & Tooling + +- **Structured logs**: Adopt the logging schema from the CRISP server (JSON with `e3_id` and phase) + so you can stitch together end-to-end traces. +- **Synthetic tests**: Reuse `pnpm dev:up` + Playwright to run rehearsal rounds on CI before + shipping new circuits or SDK releases. +- **Dashboarding**: Track request fees, committee saturation, and mean time from `request` to + `PlaintextOutputPublished` just like Ritual exposes node specialization metrics. + +## Deployment Checklist + +1. Run `pnpm dev:build` to preflight the entire stack. +2. Execute integration tests that cover `request → publishInput → publishCiphertextOutput` with mock + proofs. +3. Verify wallet funding for any automation (enclave CLI, Hardhat deployers). +4. Update onboarding docs (MetaMask, scripts) when RPC URLs or ports change. +5. Publish a postmortem template so incidents have consistent follow-up. + +Pair these practices with the [Use Cases](/use-cases) catalog to craft predictable launch plans. diff --git a/docs/pages/building-with-enclave.mdx b/docs/pages/building-with-enclave.mdx index d1c1c6c681..916727e827 100644 --- a/docs/pages/building-with-enclave.mdx +++ b/docs/pages/building-with-enclave.mdx @@ -138,22 +138,11 @@ to the E3's public key. It is also recommended to bundle in proofs to validate: ```solidity event E3Requested(uint256 indexed e3Id, address indexed requester, address e3ProgramAddress); -event InputPublished( - uint256 indexed e3Id, - bytes data, - uint256 inputHash, - uint256 index -); - -event CiphertextOutputPublished( - uint256 indexed e3Id, - bytes ciphertextOutput -); - -event PlaintextOutputPublished( - uint256 indexed e3Id, - bytes plaintextOutput -); +event InputPublished(uint256 indexed e3Id, bytes data, uint256 inputHash, uint256 index); + +event CiphertextOutputPublished(uint256 indexed e3Id, bytes ciphertextOutput); + +event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput); ``` ### Result Publication Flow diff --git a/docs/pages/ciphernode-operators.mdx b/docs/pages/ciphernode-operators.mdx index 461a1a8211..4d57c0b0a8 100644 --- a/docs/pages/ciphernode-operators.mdx +++ b/docs/pages/ciphernode-operators.mdx @@ -1,240 +1,240 @@ ---- -title: 'Ciphernode Operators' -description: 'How to bond, configure, and operate Ciphernodes on the Enclave network' ---- - -# Ciphernode Operators - -Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key -shares, and keep the Enclave network alive. This guide walks through the economic requirements, -on-chain lifecycle, CLI workflow, networking expectations, and production deployment patterns for -running a Ciphernode. - -## Role overview - -Ciphernodes are expected to: - -- Maintain an online endpoint and participate in the event bus -- Bond license collateral (ENCL) and hold tickets (stablecoin-backed ETK) to earn committee slots -- Submit tickets on-chain during sortition and publish committee key material -- Produce decryption shares for every E3 the node was selected to serve -- Remain slash-aware: missed duties or malicious behavior can lose both ticket collateral and - license bonds - -The protocol is chain-agnostic. Each configured chain entry in `enclave.config.yaml` can track a -different Enclave + registry deployment, and each Ciphernode instance manages the lifecycle for its -configured chains simultaneously. - -## Contract references - -| Contract | Sepolia address | Notes | -| ------------------------ | -------------------------------------------- | -------------------------------- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | -| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | - -> ⚠️ Always confirm the latest addresses from the docs. Addresses differ per network. - -## Economics & staking - -BondingRegistry constants on Sepolia: - -- **Ticket price**: `10_000_000` base units (10 USDC per ticket) -- **License bond requirement**: `100 ENCL` -- **Active license floor**: 80% of the required bond must remain bonded -- **Minimum ticket balance**: 1 ticket (10 USDC) -- **Exit delay**: `604_800 s` (7 days) - -Ticket balances are represented by the non-transferable `EnclaveTicketToken`. To mint tickets: - -1. Acquire the underlying stablecoin (`MockUSDC` on Sepolia) -2. Approve the BondingRegistry to pull funds -3. Call `addTicketBalance(amount)` - -The number of usable tickets is: - -``` -availableTickets = floor(ticketTokenBalance / ticketPrice) -``` - -Tickets control a node's probability of selection via sortition. - -License bonds are denominated in ENCL. Operators must keep at least 80% of `licenseRequiredBond` -bonded to remain `active`. - -SlashingManager penalties can remove both ticket balances and license bonds, and may ban an -operator. Appeals are time-bound by the policy's `appealWindow`. - -Rewards (any ERC20) are pushed by the configured `rewardDistributor` through -`BondingRegistry.distributeRewards`. Only registered operators receive payouts. - -## Lifecycle checklist - -1. **Acquire collateral** - - ENCL for license bonding - - USDC (or the configured fee token) for tickets -2. **Bond the license** - ```bash - cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -3. **Register as a ciphernode** - ```bash - cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -4. **Deposit tickets** - ```bash - cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - ``` -5. **Verify status** - - `BondingRegistry.isRegistered(address)` must be `true` - - `BondingRegistry.isActive(address)` turns `true` after ticket + license thresholds -6. **Stay online** - - Run the CLI (see below) so your node listens for events and participates in sortition -7. **Handle exits** - - Call `deregisterOperator(siblingProof)` to begin exit - - Wait 7 days, then `claimExits(maxTickets, maxLicense)` to withdraw - -> ℹ️ The sibling proof passed to `deregisterOperator` is the path needed to remove the node from the -> registry IMT. Capture it from the Merkle proof emitted in `CiphernodeAdded` events or by querying -> the registry before exit. - -## CLI workflow - -The `enclave` CLI wraps node orchestration, credentials, and repository tooling. - -### Initialize configuration - -```bash -enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS -``` - -This creates `~/.config/enclave/config.yaml` (or the path you pass with `--config`). Most operators -instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass -it with `--config /path/to/config.yaml` on every command. - -### Manage credentials - -| Secret | Command | Notes | -| ---------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | -| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | -| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | -| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for the node to submit on-chain txs | - -The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config -sets those flags. - -### Run nodes - -```bash -enclave nodes up --detach # start every node profile defined in config -enclave nodes ps # list process status -enclave nodes status cn1 # query single node -enclave nodes restart cn1 # restart one node -enclave nodes down # stop everything -enclave nodes purge # wipe local db + secrets (irreversible) -``` - -To run a single node profile outside the supervisor, use -`enclave start --config /path/to/config.yaml`. Pass peers with -`--peer /dns4/bootstrap.enclave.gg/udp/5901/quic-v1` to override the config at runtime. - -## Networking & configuration - -Every node section in `enclave.config.yaml` defines how the CLI spawns that instance: - -```yaml -node: - address: '0x7099…79C8' - quic_port: 9201 - peers: - - '/dns4/bootstrap.enclave.gg/udp/5901/quic-v1' - autonetkey: true - autopassword: true -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8B…FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F6…0b1C7' - bonding_registry: - address: '0x5636…406E3' - fee_token: - address: '0xB58B…4De0' -``` - -Notes: - -- `peers` expects libp2p multiaddrs (`/dns4//udp//quic-v1`). Provide at least one - bootstrap peer. For production, run a static bootstrap service (planned: `bootstrap.enclave.gg`). -- `quic_port` must match firewall rules; expose UDP. -- Each node can override `data_dir` and `config_dir` if the defaults under `~/.local/share/enclave` - and `~/.config/enclave` are unsuitable. -- Set `role.type: aggregator` for nodes tasked with publishing plaintext outputs. - -## Deployment manifests & secrets - -The repository ships a Docker Swarm example under `deploy/` that you can adapt: - -- `cn*.yaml` / `agg.yaml`: minimal configs templated with `${ADDRESS}` and `${RPC_URL}` -- `docker-compose.yml`: runs multiple Ciphernodes plus an aggregator with shared overlay network -- Secrets files (`cn1.secrets.json`, etc.) follow: - ```json - { - "password": "changeme", - "private_key": "0x…", - "network_private_key": "0x…" - } - ``` -- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands - (`enclave password set`, `enclave net keypair set`, `enclave wallet set`), then execs - `enclave start -v` - -This pattern is also useful for Kubernetes Jobs or systemd units: mount a config, mount an encrypted -secret bundle, run the entrypoint. - -## Sortition & operations - -- Committee requests originate from the Enclave contract. The registry snapshots ticket balances at - `requestBlock - 1`, so topping up tickets after a request starts will not help that round. -- Submission window defaults to 10 seconds on Sepolia (`sortitionSubmissionWindow`). Nodes must call - `submitTicket(e3Id, ticketNumber)` before it expires. The CLI handles this automatically using the - event bus. -- `finalizeCommittee` can be called by anyone once the window closes and at least `threshold_m` - submissions exist. After finalization, nodes publish key shares, aggregate the public key, and - submit it via `publishCommittee`. -- If a node is offline during submission, it misses the round but remains active provided its stake - satisfies the requirements. Repeated failures risk slashing. - -## Rewards, slashing, and exits - -- **Rewards**: Watch for `RewardDistributed` (BondingRegistry) logs. Ensure the operator wallet can - receive the reward token. -- **Slashing**: `SlashingManager` proposals reference reason codes. Operators should monitor - `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is - not required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. -- **Exits**: `deregisterOperator()` burns tickets immediately and queues withdrawals. The exit queue - tracks amounts per operator; call `pendingExits(address)` or `previewClaimable(address)` to view - status. - -## Troubleshooting - -| Symptom | Checks | -| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | -| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | -| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | -| Sortition submissions fail | Node must be registered + active _before_ `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | -| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | -| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | - -Maintaining high uptime, redundant networking, and alerting on contract events are the best ways to -protect your stake. Use the CLI supervisors plus infrastructure automation to ensure secrets and -configs stay consistent across restarts. +--- +title: 'Ciphernode Operators' +description: 'How to bond, configure, and operate Ciphernodes on the Enclave network' +--- + +# Ciphernode Operators + +Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key +shares, and keep the Enclave network alive. This guide walks through the economic requirements, +on-chain lifecycle, CLI workflow, networking expectations, and production deployment patterns for +running a Ciphernode. + +## Role overview + +Ciphernodes are expected to: + +- Maintain an online endpoint and participate in the event bus +- Bond license collateral (ENCL) and hold tickets (stablecoin-backed ETK) to earn committee slots +- Submit tickets on-chain during sortition and publish committee key material +- Produce decryption shares for every E3 the node was selected to serve +- Remain slash-aware: missed duties or malicious behavior can lose both ticket collateral and + license bonds + +The protocol is chain-agnostic. Each configured chain entry in `enclave.config.yaml` can track a +different Enclave + registry deployment, and each Ciphernode instance manages the lifecycle for its +configured chains simultaneously. + +## Contract references + +| Contract | Sepolia address | Notes | +| ------------------------ | -------------------------------------------- | -------------------------------- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | +| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | + +> ⚠️ Always confirm the latest addresses from the docs. Addresses differ per network. + +## Economics & staking + +BondingRegistry constants on Sepolia: + +- **Ticket price**: `10_000_000` base units (10 USDC per ticket) +- **License bond requirement**: `100 ENCL` +- **Active license floor**: 80% of the required bond must remain bonded +- **Minimum ticket balance**: 1 ticket (10 USDC) +- **Exit delay**: `604_800 s` (7 days) + +Ticket balances are represented by the non-transferable `EnclaveTicketToken`. To mint tickets: + +1. Acquire the underlying stablecoin (`MockUSDC` on Sepolia) +2. Approve the BondingRegistry to pull funds +3. Call `addTicketBalance(amount)` + +The number of usable tickets is: + +``` +availableTickets = floor(ticketTokenBalance / ticketPrice) +``` + +Tickets control a node's probability of selection via sortition. + +License bonds are denominated in ENCL. Operators must keep at least 80% of `licenseRequiredBond` +bonded to remain `active`. + +SlashingManager penalties can remove both ticket balances and license bonds, and may ban an +operator. Appeals are time-bound by the policy's `appealWindow`. + +Rewards (any ERC20) are pushed by the configured `rewardDistributor` through +`BondingRegistry.distributeRewards`. Only registered operators receive payouts. + +## Lifecycle checklist + +1. **Acquire collateral** + - ENCL for license bonding + - USDC (or the configured fee token) for tickets +2. **Bond the license** + ```bash + cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +3. **Register as a ciphernode** + ```bash + cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +4. **Deposit tickets** + ```bash + cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + ``` +5. **Verify status** + - `BondingRegistry.isRegistered(address)` must be `true` + - `BondingRegistry.isActive(address)` turns `true` after ticket + license thresholds +6. **Stay online** + - Run the CLI (see below) so your node listens for events and participates in sortition +7. **Handle exits** + - Call `deregisterOperator(siblingProof)` to begin exit + - Wait 7 days, then `claimExits(maxTickets, maxLicense)` to withdraw + +> ℹ️ The sibling proof passed to `deregisterOperator` is the path needed to remove the node from the +> registry IMT. Capture it from the Merkle proof emitted in `CiphernodeAdded` events or by querying +> the registry before exit. + +## CLI workflow + +The `enclave` CLI wraps node orchestration, credentials, and repository tooling. + +### Initialize configuration + +```bash +enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS +``` + +This creates `~/.config/enclave/config.yaml` (or the path you pass with `--config`). Most operators +instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass +it with `--config /path/to/config.yaml` on every command. + +### Manage credentials + +| Secret | Command | Notes | +| ---------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | +| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | +| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | +| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for the node to submit on-chain txs | + +The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config +sets those flags. + +### Run nodes + +```bash +enclave nodes up --detach # start every node profile defined in config +enclave nodes ps # list process status +enclave nodes status cn1 # query single node +enclave nodes restart cn1 # restart one node +enclave nodes down # stop everything +enclave nodes purge # wipe local db + secrets (irreversible) +``` + +To run a single node profile outside the supervisor, use +`enclave start --config /path/to/config.yaml`. Pass peers with +`--peer /dns4/bootstrap.enclave.gg/udp/5901/quic-v1` to override the config at runtime. + +## Networking & configuration + +Every node section in `enclave.config.yaml` defines how the CLI spawns that instance: + +```yaml +node: + address: '0x7099…79C8' + quic_port: 9201 + peers: + - '/dns4/bootstrap.enclave.gg/udp/5901/quic-v1' + autonetkey: true + autopassword: true +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia.publicnode.com' + contracts: + enclave: + address: '0x1E8B…FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F6…0b1C7' + bonding_registry: + address: '0x5636…406E3' + fee_token: + address: '0xB58B…4De0' +``` + +Notes: + +- `peers` expects libp2p multiaddrs (`/dns4//udp//quic-v1`). Provide at least one + bootstrap peer. For production, run a static bootstrap service (planned: `bootstrap.enclave.gg`). +- `quic_port` must match firewall rules; expose UDP. +- Each node can override `data_dir` and `config_dir` if the defaults under `~/.local/share/enclave` + and `~/.config/enclave` are unsuitable. +- Set `role.type: aggregator` for nodes tasked with publishing plaintext outputs. + +## Deployment manifests & secrets + +The repository ships a Docker Swarm example under `deploy/` that you can adapt: + +- `cn*.yaml` / `agg.yaml`: minimal configs templated with `${ADDRESS}` and `${RPC_URL}` +- `docker-compose.yml`: runs multiple Ciphernodes plus an aggregator with shared overlay network +- Secrets files (`cn1.secrets.json`, etc.) follow: + ```json + { + "password": "changeme", + "private_key": "0x…", + "network_private_key": "0x…" + } + ``` +- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands + (`enclave password set`, `enclave net keypair set`, `enclave wallet set`), then execs + `enclave start -v` + +This pattern is also useful for Kubernetes Jobs or systemd units: mount a config, mount an encrypted +secret bundle, run the entrypoint. + +## Sortition & operations + +- Committee requests originate from the Enclave contract. The registry snapshots ticket balances at + `requestBlock - 1`, so topping up tickets after a request starts will not help that round. +- Submission window defaults to 10 seconds on Sepolia (`sortitionSubmissionWindow`). Nodes must call + `submitTicket(e3Id, ticketNumber)` before it expires. The CLI handles this automatically using the + event bus. +- `finalizeCommittee` can be called by anyone once the window closes and at least `threshold_m` + submissions exist. After finalization, nodes publish key shares, aggregate the public key, and + submit it via `publishCommittee`. +- If a node is offline during submission, it misses the round but remains active provided its stake + satisfies the requirements. Repeated failures risk slashing. + +## Rewards, slashing, and exits + +- **Rewards**: Watch for `RewardDistributed` (BondingRegistry) logs. Ensure the operator wallet can + receive the reward token. +- **Slashing**: `SlashingManager` proposals reference reason codes. Operators should monitor + `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is + not required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. +- **Exits**: `deregisterOperator()` burns tickets immediately and queues withdrawals. The exit queue + tracks amounts per operator; call `pendingExits(address)` or `previewClaimable(address)` to view + status. + +## Troubleshooting + +| Symptom | Checks | +| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | +| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | +| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | +| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | +| Sortition submissions fail | Node must be registered + active _before_ `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | +| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | +| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | + +Maintaining high uptime, redundant networking, and alerting on contract events are the best ways to +protect your stake. Use the CLI supervisors plus infrastructure automation to ensure secrets and +configs stay consistent across restarts. diff --git a/docs/pages/ciphernode-operators/_meta.json b/docs/pages/ciphernode-operators/_meta.json index cbb6227cc7..f94f5188ed 100644 --- a/docs/pages/ciphernode-operators/_meta.json +++ b/docs/pages/ciphernode-operators/_meta.json @@ -1,17 +1,17 @@ -{ - "index": { - "title": "Overview" - }, - "registration": { - "title": "Registration & Licensing" - }, - "operations": { - "title": "Running a Ciphernode" - }, - "tickets-and-sortition": { - "title": "Tickets & Sortition" - }, - "exits-and-slashing": { - "title": "Exits, Rewards & Slashing" - } -} +{ + "index": { + "title": "Overview" + }, + "registration": { + "title": "Registration & Licensing" + }, + "operations": { + "title": "Running a Ciphernode" + }, + "tickets-and-sortition": { + "title": "Tickets & Sortition" + }, + "exits-and-slashing": { + "title": "Exits, Rewards & Slashing" + } +} diff --git a/docs/pages/ciphernode-operators/exits-and-slashing.mdx b/docs/pages/ciphernode-operators/exits-and-slashing.mdx index cc0ba7c2ab..e574d13cc1 100644 --- a/docs/pages/ciphernode-operators/exits-and-slashing.mdx +++ b/docs/pages/ciphernode-operators/exits-and-slashing.mdx @@ -1,100 +1,102 @@ ---- -title: 'Exits, Rewards & Slashing' ---- - -# Exits, Rewards & Slashing - -Understand how to collect rewards, respond to slashing proposals, and exit the registry safely. - -## Rewards - -- Distributed via `BondingRegistry.distributeRewards` (any ERC20) -- Watch for `RewardsDistributed` events and map them back to the source `e3Id` -- Keep the operator wallet funded; payouts are on-chain transfers and still require gas when - claimed through automation scripts - -Pair reward monitoring with lightweight probes: - -```bash -cast call $BONDING "pendingExits(address)" $OPERATOR -cast call $BONDING "getTicketBalance(address)" $OPERATOR -cast call $BONDING "licenseRequiredBond()" -``` - -Seeing rewards fall while balances remain healthy is an early indicator of missed jobs or RPC issues. - -## Slashing lifecycle - -1. `SlashingManager` emits `SlashProposed` referencing a policy + reason code. -2. Operators inspect the evidence (if any) and the associated `SlashPolicy` parameters. -3. File an appeal with `fileAppeal(e3Id, reason, evidenceURI)` before `appealWindow` expires, if the - policy allows it. -4. Once finalized, penalties may burn tickets, confiscate license bonds, and optionally ban the - operator. - -Stay alert for: - -- `appealWindow` values per policy (some reasons skip appeals entirely) -- `updateBanStatus` (governance must lift bans before re-registration) - -Policy anatomy: - -```solidity -struct SlashPolicy { - uint256 ticketPenalty; - uint256 licensePenalty; - bool requiresProof; - uint64 appealWindow; - bool appealable; -} -``` - -Never assume a slash is appealable without fetching the latest policy via `SlashingManager`. - -## Exit process - -1. **Deregister** — Call `deregisterOperator(uint256[] siblingNodes)` with a valid IMT proof. The - CLI logs the proof when you first register; stash it alongside your secrets bundle. -2. **Queue assets** — Ticket balances burn immediately. License bonds slide into the exit queue and - set `exitUnlocksAt = block.timestamp + exitDelay`. -3. **Wait out `exitDelay()`** — Default is 7 days on Sepolia. Automation should poll - `exitUnlocksAt(address)` to know when to attempt a claim. -4. **Claim exits** — Once the unlock timestamp passes, drain the queue: - - ```bash - cast send $BONDING "claimExits(uint256,uint256)" $MAX_TICKETS $MAX_LICENSE \ - --rpc-url $RPC --private-key $OPERATOR_KEY - ``` - - Pass `type(uint256).max` to withdraw the full pending amount. The call reverts with - `ExitNotReady` if neither queue matured yet. -5. **Cancel if needed** — Calling `registerOperator()` before `claimExits` clears the exit and puts - you back into the registry. - -Helpful getters: - -- `pendingExits(address)` → pending ticket + license totals -- `exitUnlocksAt(address)` → timestamp when claims unlock -- `hasExitInProgress(address)` → guard before attempting to re-register - -## Health checklist - -| Symptom | Actions | -| --- | --- | -| `ExitNotReady` on `claimExits` | Confirm `block.timestamp` passed `exitUnlocksAt` and delay. Call `previewClaimable`. | -| Slashing appeal rejected immediately | Policy likely disables appeals. Review policy metadata. | -| `isActive` toggles false unexpectedly | Check ticket balance (>= 1) and verify bonded ENCL >= 80% requirement. | -| Missed reward payouts | Ensure registry still lists the operator, RPC did not drop events, and reward token address is supported. | - -## Post-exit - -- Securely wipe local secrets (`enclave purge-all` to clear caches and databases, delete keystores) -- Revoke RPC credentials and firewall openings -- Document the exit reason for future audits or compliance - -## Slashing prevention checklist - -- Monitor active jobs before scheduled maintenance to avoid abandoning active work. -- Alert on `SlashProposed` events tagged with your operator address. -- Archive CLI + RPC logs for every incident; you need them for appeals. -- Double-check `isActive` after any ticket removal or license unbond to avoid accidental downtime. +--- +title: 'Exits, Rewards & Slashing' +--- + +# Exits, Rewards & Slashing + +Understand how to collect rewards, respond to slashing proposals, and exit the registry safely. + +## Rewards + +- Distributed via `BondingRegistry.distributeRewards` (any ERC20) +- Watch for `RewardsDistributed` events and map them back to the source `e3Id` +- Keep the operator wallet funded; payouts are on-chain transfers and still require gas when claimed + through automation scripts + +Pair reward monitoring with lightweight probes: + +```bash +cast call $BONDING "pendingExits(address)" $OPERATOR +cast call $BONDING "getTicketBalance(address)" $OPERATOR +cast call $BONDING "licenseRequiredBond()" +``` + +Seeing rewards fall while balances remain healthy is an early indicator of missed jobs or RPC +issues. + +## Slashing lifecycle + +1. `SlashingManager` emits `SlashProposed` referencing a policy + reason code. +2. Operators inspect the evidence (if any) and the associated `SlashPolicy` parameters. +3. File an appeal with `fileAppeal(e3Id, reason, evidenceURI)` before `appealWindow` expires, if the + policy allows it. +4. Once finalized, penalties may burn tickets, confiscate license bonds, and optionally ban the + operator. + +Stay alert for: + +- `appealWindow` values per policy (some reasons skip appeals entirely) +- `updateBanStatus` (governance must lift bans before re-registration) + +Policy anatomy: + +```solidity +struct SlashPolicy { + uint256 ticketPenalty; + uint256 licensePenalty; + bool requiresProof; + uint64 appealWindow; + bool appealable; +} +``` + +Never assume a slash is appealable without fetching the latest policy via `SlashingManager`. + +## Exit process + +1. **Deregister** — Call `deregisterOperator(uint256[] siblingNodes)` with a valid IMT proof. The + CLI logs the proof when you first register; stash it alongside your secrets bundle. +2. **Queue assets** — Ticket balances burn immediately. License bonds slide into the exit queue and + set `exitUnlocksAt = block.timestamp + exitDelay`. +3. **Wait out `exitDelay()`** — Default is 7 days on Sepolia. Automation should poll + `exitUnlocksAt(address)` to know when to attempt a claim. +4. **Claim exits** — Once the unlock timestamp passes, drain the queue: + + ```bash + cast send $BONDING "claimExits(uint256,uint256)" $MAX_TICKETS $MAX_LICENSE \ + --rpc-url $RPC --private-key $OPERATOR_KEY + ``` + + Pass `type(uint256).max` to withdraw the full pending amount. The call reverts with + `ExitNotReady` if neither queue matured yet. + +5. **Cancel if needed** — Calling `registerOperator()` before `claimExits` clears the exit and puts + you back into the registry. + +Helpful getters: + +- `pendingExits(address)` → pending ticket + license totals +- `exitUnlocksAt(address)` → timestamp when claims unlock +- `hasExitInProgress(address)` → guard before attempting to re-register + +## Health checklist + +| Symptom | Actions | +| ------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `ExitNotReady` on `claimExits` | Confirm `block.timestamp` passed `exitUnlocksAt` and delay. Call `previewClaimable`. | +| Slashing appeal rejected immediately | Policy likely disables appeals. Review policy metadata. | +| `isActive` toggles false unexpectedly | Check ticket balance (>= 1) and verify bonded ENCL >= 80% requirement. | +| Missed reward payouts | Ensure registry still lists the operator, RPC did not drop events, and reward token address is supported. | + +## Post-exit + +- Securely wipe local secrets (`enclave purge-all` to clear caches and databases, delete keystores) +- Revoke RPC credentials and firewall openings +- Document the exit reason for future audits or compliance + +## Slashing prevention checklist + +- Monitor active jobs before scheduled maintenance to avoid abandoning active work. +- Alert on `SlashProposed` events tagged with your operator address. +- Archive CLI + RPC logs for every incident; you need them for appeals. +- Double-check `isActive` after any ticket removal or license unbond to avoid accidental downtime. diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx index 370af52b21..fcb60e7e3c 100644 --- a/docs/pages/ciphernode-operators/index.mdx +++ b/docs/pages/ciphernode-operators/index.mdx @@ -1,104 +1,104 @@ ---- -title: 'Ciphernode Operators' -description: 'Role overview, prerequisites, and quick links for node operators' ---- - -# Ciphernode Operators - -Ciphernodes decrypt committee outputs, publish threshold key shares, and keep the Enclave request -pipeline moving. This section organizes everything operators need—from bonding requirements to exit -procedures—into focused guides. - -## Responsibilities at a glance - -Operators are expected to cover four concurrent tracks: - -- **Key management**: generate PVSS shares, keep private key material encrypted at rest, and publish - committee public keys once the threshold is met. -- **Decryption work**: watch for ciphertext outputs, craft decryption shares, and ensure plaintext - gets relayed on-chain. -- **Network availability**: run a QUIC/libp2p endpoint that stays reachable, stay synced to the - event bus, and keep RPC endpoints redundant. -- **Operational hygiene**: rotate secrets, snapshot configs, monitor sortition + job logs, and react - to slashing proposals or bans quickly. - -## Role overview - -Operators are expected to: - -- Maintain a QUIC/libp2p endpoint that stays reachable 24/7 -- Bond license collateral (ENCL) and hold ticket balances (ETK) to remain eligible for committees -- Stay synced with the event bus so sortition submissions and key shares happen on time -- Produce decryption shares for every E3 assigned to their committee -- Monitor slashing proposals, appeals, and rewards distribution - -Each node profile in `enclave.config.yaml` can point to a different network (mainnet, testnet, or -local dev). The CLI supervises all configured chains concurrently. - -## Why operate a Ciphernode? - -- **Rewards & upside**: committee participation and steady uptime translate to ERC20 payouts through - `distributeRewards`. -- **Governance voice**: active operators are closest to the protocol and shape roadmap + policy - discussions. -- **Visibility**: infra partners highlight high-performing nodes in working group updates and future - customer routes. - -Balance rewards against the capital tied up in ENCL bonds and ETK tickets plus infra costs. The -Scenarios page includes quick ROI checklists. - -## Contract references - -| Contract | Sepolia address | Notes | -| --- | --- | --- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration + committees | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Manages license bonds + tickets | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash & ban workflow | -| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | - -> ⚠️ Confirm addresses in `packages/enclave-contracts/deployed_contracts.json` or your deployment -> output before funding a node. Values differ per network. - -## Requirements checklist - -| Track | What you need | Notes | -| --- | --- | --- | -| Financial | ≥ `licenseRequiredBond` ENCL, ≥ `minTicketBalance * ticketPrice` USDC, plus gas | Top up - ahead of big request windows | -| Technical | Linux/macOS host, 4 cores / 8 GB RAM minimum, open UDP ports for QUIC | Containers or - bare metal both work | -| Operational | CLI >= current release, secrets storage (password, wallet, net key), monitoring + - pager | Bake into `ciphernode-entrypoint.sh` in `deploy/` | - -## Section map - -- [Registration & Licensing](./registration) — economic requirements, bonding steps, CLI commands -- [Tickets & Sortition](./tickets-and-sortition) — how ETK balances influence committee selection -- [Operations & Responsibilities](./operations) — CLI workflow, networking, deployment manifests -- [Exits, Rewards & Slashing](./exits-and-slashing) — life after registration, penalties, exits -- [Runbook Scenarios](./scenarios) — ready-made playbooks for common situations - -Use these pages sequentially when onboarding a new operator or jump to the topic you need. - -## Lifecycle states - -```mermaid -stateDiagram-v2 - [*] --> Unbonded - Unbonded --> Licensed: bondLicense(amount >= requiredBond) - Licensed --> Registered: registerOperator() - Registered --> Active: addTicketBalance(balance >= minBalance) - Active --> Inactive: removeTicketBalance() OR unbondLicense() - Inactive --> Active: addTicketBalance() OR bondLicense() - Active --> ExitPending: deregisterOperator() - Inactive --> ExitPending: deregisterOperator() - Registered --> ExitPending: deregisterOperator() - ExitPending --> [*]: claimExits() after exitDelay - ExitPending --> Registered: registerOperator() (cancels exit) -``` - -Refer back here while reading the rest of the section; each guide calls out which state transitions -it affects. +--- +title: 'Ciphernode Operators' +description: 'Role overview, prerequisites, and quick links for node operators' +--- + +# Ciphernode Operators + +Ciphernodes decrypt committee outputs, publish threshold key shares, and keep the Enclave request +pipeline moving. This section organizes everything operators need—from bonding requirements to exit +procedures—into focused guides. + +## Responsibilities at a glance + +Operators are expected to cover four concurrent tracks: + +- **Key management**: generate PVSS shares, keep private key material encrypted at rest, and publish + committee public keys once the threshold is met. +- **Decryption work**: watch for ciphertext outputs, craft decryption shares, and ensure plaintext + gets relayed on-chain. +- **Network availability**: run a QUIC/libp2p endpoint that stays reachable, stay synced to the + event bus, and keep RPC endpoints redundant. +- **Operational hygiene**: rotate secrets, snapshot configs, monitor sortition + job logs, and react + to slashing proposals or bans quickly. + +## Role overview + +Operators are expected to: + +- Maintain a QUIC/libp2p endpoint that stays reachable 24/7 +- Bond license collateral (ENCL) and hold ticket balances (ETK) to remain eligible for committees +- Stay synced with the event bus so sortition submissions and key shares happen on time +- Produce decryption shares for every E3 assigned to their committee +- Monitor slashing proposals, appeals, and rewards distribution + +Each node profile in `enclave.config.yaml` can point to a different network (mainnet, testnet, or +local dev). The CLI supervises all configured chains concurrently. + +## Why operate a Ciphernode? + +- **Rewards & upside**: committee participation and steady uptime translate to ERC20 payouts through + `distributeRewards`. +- **Governance voice**: active operators are closest to the protocol and shape roadmap + policy + discussions. +- **Visibility**: infra partners highlight high-performing nodes in working group updates and future + customer routes. + +Balance rewards against the capital tied up in ENCL bonds and ETK tickets plus infra costs. The +Scenarios page includes quick ROI checklists. + +## Contract references + +| Contract | Sepolia address | Notes | +| ------------------------ | -------------------------------------------- | --------------------------------- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration + committees | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Manages license bonds + tickets | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash & ban workflow | +| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | + +> ⚠️ Confirm addresses in `packages/enclave-contracts/deployed_contracts.json` or your deployment +> output before funding a node. Values differ per network. + +## Requirements checklist + +| Track | What you need | Notes | +| ---------------------------- | --------------------------------------------------------------------------------- | ------------- | +| Financial | ≥ `licenseRequiredBond` ENCL, ≥ `minTicketBalance * ticketPrice` USDC, plus gas | Top up | +| ahead of big request windows | +| Technical | Linux/macOS host, 4 cores / 8 GB RAM minimum, open UDP ports for QUIC | Containers or | +| bare metal both work | +| Operational | CLI >= current release, secrets storage (password, wallet, net key), monitoring + | +| pager | Bake into `ciphernode-entrypoint.sh` in `deploy/` | + +## Section map + +- [Registration & Licensing](./registration) — economic requirements, bonding steps, CLI commands +- [Tickets & Sortition](./tickets-and-sortition) — how ETK balances influence committee selection +- [Operations & Responsibilities](./operations) — CLI workflow, networking, deployment manifests +- [Exits, Rewards & Slashing](./exits-and-slashing) — life after registration, penalties, exits +- [Runbook Scenarios](./scenarios) — ready-made playbooks for common situations + +Use these pages sequentially when onboarding a new operator or jump to the topic you need. + +## Lifecycle states + +```mermaid +stateDiagram-v2 + [*] --> Unbonded + Unbonded --> Licensed: bondLicense(amount >= requiredBond) + Licensed --> Registered: registerOperator() + Registered --> Active: addTicketBalance(balance >= minBalance) + Active --> Inactive: removeTicketBalance() OR unbondLicense() + Inactive --> Active: addTicketBalance() OR bondLicense() + Active --> ExitPending: deregisterOperator() + Inactive --> ExitPending: deregisterOperator() + Registered --> ExitPending: deregisterOperator() + ExitPending --> [*]: claimExits() after exitDelay + ExitPending --> Registered: registerOperator() (cancels exit) +``` + +Refer back here while reading the rest of the section; each guide calls out which state transitions +it affects. diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx index 109057620c..c45ab41efa 100644 --- a/docs/pages/ciphernode-operators/operations.mdx +++ b/docs/pages/ciphernode-operators/operations.mdx @@ -1,357 +1,357 @@ ---- -title: 'Running a Ciphernode' ---- - -# Running a Ciphernode - -This guide walks you through setting up and running a ciphernode, then explains the complete -computation flow from E3 request to plaintext decryption. - -## Deployment paths - -### DAppNode UI (IPFS package) - -If you're already running DAppNode, install the packaged service instead of hand-building -containers: - -1. Open **Packages → Install from IPFS hash** in the DAppNode UI, then paste - `QmeX7jxDFcwbW7kAbs8Tgn5T4vonYxe4WmemUQsaca8xDQ`. This pulls - `enclave-ciphernode.public.dappnode.eth@0.1.0`. -2. After the download finishes, click **Configure** on the package tile to launch the wizard. -3. Fill the wizard fields with the same addresses listed in the contract table on this page. The - following values keep you in-sync with the public Sepolia network: - -| Wizard field | Value / Notes | -| --- | --- | -| `Network` | `sepolia` (mainnet + localhost are also available) | -| `RPC URL` | WebSocket endpoint, e.g. `wss://ethereum-sepolia.publicnode.com` | -| `Node Address` | Operator address funded with ENCL and the stable token (ETK backing) | -| `Private Key` | Matches `Node Address`; stored as a secret in the container | -| `Bootstrap Peers` | `/dnsaddr/bootstrap.enclave.gg` (add more comma-separated peers as needed) | -| `Node Role` | `ciphernode` (switch to `aggregator` only if this host should aggregate plaintext) | -| `Enclave / CiphernodeRegistry / BondingRegistry` | Use the Sepolia addresses from this doc or your deployment artifact | -| `*_DEPLOY_BLOCK` | Block numbers for each contract (Sepolia example: Enclave `9615399`) | -| `ENCRYPTION_PASSWORD`, `NETWORK_PRIVATE_KEY` | Provide values to keep deterministic peer IDs across restarts; leave blank to auto-generate | - -The wizard writes `config.yaml` from `config.template.yaml`, injects your answers as environment -variables, and persists `/data` so restarts do not erase the node database. After the wizard -completes: - -- Click **Start** to boot the service. DAppNode automatically runs `enclave start -v` with your - config. -- Use the **Logs** tab or `docker logs -f enclave-ciphernode.public.dappnode.eth` to watch the - bootstrap process. -- To override CLI arguments, edit the package's `EXTRA_OPTS` field (for example, to add - `--peer /dnsaddr/bootstrap.enclave.gg` while testing new peers). -- When you need to refresh secrets, stop the service, update the wizard values, and start it again. - -### Standalone Docker container - -Prefer to run a single node outside DAppNode? Build from the repo and mount your config + secrets: - -```bash -# From the repository root -docker build -f crates/Dockerfile -t enclave-ciphernode:latest . - -mkdir -p ops/enclave/config ops/enclave/data -cat <<'EOF' > ops/enclave/config/enclave.config.yaml -node: - address: '0xYourOperator' - quic_port: 9201 - peers: - - '/dnsaddr/bootstrap.enclave.gg' - autonetkey: true - autopassword: true -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' - bonding_registry: - address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' - fee_token: - address: '0xB58B762748c64f1a36B34012d1C52503617f4De0' -EOF - -cat <<'EOF' > ops/enclave/secrets.json -{ - "password": "choose-a-long-passphrase", - "private_key": "0x", - "network_private_key": "0x" -} -EOF - -docker run -d --name enclave-cn1 --restart unless-stopped \ - -p 9201:9201/udp \ - -v $PWD/ops/enclave/config:/home/ciphernode/.config/enclave \ - -v $PWD/ops/enclave/data:/home/ciphernode/.local/share/enclave \ - -v $PWD/ops/enclave/secrets.json:/run/secrets/secrets.json:ro \ - -e AGGREGATOR=false \ - enclave-ciphernode:latest -``` - -- The entrypoint reads `/run/secrets/secrets.json`, sets your password + keys, and then runs - `enclave start -v --config /home/ciphernode/.config/enclave/config.yaml`. -- Switch `AGGREGATOR=true` for plaintext aggregators. -- Mount any additional configs (TLS certs, Grafana agents, etc.) under the same directory and - reference them from `enclave.config.yaml`. -- To run CLI commands inside the container, use - `docker exec -it enclave-cn1 enclave ciphernode status --chain sepolia`. - -## Manual setup: initialize your ciphernode - -Start by running `enclave init` to create the initial configuration: - -```bash -enclave init -``` - -This command will: - -- Create `~/.config/enclave/config.yaml` with your node configuration -- Generate a network keypair in `~/.config/enclave/key` -- Set up the data directory at `~/.local/share/enclave/` - -During initialization, you'll be prompted for: - -- Your Ethereum address (the address that will participate in committees) -- A password to encrypt sensitive data -- RPC URL for the chain you want to connect to - -## Configuration - -After initialization, edit your `~/.config/enclave/config.yaml` to configure: - -### 1. Contract Addresses - -Update the contract addresses to match the network you're connecting to: - -```yaml -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8B…FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F6…0b1C7' - bonding_registry: - address: '0x5636…406E3' - fee_token: - address: '0xB58B…4De0' -``` - -### 2. Bootstrap Peers - -Add the bootstrap peer to join the network: - -```yaml -node: - address: '0xYourAddress' - quic_port: 9201 - peers: - - '/dnsaddr/bootstrap.enclave.gg' - autonetkey: true - autopassword: true -``` - -### 3. Set Your Wallet - -Configure your private key to sign transactions: - -```bash -enclave wallet set --private-key "0xYourPrivateKey" -``` - -**Warning:** Never share your private key. Keep it secure. - -## Starting Your Node - -Once configured, start your ciphernode: - -```bash -enclave start -``` - -Your node will: - -- Connect to the bootstrap peer(s) -- Subscribe to blockchain events -- Begin participating in sortition when E3s are requested - -## CLI lifecycle after deployment - -With the node running (via DAppNode, Docker, or bare metal) and your wallet already funded with the -required ENCL + stable tokens, move through the registry lifecycle using the CLI. Every command -accepts `--chain ` to select the chain entry from your config file and `--config ` if you -store configs outside the default. - -| Goal | Command | Result | -| --- | --- | --- | -| Bond ENCL license collateral | `enclave ciphernode license bond --amount 100 --chain sepolia` | Approves + bonds ENCL into the BondingRegistry | -| Deposit ticket backing (stablecoin) | `enclave ciphernode tickets buy --amount 100 --chain sepolia` | Approves fee token, mints ETK tickets | -| Register the operator | `enclave ciphernode register --chain sepolia` | Calls `registerOperator()` and unlocks sortition eligibility | -| Force an activation check | `enclave ciphernode activate --chain sepolia` | Replays `registerOperator()` if status drifted | -| Inspect state | `enclave ciphernode status --chain sepolia` | Prints bonded amounts, tickets, exits, and requirements | -| Remove stake during an exit | `enclave ciphernode deactivate --tickets 10 --license 20 --chain sepolia` | Withdraws tickets / unbonds license into the exit queue | -| Deregister completely | `enclave ciphernode deregister --proof 0xabc,0xdef --chain sepolia` | Calls `deregisterOperator()`, burning tickets immediately | -| Claim finished exits | `enclave ciphernode license claim --max-ticket 100 --max-license 100 --chain sepolia` | Calls `claimExits()` to pull unlocked funds | - -- For `tickets buy` and `license bond`, the CLI automatically checks ERC20 allowances and submits - approvals before calling the BondingRegistry. -- Capture the IMT siblings emitted in `CiphernodeAdded` to reuse later with the `--proof` flag. -- When running inside Docker/DAppNode, wrap commands with `docker exec -it ` so they can - access the mounted config and keystore. -- The lifecycle diagram in `ciphernode-operators/index.mdx` matches the sequence above: bond → - register → add tickets → stay active → deactivate/deregister → claim exits. - -## The Complete E3 Flow - -Here's what happens when an E3 (Encrypted Execution Environment) computation is requested: - -### Phase 1: E3 Request - -1. Someone calls `request()` on the Enclave contract with computation parameters -2. A new E3 ID is created with a random seed -3. The contract emits an `E3Requested` event - -### Phase 2: Committee Selection (Sortition) - -1. **Ticket Submission**: Your ciphernode listens for `E3Requested` events -2. **Score Calculation**: Your node calculates a sortition score based on: - - The E3 seed - - Your tickets/stake - - Your node's tickets -3. **Committee Finalization**: The top N nodes with the best scores are selected -4. If selected, you'll receive a `CommitteeFinalized` event with your party ID - -### Phase 3: Keyshare Generation - -When your node is selected for a committee: - -1. **Generate Secret**: Your node generates a secret key share and public key share -2. **Publish Keyshare**: The public key share is broadcast via libp2p and published onchain -3. **Storage**: The secret is encrypted and stored in `~/.local/share/enclave/jobs//` - -### Phase 4: Public Key Aggregation - -1. **Collect Keyshares**: An aggregator node collects all N public key shares from the committee -2. **Aggregate**: Once all shares are received, they're combined into a single public encryption key -3. **Publish**: The aggregated public key is published onchain via `publishPublicKey()` -4. The contract emits `PublicKeyAggregated` event -5. The E3 is now activated and ready to receive encrypted inputs - -### Phase 5: Input Window - -During this phase: - -1. Data providers encrypt their inputs using the aggregated public key -2. They submit encrypted data to the contract via `publishInput()` -3. The E3 Program validates each input -4. Input hashes are added to a Merkle tree onchain - -### Phase 6: Computation - -1. **Deadline Passes**: Once the input window closes, computation can begin -2. **Compute Provider Execution**: A compute provider (or E3 program) retrieves all encrypted inputs -3. **FHE Computation**: The computation runs entirely on encrypted data -4. **Output Generation**: The result is produced as encrypted ciphertext with a ZK proof - -### Phase 7: Ciphertext Publishing - -1. The compute provider calls `publishCiphertextOutput()` with the encrypted result and proof -2. The contract verifies the proof -3. Contract emits `CiphertextOutputPublished` event -4. All committee members are notified to begin decryption - -### Phase 8: Decryption Share Generation - -When your ciphernode receives `CiphertextOutputPublished`: - -1. **Load Secret**: Your node retrieves the encrypted secret key share from storage -2. **Decrypt Secret**: The secret is decrypted using your node's cipher -3. **Generate Share**: Your node creates a decryption share by partially decrypting the ciphertext -4. **Publish Share**: The decryption share is broadcast via libp2p and published onchain -5. Your node emits `DecryptionshareCreated` event - -### Phase 9: Plaintext Aggregation - -1. **Collect Shares**: An aggregator node collects decryption shares from committee members -2. **Threshold Met**: Once M-of-N threshold shares are received (e.g., 3 of 5) -3. **Aggregate**: The aggregator combines the shares to decrypt the final plaintext -4. **Publish Result**: The plaintext is published onchain via `publishPlaintextOutput()` -5. Contract emits `PlaintextOutputPublished` event -6. **Rewards**: Committee members receive their rewards for successful completion - -### Phase 10: Completion - -1. The plaintext output is now available onchain -2. Anyone can query `getE3()` to retrieve the result -3. Your node clears the secret from memory -4. The E3 round is complete - -## Monitoring Your Node - -### Check Node Status - -View your node's logs depending on how you're running it: - -```bash -# If running as a systemd service -journalctl -u enclave -f - -# If running directly or in a container, check the process -ps aux | grep enclave - -# Or check container logs if using Docker -docker logs -f -``` - -### What to Watch For - -Your node logs will show: - -- `E3Requested` - New computation request detected -- `TicketGenerated` - Your sortition ticket was calculated -- `CiphernodeSelected` - You were selected for a committee -- `KeyshareCreated` - Your keyshare was generated -- `PublicKeyAggregated` - Committee public key is ready -- `CiphertextOutputPublished` - Time to generate decryption share -- `DecryptionshareCreated` - Your decryption share was published -- `PlaintextAggregated` - Final result is available - -## Important Notes - -### Stay Online - -- Your node must be online and responsive during all phases of an E3 you're selected for -- Missing keyshare publication or decryption share submission may result in slashing - -### Network Connectivity - -- Ensure your `quic_port` (UDP) is accessible from the internet -- Maintain stable connections to bootstrap peers -- Consider running your own bootstrap node for redundancy - -### RPC Reliability - -- Use reliable RPC endpoints (consider running your own node) -- Have backup RPC URLs configured -- Monitor RPC connectivity and switch if needed - -### Data Persistence - -- The `~/.local/share/enclave/` directory contains critical job data -- Back up this directory regularly -- Do not delete data for active E3s - -### Key Security - -- Your network keypair is stored in `~/.config/enclave/key` -- Your wallet private key is encrypted in the config -- Never share these files or your private keys +--- +title: 'Running a Ciphernode' +--- + +# Running a Ciphernode + +This guide walks you through setting up and running a ciphernode, then explains the complete +computation flow from E3 request to plaintext decryption. + +## Deployment paths + +### DAppNode UI (IPFS package) + +If you're already running DAppNode, install the packaged service instead of hand-building +containers: + +1. Open **Packages → Install from IPFS hash** in the DAppNode UI, then paste + `QmeX7jxDFcwbW7kAbs8Tgn5T4vonYxe4WmemUQsaca8xDQ`. This pulls + `enclave-ciphernode.public.dappnode.eth@0.1.0`. +2. After the download finishes, click **Configure** on the package tile to launch the wizard. +3. Fill the wizard fields with the same addresses listed in the contract table on this page. The + following values keep you in-sync with the public Sepolia network: + +| Wizard field | Value / Notes | +| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | +| `Network` | `sepolia` (mainnet + localhost are also available) | +| `RPC URL` | WebSocket endpoint, e.g. `wss://ethereum-sepolia.publicnode.com` | +| `Node Address` | Operator address funded with ENCL and the stable token (ETK backing) | +| `Private Key` | Matches `Node Address`; stored as a secret in the container | +| `Bootstrap Peers` | `/dnsaddr/bootstrap.enclave.gg` (add more comma-separated peers as needed) | +| `Node Role` | `ciphernode` (switch to `aggregator` only if this host should aggregate plaintext) | +| `Enclave / CiphernodeRegistry / BondingRegistry` | Use the Sepolia addresses from this doc or your deployment artifact | +| `*_DEPLOY_BLOCK` | Block numbers for each contract (Sepolia example: Enclave `9615399`) | +| `ENCRYPTION_PASSWORD`, `NETWORK_PRIVATE_KEY` | Provide values to keep deterministic peer IDs across restarts; leave blank to auto-generate | + +The wizard writes `config.yaml` from `config.template.yaml`, injects your answers as environment +variables, and persists `/data` so restarts do not erase the node database. After the wizard +completes: + +- Click **Start** to boot the service. DAppNode automatically runs `enclave start -v` with your + config. +- Use the **Logs** tab or `docker logs -f enclave-ciphernode.public.dappnode.eth` to watch the + bootstrap process. +- To override CLI arguments, edit the package's `EXTRA_OPTS` field (for example, to add + `--peer /dnsaddr/bootstrap.enclave.gg` while testing new peers). +- When you need to refresh secrets, stop the service, update the wizard values, and start it again. + +### Standalone Docker container + +Prefer to run a single node outside DAppNode? Build from the repo and mount your config + secrets: + +```bash +# From the repository root +docker build -f crates/Dockerfile -t enclave-ciphernode:latest . + +mkdir -p ops/enclave/config ops/enclave/data +cat <<'EOF' > ops/enclave/config/enclave.config.yaml +node: + address: '0xYourOperator' + quic_port: 9201 + peers: + - '/dnsaddr/bootstrap.enclave.gg' + autonetkey: true + autopassword: true +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia.publicnode.com' + contracts: + enclave: + address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + bonding_registry: + address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' + fee_token: + address: '0xB58B762748c64f1a36B34012d1C52503617f4De0' +EOF + +cat <<'EOF' > ops/enclave/secrets.json +{ + "password": "choose-a-long-passphrase", + "private_key": "0x", + "network_private_key": "0x" +} +EOF + +docker run -d --name enclave-cn1 --restart unless-stopped \ + -p 9201:9201/udp \ + -v $PWD/ops/enclave/config:/home/ciphernode/.config/enclave \ + -v $PWD/ops/enclave/data:/home/ciphernode/.local/share/enclave \ + -v $PWD/ops/enclave/secrets.json:/run/secrets/secrets.json:ro \ + -e AGGREGATOR=false \ + enclave-ciphernode:latest +``` + +- The entrypoint reads `/run/secrets/secrets.json`, sets your password + keys, and then runs + `enclave start -v --config /home/ciphernode/.config/enclave/config.yaml`. +- Switch `AGGREGATOR=true` for plaintext aggregators. +- Mount any additional configs (TLS certs, Grafana agents, etc.) under the same directory and + reference them from `enclave.config.yaml`. +- To run CLI commands inside the container, use + `docker exec -it enclave-cn1 enclave ciphernode status --chain sepolia`. + +## Manual setup: initialize your ciphernode + +Start by running `enclave init` to create the initial configuration: + +```bash +enclave init +``` + +This command will: + +- Create `~/.config/enclave/config.yaml` with your node configuration +- Generate a network keypair in `~/.config/enclave/key` +- Set up the data directory at `~/.local/share/enclave/` + +During initialization, you'll be prompted for: + +- Your Ethereum address (the address that will participate in committees) +- A password to encrypt sensitive data +- RPC URL for the chain you want to connect to + +## Configuration + +After initialization, edit your `~/.config/enclave/config.yaml` to configure: + +### 1. Contract Addresses + +Update the contract addresses to match the network you're connecting to: + +```yaml +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia.publicnode.com' + contracts: + enclave: + address: '0x1E8B…FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F6…0b1C7' + bonding_registry: + address: '0x5636…406E3' + fee_token: + address: '0xB58B…4De0' +``` + +### 2. Bootstrap Peers + +Add the bootstrap peer to join the network: + +```yaml +node: + address: '0xYourAddress' + quic_port: 9201 + peers: + - '/dnsaddr/bootstrap.enclave.gg' + autonetkey: true + autopassword: true +``` + +### 3. Set Your Wallet + +Configure your private key to sign transactions: + +```bash +enclave wallet set --private-key "0xYourPrivateKey" +``` + +**Warning:** Never share your private key. Keep it secure. + +## Starting Your Node + +Once configured, start your ciphernode: + +```bash +enclave start +``` + +Your node will: + +- Connect to the bootstrap peer(s) +- Subscribe to blockchain events +- Begin participating in sortition when E3s are requested + +## CLI lifecycle after deployment + +With the node running (via DAppNode, Docker, or bare metal) and your wallet already funded with the +required ENCL + stable tokens, move through the registry lifecycle using the CLI. Every command +accepts `--chain ` to select the chain entry from your config file and `--config ` if +you store configs outside the default. + +| Goal | Command | Result | +| ----------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------ | +| Bond ENCL license collateral | `enclave ciphernode license bond --amount 100 --chain sepolia` | Approves + bonds ENCL into the BondingRegistry | +| Deposit ticket backing (stablecoin) | `enclave ciphernode tickets buy --amount 100 --chain sepolia` | Approves fee token, mints ETK tickets | +| Register the operator | `enclave ciphernode register --chain sepolia` | Calls `registerOperator()` and unlocks sortition eligibility | +| Force an activation check | `enclave ciphernode activate --chain sepolia` | Replays `registerOperator()` if status drifted | +| Inspect state | `enclave ciphernode status --chain sepolia` | Prints bonded amounts, tickets, exits, and requirements | +| Remove stake during an exit | `enclave ciphernode deactivate --tickets 10 --license 20 --chain sepolia` | Withdraws tickets / unbonds license into the exit queue | +| Deregister completely | `enclave ciphernode deregister --proof 0xabc,0xdef --chain sepolia` | Calls `deregisterOperator()`, burning tickets immediately | +| Claim finished exits | `enclave ciphernode license claim --max-ticket 100 --max-license 100 --chain sepolia` | Calls `claimExits()` to pull unlocked funds | + +- For `tickets buy` and `license bond`, the CLI automatically checks ERC20 allowances and submits + approvals before calling the BondingRegistry. +- Capture the IMT siblings emitted in `CiphernodeAdded` to reuse later with the `--proof` flag. +- When running inside Docker/DAppNode, wrap commands with `docker exec -it ` so they can + access the mounted config and keystore. +- The lifecycle diagram in `ciphernode-operators/index.mdx` matches the sequence above: bond → + register → add tickets → stay active → deactivate/deregister → claim exits. + +## The Complete E3 Flow + +Here's what happens when an E3 (Encrypted Execution Environment) computation is requested: + +### Phase 1: E3 Request + +1. Someone calls `request()` on the Enclave contract with computation parameters +2. A new E3 ID is created with a random seed +3. The contract emits an `E3Requested` event + +### Phase 2: Committee Selection (Sortition) + +1. **Ticket Submission**: Your ciphernode listens for `E3Requested` events +2. **Score Calculation**: Your node calculates a sortition score based on: + - The E3 seed + - Your tickets/stake + - Your node's tickets +3. **Committee Finalization**: The top N nodes with the best scores are selected +4. If selected, you'll receive a `CommitteeFinalized` event with your party ID + +### Phase 3: Keyshare Generation + +When your node is selected for a committee: + +1. **Generate Secret**: Your node generates a secret key share and public key share +2. **Publish Keyshare**: The public key share is broadcast via libp2p and published onchain +3. **Storage**: The secret is encrypted and stored in `~/.local/share/enclave/jobs//` + +### Phase 4: Public Key Aggregation + +1. **Collect Keyshares**: An aggregator node collects all N public key shares from the committee +2. **Aggregate**: Once all shares are received, they're combined into a single public encryption key +3. **Publish**: The aggregated public key is published onchain via `publishPublicKey()` +4. The contract emits `PublicKeyAggregated` event +5. The E3 is now activated and ready to receive encrypted inputs + +### Phase 5: Input Window + +During this phase: + +1. Data providers encrypt their inputs using the aggregated public key +2. They submit encrypted data to the contract via `publishInput()` +3. The E3 Program validates each input +4. Input hashes are added to a Merkle tree onchain + +### Phase 6: Computation + +1. **Deadline Passes**: Once the input window closes, computation can begin +2. **Compute Provider Execution**: A compute provider (or E3 program) retrieves all encrypted inputs +3. **FHE Computation**: The computation runs entirely on encrypted data +4. **Output Generation**: The result is produced as encrypted ciphertext with a ZK proof + +### Phase 7: Ciphertext Publishing + +1. The compute provider calls `publishCiphertextOutput()` with the encrypted result and proof +2. The contract verifies the proof +3. Contract emits `CiphertextOutputPublished` event +4. All committee members are notified to begin decryption + +### Phase 8: Decryption Share Generation + +When your ciphernode receives `CiphertextOutputPublished`: + +1. **Load Secret**: Your node retrieves the encrypted secret key share from storage +2. **Decrypt Secret**: The secret is decrypted using your node's cipher +3. **Generate Share**: Your node creates a decryption share by partially decrypting the ciphertext +4. **Publish Share**: The decryption share is broadcast via libp2p and published onchain +5. Your node emits `DecryptionshareCreated` event + +### Phase 9: Plaintext Aggregation + +1. **Collect Shares**: An aggregator node collects decryption shares from committee members +2. **Threshold Met**: Once M-of-N threshold shares are received (e.g., 3 of 5) +3. **Aggregate**: The aggregator combines the shares to decrypt the final plaintext +4. **Publish Result**: The plaintext is published onchain via `publishPlaintextOutput()` +5. Contract emits `PlaintextOutputPublished` event +6. **Rewards**: Committee members receive their rewards for successful completion + +### Phase 10: Completion + +1. The plaintext output is now available onchain +2. Anyone can query `getE3()` to retrieve the result +3. Your node clears the secret from memory +4. The E3 round is complete + +## Monitoring Your Node + +### Check Node Status + +View your node's logs depending on how you're running it: + +```bash +# If running as a systemd service +journalctl -u enclave -f + +# If running directly or in a container, check the process +ps aux | grep enclave + +# Or check container logs if using Docker +docker logs -f +``` + +### What to Watch For + +Your node logs will show: + +- `E3Requested` - New computation request detected +- `TicketGenerated` - Your sortition ticket was calculated +- `CiphernodeSelected` - You were selected for a committee +- `KeyshareCreated` - Your keyshare was generated +- `PublicKeyAggregated` - Committee public key is ready +- `CiphertextOutputPublished` - Time to generate decryption share +- `DecryptionshareCreated` - Your decryption share was published +- `PlaintextAggregated` - Final result is available + +## Important Notes + +### Stay Online + +- Your node must be online and responsive during all phases of an E3 you're selected for +- Missing keyshare publication or decryption share submission may result in slashing + +### Network Connectivity + +- Ensure your `quic_port` (UDP) is accessible from the internet +- Maintain stable connections to bootstrap peers +- Consider running your own bootstrap node for redundancy + +### RPC Reliability + +- Use reliable RPC endpoints (consider running your own node) +- Have backup RPC URLs configured +- Monitor RPC connectivity and switch if needed + +### Data Persistence + +- The `~/.local/share/enclave/` directory contains critical job data +- Back up this directory regularly +- Do not delete data for active E3s + +### Key Security + +- Your network keypair is stored in `~/.config/enclave/key` +- Your wallet private key is encrypted in the config +- Never share these files or your private keys diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx index 130e8b2404..7f373d2ab1 100644 --- a/docs/pages/ciphernode-operators/registration.mdx +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -1,117 +1,117 @@ ---- -title: 'Registration & Licensing' ---- - -# Registration & Licensing - -This guide covers everything required to become an active Ciphernode: collateral, bonding, -registration transactions, and config secrets. - -## Before you start - -| Track | Checklist | -| --- | --- | -| Financial | ENCL covering `licenseRequiredBond`, USDC covering at least `minTicketBalance * ticketPrice`, and ETH for gas | -| Technical | Enclave CLI ≥ current release, WebSocket RPC, `enclave password/net keypair/wallet` secrets set | -| Operational | `enclave.config.yaml` committed, secrets mirrored into `deploy/*.secrets.json`, monitoring hooks for registration state | - -Adjust the numbers using `cast call $BONDING` for `licenseRequiredBond()`, `ticketPrice()` and -`minTicketBalance()` on your target network. - -## Economic requirements - -Sepolia defaults (check `BondingRegistry` on your network): - -- **Ticket price**: `10_000_000` base units (10 USDC per ticket) -- **License bond requirement**: `100 ENCL` -- **Active license floor**: 80% of the required bond must remain locked -- **Minimum ticket balance**: 1 ticket (10 USDC) -- **Exit delay**: `604_800 s` (7 days) - -Tickets live inside the non-transferable `EnclaveTicketToken`. Mint them by depositing the underlying -stablecoin (MockUSDC on Sepolia) via `BondingRegistry.addTicketBalance`. The usable ticket count is: - - -`availableTickets = floor(ticketTokenBalance / ticketPrice)` - -License bonds are denominated in ENCL. Falling below 80% of `licenseRequiredBond` moves the operator -back to `inactive` even if tickets remain. - -## CLI prerequisites - -Before bonding, prepare local secrets: - -```bash -# Set up config (or pass --config later) -enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS - -# Store secrets (optional if using automation) -enclave password set --password "$PASSWORD" -enclave net keypair -enclave wallet set --private-key $OPERATOR_KEY -``` - -These commands populate `~/.config/enclave` and `~/.local/share/enclave`. For containerized -deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). - -## Lifecycle checklist - -1. **Acquire collateral** - - ENCL for license bonds - - USDC (or the configured fee token) for tickets -2. **Bond the license** - ```bash - cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -3. **Register the operator** - ```bash - cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -4. **Deposit tickets** - ```bash - cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - ``` -5. **Verify status** - ```bash - cast call $BONDING "isRegistered(address)" $OPERATOR - cast call $BONDING "isActive(address)" $OPERATOR - cast call $BONDING "getLicenseBond(address)" $OPERATOR - cast call $BONDING "getTicketBalance(address)" $OPERATOR - ``` -6. **Add buffers (optional)** - - Maintain ≥ 1.1× the minimum license bond so transient unbonds or slashes do not deactivate you - - Keep a few extra tickets so `availableTickets` never dips below the floor -7. **Snapshot config for production** - - Commit `enclave.config.yaml` alongside deployment manifests - - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely - -> The wallet private key is encrypted and stored in the config. Ensure you have set the correct -> operator key with `enclave wallet set` before running bonding transactions. - -## One-command bootstrap (optional) - -Hardhat ships with a helper task that strings approvals + bonding + registration together: - -```bash -npx hardhat ciphernode:add \ - --license-bond-amount 100000000000000000000 \ - --ticket-amount 10000000 -``` - -It calls `bondLicense`, `registerOperator`, and `addTicketBalance` under the hood. Production nodes -usually stick with explicit `cast` or `enclave` commands for better observability and auditing. - -## Status probes to monitor - -Once bonded, keep lightweight probes in your monitoring stack: - -```bash -cast call $BONDING "minTicketBalance()" -cast call $BONDING "ticketPrice()" -cast call $BONDING "licenseRequiredBond()" -cast call $BONDING "hasExitInProgress(address)" $OPERATOR -``` - -Pause automation if any probe changes unexpectedly until you reconcile it with a governance action -or migration plan. +--- +title: 'Registration & Licensing' +--- + +# Registration & Licensing + +This guide covers everything required to become an active Ciphernode: collateral, bonding, +registration transactions, and config secrets. + +## Before you start + +| Track | Checklist | +| ----------- | ----------------------------------------------------------------------------------------------------------------------- | +| Financial | ENCL covering `licenseRequiredBond`, USDC covering at least `minTicketBalance * ticketPrice`, and ETH for gas | +| Technical | Enclave CLI ≥ current release, WebSocket RPC, `enclave password/net keypair/wallet` secrets set | +| Operational | `enclave.config.yaml` committed, secrets mirrored into `deploy/*.secrets.json`, monitoring hooks for registration state | + +Adjust the numbers using `cast call $BONDING` for `licenseRequiredBond()`, `ticketPrice()` and +`minTicketBalance()` on your target network. + +## Economic requirements + +Sepolia defaults (check `BondingRegistry` on your network): + +- **Ticket price**: `10_000_000` base units (10 USDC per ticket) +- **License bond requirement**: `100 ENCL` +- **Active license floor**: 80% of the required bond must remain locked +- **Minimum ticket balance**: 1 ticket (10 USDC) +- **Exit delay**: `604_800 s` (7 days) + +Tickets live inside the non-transferable `EnclaveTicketToken`. Mint them by depositing the +underlying stablecoin (MockUSDC on Sepolia) via `BondingRegistry.addTicketBalance`. The usable +ticket count is: + +`availableTickets = floor(ticketTokenBalance / ticketPrice)` + +License bonds are denominated in ENCL. Falling below 80% of `licenseRequiredBond` moves the operator +back to `inactive` even if tickets remain. + +## CLI prerequisites + +Before bonding, prepare local secrets: + +```bash +# Set up config (or pass --config later) +enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS + +# Store secrets (optional if using automation) +enclave password set --password "$PASSWORD" +enclave net keypair +enclave wallet set --private-key $OPERATOR_KEY +``` + +These commands populate `~/.config/enclave` and `~/.local/share/enclave`. For containerized +deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). + +## Lifecycle checklist + +1. **Acquire collateral** + - ENCL for license bonds + - USDC (or the configured fee token) for tickets +2. **Bond the license** + ```bash + cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +3. **Register the operator** + ```bash + cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC + ``` +4. **Deposit tickets** + ```bash + cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + ``` +5. **Verify status** + ```bash + cast call $BONDING "isRegistered(address)" $OPERATOR + cast call $BONDING "isActive(address)" $OPERATOR + cast call $BONDING "getLicenseBond(address)" $OPERATOR + cast call $BONDING "getTicketBalance(address)" $OPERATOR + ``` +6. **Add buffers (optional)** + - Maintain ≥ 1.1× the minimum license bond so transient unbonds or slashes do not deactivate you + - Keep a few extra tickets so `availableTickets` never dips below the floor +7. **Snapshot config for production** + - Commit `enclave.config.yaml` alongside deployment manifests + - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely + +> The wallet private key is encrypted and stored in the config. Ensure you have set the correct +> operator key with `enclave wallet set` before running bonding transactions. + +## One-command bootstrap (optional) + +Hardhat ships with a helper task that strings approvals + bonding + registration together: + +```bash +npx hardhat ciphernode:add \ + --license-bond-amount 100000000000000000000 \ + --ticket-amount 10000000 +``` + +It calls `bondLicense`, `registerOperator`, and `addTicketBalance` under the hood. Production nodes +usually stick with explicit `cast` or `enclave` commands for better observability and auditing. + +## Status probes to monitor + +Once bonded, keep lightweight probes in your monitoring stack: + +```bash +cast call $BONDING "minTicketBalance()" +cast call $BONDING "ticketPrice()" +cast call $BONDING "licenseRequiredBond()" +cast call $BONDING "hasExitInProgress(address)" $OPERATOR +``` + +Pause automation if any probe changes unexpectedly until you reconcile it with a governance action +or migration plan. diff --git a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx index 8c8c14afc0..449af514c4 100644 --- a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx +++ b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx @@ -1,139 +1,139 @@ ---- -title: 'Tickets & Sortition' ---- - -# Tickets & Sortition - -> Ticket availability: `availableTickets = floor(ticketTokenBalance / ticketPrice)` - -| Stake | Token | Purpose | Key calls | -| ------------ | -------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- | -| License bond | ENCL | Unlock registration + maintain eligibility | `bondLicense`, `unbondLicense`, `getLicenseBond` | -| Tickets | ETK (non-transferable, backed by USDC) | Determine committee probability | `addTicketBalance`, `removeTicketBalance`, `getTicketBalance`, `availableTickets` | - -- Keep ≥ `licenseRequiredBond * 0.8` bonded or `isActive` flips false. -- Hold ≥ `minTicketBalance` tickets so the registry considers you for committees. -- Check `hasExitInProgress` / `pendingExits` before rebonding; queued exits block new registrations. - -## Ticket economics - -- Tickets are priced in stablecoins, minted into non-transferable ETK balances, and track intent to - work. -- Committee probability scales linearly with `availableTickets`; doubling tickets doubles your odds - if peers stay constant. -- Balances are snapshotted at `requestBlock - 1`. Adding tickets after the request event does not - change that round. -- Rewards accrue only when committees form and you complete duties, so idle tickets still incur the - opportunity cost of locked capital. - -### Managing ticket balance - -```bash -# Approve USDC (or configured fee token) -cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - -# Add tickets (mints ETK) -cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - -# Remove tickets (burns ETK, returns USDC) -cast send $BONDING "removeTicketBalance(uint256)" 500e6 --rpc-url $RPC --private-key $OPERATOR_KEY -``` - -`removeTicketBalance` takes effect immediately. Dropping below the minimum ticket balance makes you -inactive until you top up again. - -### Rebalancing tips - -- Add tickets one or two requests ahead of anticipated demand to avoid race-condition gas spikes. -- Keep a small ticket buffer so slashing or removals do not instantly deactivate you. -- Monitor `ticketPrice()` and `minTicketBalance()` before automating deposits on multiple networks. - -## Sortition algorithm - -```mermaid -flowchart TD - A[E3Requested event] --> B[Snapshot balances (requestBlock - 1)] - B --> C[CLI filters active + ticketed operators] - C --> D[Submit numbered tickets via submitTicket] - D --> E[TicketSubmitted events expose scores] - E --> F[Finalize committee after submission deadline] - F --> G[Publish committee public key] - G --> H[Execute jobs (keyshares, ciphertext, decryption)] -``` - -### 1. Event intake & eligibility - -1. `Enclave` requests a committee, triggering `CommitteeRequested` with the round seed, threshold, - and submission deadline. -2. Nodes snapshot balances at `requestBlock - 1` and build an **eligible set** where operators are: - - Registered and not banned - - `isActive` (bond + ticket minimums satisfied) - - Not in the middle of an exit - -### 2. Score-based selection - -Sortition is deterministic once the seed and eligible set are known: - -1. Derive per-ticket scores with `keccak256(seed, operator, ticketNumber)`. -2. Sort scores and take the top `threshold_n` entries. -3. Because the same inputs yield the same winners, every honest node converges on the same - committee. - -### 3. Ticket submissions & committee finalization - -1. Operators submit each winning ticket via `submitTicket(e3Id, ticketNumber)` during the - `sortitionSubmissionWindow` (10s on Sepolia). -2. Every submission emits `TicketSubmitted(e3Id, operator, ticketNumber, score)` so you can audit - progress. -3. After the window closes and ≥ `threshold_m` tickets are present, anyone calls - `finalizeCommittee(e3Id)`; the registry emits `CommitteeFinalized`. -4. Once enough key shares are ready, the CLI drives `publishCommittee`, emitting - `CommitteePublished` with the aggregated key. - -### 4. Committee operations - -- Generate and encrypt PVSS key shares for the round. -- Publish the committee public key once the threshold is met. -- Stay online for `CiphertextOutputPublished` and respond with decryption shares until - `PlaintextOutputPublished` confirms completion. - -See the [Operations & Responsibilities](./operations) page for the detailed job lifecycle. - -## Parameter reference - -```solidity -uint32[2] threshold; // [threshold_m, threshold_n] -``` - -- `threshold_m` — Minimum number of operators needed for duties (e.g., 3). -- `threshold_n` — Committee size (e.g., 5). The CLI submits up to this many tickets per E3. -- Use `CiphernodeRegistry.sortitionSubmissionWindow()` to size your submission workers. - -## Monitoring & troubleshooting - -### Signals to watch - -- `CommitteeRequested`, `TicketSubmitted`, `CommitteeFinalized`, and `CommitteePublished` events. -- CLI logs: `sortition::submitted`, `sortition::missed`, `jobs::selected`. -- Contract reads: `submissions(e3Id, operator)` to confirm ticket IDs and `getCommitteeNodes(e3Id)` - post-finalization. - -### Common issues - -| Symptom | Checks | Fix | -| ------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| Not being selected | Verify `isActive`, ticket balance ≥ minimum, no bans, and compare tickets to peers | Add tickets, rebond license, or appeal bans | -| `SubmissionWindowClosed` errors | Ensure submissions start immediately after `CommitteeRequested` and that RPC latency is low | Increase submission workers, reduce per-ticket delays | -| Committee missing operator | Confirm CLI derived the same winners (seed + tickets) and that submissions succeeded | Replay submissions, inspect `TicketSubmitted` logs, retry with correct ticket IDs | - -## Best practices - -- **Stagger ticket top-ups** to avoid last-minute gas spikes. -- **Alert on missed submissions** so humans can intervene before committee deadlines. -- **Batch networks** by running separate CLI supervisors per chain; congestion on one network should - not block another. -- **Track governance knobs** like `sortitionSubmissionWindow`, `ticketPrice`, and - `licenseRequiredBond` so automation adapts when values change. - -For deeper visuals, skim `crates/sortition/README` or the ciphernodes architecture docs; they mirror -the same deterministic score-based flow described here. +--- +title: 'Tickets & Sortition' +--- + +# Tickets & Sortition + +> Ticket availability: `availableTickets = floor(ticketTokenBalance / ticketPrice)` + +| Stake | Token | Purpose | Key calls | +| ------------ | -------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- | +| License bond | ENCL | Unlock registration + maintain eligibility | `bondLicense`, `unbondLicense`, `getLicenseBond` | +| Tickets | ETK (non-transferable, backed by USDC) | Determine committee probability | `addTicketBalance`, `removeTicketBalance`, `getTicketBalance`, `availableTickets` | + +- Keep ≥ `licenseRequiredBond * 0.8` bonded or `isActive` flips false. +- Hold ≥ `minTicketBalance` tickets so the registry considers you for committees. +- Check `hasExitInProgress` / `pendingExits` before rebonding; queued exits block new registrations. + +## Ticket economics + +- Tickets are priced in stablecoins, minted into non-transferable ETK balances, and track intent to + work. +- Committee probability scales linearly with `availableTickets`; doubling tickets doubles your odds + if peers stay constant. +- Balances are snapshotted at `requestBlock - 1`. Adding tickets after the request event does not + change that round. +- Rewards accrue only when committees form and you complete duties, so idle tickets still incur the + opportunity cost of locked capital. + +### Managing ticket balance + +```bash +# Approve USDC (or configured fee token) +cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + +# Add tickets (mints ETK) +cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY + +# Remove tickets (burns ETK, returns USDC) +cast send $BONDING "removeTicketBalance(uint256)" 500e6 --rpc-url $RPC --private-key $OPERATOR_KEY +``` + +`removeTicketBalance` takes effect immediately. Dropping below the minimum ticket balance makes you +inactive until you top up again. + +### Rebalancing tips + +- Add tickets one or two requests ahead of anticipated demand to avoid race-condition gas spikes. +- Keep a small ticket buffer so slashing or removals do not instantly deactivate you. +- Monitor `ticketPrice()` and `minTicketBalance()` before automating deposits on multiple networks. + +## Sortition algorithm + +```mermaid +flowchart TD + A[E3Requested event] --> B[Snapshot balances (requestBlock - 1)] + B --> C[CLI filters active + ticketed operators] + C --> D[Submit numbered tickets via submitTicket] + D --> E[TicketSubmitted events expose scores] + E --> F[Finalize committee after submission deadline] + F --> G[Publish committee public key] + G --> H[Execute jobs (keyshares, ciphertext, decryption)] +``` + +### 1. Event intake & eligibility + +1. `Enclave` requests a committee, triggering `CommitteeRequested` with the round seed, threshold, + and submission deadline. +2. Nodes snapshot balances at `requestBlock - 1` and build an **eligible set** where operators are: + - Registered and not banned + - `isActive` (bond + ticket minimums satisfied) + - Not in the middle of an exit + +### 2. Score-based selection + +Sortition is deterministic once the seed and eligible set are known: + +1. Derive per-ticket scores with `keccak256(seed, operator, ticketNumber)`. +2. Sort scores and take the top `threshold_n` entries. +3. Because the same inputs yield the same winners, every honest node converges on the same + committee. + +### 3. Ticket submissions & committee finalization + +1. Operators submit each winning ticket via `submitTicket(e3Id, ticketNumber)` during the + `sortitionSubmissionWindow` (10s on Sepolia). +2. Every submission emits `TicketSubmitted(e3Id, operator, ticketNumber, score)` so you can audit + progress. +3. After the window closes and ≥ `threshold_m` tickets are present, anyone calls + `finalizeCommittee(e3Id)`; the registry emits `CommitteeFinalized`. +4. Once enough key shares are ready, the CLI drives `publishCommittee`, emitting + `CommitteePublished` with the aggregated key. + +### 4. Committee operations + +- Generate and encrypt PVSS key shares for the round. +- Publish the committee public key once the threshold is met. +- Stay online for `CiphertextOutputPublished` and respond with decryption shares until + `PlaintextOutputPublished` confirms completion. + +See the [Operations & Responsibilities](./operations) page for the detailed job lifecycle. + +## Parameter reference + +```solidity +uint32[2] threshold; // [threshold_m, threshold_n] +``` + +- `threshold_m` — Minimum number of operators needed for duties (e.g., 3). +- `threshold_n` — Committee size (e.g., 5). The CLI submits up to this many tickets per E3. +- Use `CiphernodeRegistry.sortitionSubmissionWindow()` to size your submission workers. + +## Monitoring & troubleshooting + +### Signals to watch + +- `CommitteeRequested`, `TicketSubmitted`, `CommitteeFinalized`, and `CommitteePublished` events. +- CLI logs: `sortition::submitted`, `sortition::missed`, `jobs::selected`. +- Contract reads: `submissions(e3Id, operator)` to confirm ticket IDs and `getCommitteeNodes(e3Id)` + post-finalization. + +### Common issues + +| Symptom | Checks | Fix | +| ------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | +| Not being selected | Verify `isActive`, ticket balance ≥ minimum, no bans, and compare tickets to peers | Add tickets, rebond license, or appeal bans | +| `SubmissionWindowClosed` errors | Ensure submissions start immediately after `CommitteeRequested` and that RPC latency is low | Increase submission workers, reduce per-ticket delays | +| Committee missing operator | Confirm CLI derived the same winners (seed + tickets) and that submissions succeeded | Replay submissions, inspect `TicketSubmitted` logs, retry with correct ticket IDs | + +## Best practices + +- **Stagger ticket top-ups** to avoid last-minute gas spikes. +- **Alert on missed submissions** so humans can intervene before committee deadlines. +- **Batch networks** by running separate CLI supervisors per chain; congestion on one network should + not block another. +- **Track governance knobs** like `sortitionSubmissionWindow`, `ticketPrice`, and + `licenseRequiredBond` so automation adapts when values change. + +For deeper visuals, skim `crates/sortition/README` or the ciphernodes architecture docs; they mirror +the same deterministic score-based flow described here. diff --git a/docs/pages/computation-flow.mdx b/docs/pages/computation-flow.mdx index 8d01a70291..97158ed990 100644 --- a/docs/pages/computation-flow.mdx +++ b/docs/pages/computation-flow.mdx @@ -25,19 +25,19 @@ Providers, or other network participant. ```solidity function request( - E3RequestParams calldata requestParams + E3RequestParams calldata requestParams ) external returns (uint256 e3Id, E3 memory e3); ``` ```solidity struct E3RequestParams { - uint32[2] threshold; - uint256[2] startWindow; - uint256 duration; - IE3Program e3Program; - bytes e3ProgramParams; - bytes computeProviderParams; - bytes customParams; + uint32[2] threshold; + uint256[2] startWindow; + uint256 duration; + IE3Program e3Program; + bytes e3ProgramParams; + bytes computeProviderParams; + bytes customParams; } ``` diff --git a/docs/pages/compute-provider.mdx b/docs/pages/compute-provider.mdx index 19fe453f76..0dd48b02a9 100644 --- a/docs/pages/compute-provider.mdx +++ b/docs/pages/compute-provider.mdx @@ -52,14 +52,17 @@ the [Writing the Secure Process](./write-secure-program.mdx) guide. ### Setup -In this guide, we'll go over setting up [RISC Zero](https://www.risczero.com/) with [Boundless](https://docs.beboundless.xyz/) as the CP. +In this guide, we'll go over setting up [RISC Zero](https://www.risczero.com/) with +[Boundless](https://docs.beboundless.xyz/) as the CP. -Boundless provides a [Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) that can be -used to run the Secure Process and create a ZK proof using RISC Zero's zkVM. The template includes a basic program that can -be used to get started with the smart contract code to verify the proof. +Boundless provides a [Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) +that can be used to run the Secure Process and create a ZK proof using RISC Zero's zkVM. The +template includes a basic program that can be used to get started with the smart contract code to +verify the proof. -Follow the instructions in the [Boundless Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) -to setup RISC Zero with Boundless. +Follow the instructions in the +[Boundless Foundry template](https://github.com/boundless-xyz/boundless-foundry-template) to setup +RISC Zero with Boundless. Ensure the following tools are installed: @@ -97,13 +100,16 @@ Now you're ready to develop and deploy applications using RISC Zero with Boundle ### Boundless Configuration -Boundless is a decentralized proving marketplace for RISC Zero programs. Instead of running proofs locally, you can submit them to Boundless for faster, distributed proving. +Boundless is a decentralized proving marketplace for RISC Zero programs. Instead of running proofs +locally, you can submit them to Boundless for faster, distributed proving. To use Boundless: 1. Get access to an RPC endpoint (e.g., Infura, Alchemy) with funds 2. Obtain a private key with sufficient ETH/tokens for proof generation -3. (Optional) Get a Pinata JWT from [pinata.cloud](https://pinata.cloud) for uploading programs to IPFS -4. Configure your `enclave.config.yaml` as shown in the [CRISP setup guide](/CRISP/setup#boundless-configuration-production-proving) +3. (Optional) Get a Pinata JWT from [pinata.cloud](https://pinata.cloud) for uploading programs to + IPFS +4. Configure your `enclave.config.yaml` as shown in the + [CRISP setup guide](/CRISP/setup#boundless-configuration-production-proving) For more details, see the [Boundless documentation](https://docs.beboundless.xyz/). diff --git a/docs/pages/noir-circuits.mdx b/docs/pages/noir-circuits.mdx index bc24f210d9..056afb3724 100644 --- a/docs/pages/noir-circuits.mdx +++ b/docs/pages/noir-circuits.mdx @@ -1,82 +1,84 @@ ---- -title: 'Noir Circuits' -description: 'Build and reuse Noir circuits for Enclave programs' ---- - -# Noir Circuits & Libraries - -Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge, -polynomial utilities, GRECO hashing, etc.). Use these circuits as-is or vendor them into your own E3 -programs. - -## Workspace layout - -``` -circuits/ -├── Nargo.toml # workspace manifest -├── crates/ -│ └── libs/ -│ ├── safe/ # SAFE sponge implementation -│ ├── greco/ # Poseidon & Merkle helpers -│ └── polynomial/ # polynomial commitments utils -└── target/ # build artifacts (created by nargo) -``` - -Each library has its own `README.md` describing APIs and dependency stanza. Example (`safe`): - -```toml -[dependencies] -safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } -``` - -From `v0.1.6` onward the directory becomes `circuits/crates/libs/safe` (the `packages/` prefix was removed). - -## Tooling requirements - -Install the Noir toolchain: - -```bash -curl -L https://noir-lang.org/install | bash # installs nargo + bb -nargo --version # 1.0.0-beta.11+ -bb --version # v0.87.0+ -``` - -## Formatting & compilation - -Run the helper scripts from the repo root or reproduce them in your project: - -```bash -./scripts/compile-circuits.sh # nargo fmt --check && nargo compile --workspace -./scripts/lint-circuits.sh # format check + warnings -./scripts/test-circuits.sh # run circuit unit tests (nargo test) when available -``` - -These scripts exit early (without failing the whole build) if `nargo` is not installed, which makes CI happy -when Noir is optional. - -## Exporting verifiers - -Projects such as CRISP compile Noir circuits into Solidity verifiers using `bb`: - -```bash -cd examples/CRISP -./scripts/compile_circuits.sh -``` - -The script performs: - -1. `nargo compile` for every circuit in the workspace -2. `bb write_vk` to emit the verification key (`circuits/target/vk`) -3. `bb write_solidity_verifier` to produce `CRISPVerifier.sol` -4. Copies the generated verifier into `packages/crisp-contracts/contracts/` - -Adapt the script for your own circuits and verifiers by changing the output path. - -## Integrating with E3 programs - -- Import the library from `Nargo.toml` or `program/Cargo.toml` -- Generate Solidity verifiers and move them into your contract package -- Reference the compiled artifacts when deploying via the template or CRISP scripts - -When adding new circuits, remember to update `package.json` scripts (e.g., `pnpm dev:all`) so they call your -compile script before spinning up the dev environment. This keeps your verifiers in sync with the Noir source. +--- +title: 'Noir Circuits' +description: 'Build and reuse Noir circuits for Enclave programs' +--- + +# Noir Circuits & Libraries + +Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge, +polynomial utilities, GRECO hashing, etc.). Use these circuits as-is or vendor them into your own E3 +programs. + +## Workspace layout + +``` +circuits/ +├── Nargo.toml # workspace manifest +├── crates/ +│ └── libs/ +│ ├── safe/ # SAFE sponge implementation +│ ├── greco/ # Poseidon & Merkle helpers +│ └── polynomial/ # polynomial commitments utils +└── target/ # build artifacts (created by nargo) +``` + +Each library has its own `README.md` describing APIs and dependency stanza. Example (`safe`): + +```toml +[dependencies] +safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } +``` + +From `v0.1.6` onward the directory becomes `circuits/crates/libs/safe` (the `packages/` prefix was +removed). + +## Tooling requirements + +Install the Noir toolchain: + +```bash +curl -L https://noir-lang.org/install | bash # installs nargo + bb +nargo --version # 1.0.0-beta.11+ +bb --version # v0.87.0+ +``` + +## Formatting & compilation + +Run the helper scripts from the repo root or reproduce them in your project: + +```bash +./scripts/compile-circuits.sh # nargo fmt --check && nargo compile --workspace +./scripts/lint-circuits.sh # format check + warnings +./scripts/test-circuits.sh # run circuit unit tests (nargo test) when available +``` + +These scripts exit early (without failing the whole build) if `nargo` is not installed, which makes +CI happy when Noir is optional. + +## Exporting verifiers + +Projects such as CRISP compile Noir circuits into Solidity verifiers using `bb`: + +```bash +cd examples/CRISP +./scripts/compile_circuits.sh +``` + +The script performs: + +1. `nargo compile` for every circuit in the workspace +2. `bb write_vk` to emit the verification key (`circuits/target/vk`) +3. `bb write_solidity_verifier` to produce `CRISPVerifier.sol` +4. Copies the generated verifier into `packages/crisp-contracts/contracts/` + +Adapt the script for your own circuits and verifiers by changing the output path. + +## Integrating with E3 programs + +- Import the library from `Nargo.toml` or `program/Cargo.toml` +- Generate Solidity verifiers and move them into your contract package +- Reference the compiled artifacts when deploying via the template or CRISP scripts + +When adding new circuits, remember to update `package.json` scripts (e.g., `pnpm dev:all`) so they +call your compile script before spinning up the dev environment. This keeps your verifiers in sync +with the Noir source. diff --git a/docs/pages/project-template.mdx b/docs/pages/project-template.mdx index ec792a8456..e8d1c03625 100644 --- a/docs/pages/project-template.mdx +++ b/docs/pages/project-template.mdx @@ -1,95 +1,98 @@ ---- -title: 'Project Template' -description: 'What gets generated by `enclave init` and how to customize it' ---- - -# Default Project Template - -Running `enclave init ` clones the `templates/default` workspace into your directory and -adds a tailor-made `enclave.config.yaml`. The goal is to give you a full-stack, reproducible playground -for building and testing E3 programs without copying the entire monorepo. - -## Layout - -``` -my-first-e3/ -├── contracts/ # Hardhat workspace with Enclave adapters + your E3 program contracts -├── program/ # RISC Zero guest code and runner -├── server/ # TypeScript coordination server -├── client/ # React + Vite frontend wired to @enclave-e3/sdk -├── deploy/ # Scripts + ignition configs -├── scripts/ # Helper scripts (start dev stack, ciphernodes, etc.) -├── tests/ # Integration + contract tests -├── enclave.config.yaml # Node + chain config consumed by the CLI -├── package.json # Dev orchestrator scripts -└── .enclave/ # cached CLI state (ignored by git) -``` - -Each workspace shares the same `pnpm` root so dependencies stay in sync. - -## Commands - -| Script | Purpose | -| --- | --- | -| `pnpm dev:all` | Spins up Hardhat, deploys contracts, launches the RISC0 program server, coordination server, frontend, and ciphernodes. | -| `pnpm dev:evm` | Runs `hardhat node` on `http://localhost:8545`. | -| `pnpm dev:program` | Starts the RISC0 guest runner. Pass `--dev` to skip real proving. | -| `pnpm dev:server` | Boots the TypeScript coordination server with hot reload. | -| `pnpm dev:frontend` | Launches the Vite client on `http://localhost:3000`. | -| `pnpm dev:ciphernodes` | Calls the Enclave CLI to launch the nodes defined in `enclave.config.yaml`. | -| `pnpm compile` | Compiles Solidity contracts. | -| `pnpm test` | Runs Hardhat tests. | -| `pnpm test:integration` | Executes the end-to-end flow in `tests/`. | - -Before `dev:all` runs, the `predev:all` hook calls `enclave program compile` so the latest zkVM image -is ready; skip this by exporting `SKIP_PROGRAM_COMPILE=1`. - -## Environment files - -- `client/.env`: contains `VITE_` variables for contract addresses, RPC URLs, and optional feature flags. -- `server/.env`: holds the operator wallet key (never commit), RPC endpoints, and cron API tokens. -- `enclave.config.yaml`: describes your Ciphernodes and aggregator profile. The default file mirrors the - template you saw earlier in this repo. - -## Integrating the SDK - -The template already wires the [Enclave SDK](/sdk): - -- `client/src/sdk.ts` exports a singleton `EnclaveSDK` -- `client/src/hooks/useE3.ts` wraps `useEnclaveSDK` -- `server/src/services/enclave.ts` instantiates a wallet-backed SDK for automation - -Update the `.env` files after every redeploy so the SDK listens to the correct contracts. - -## Noir circuits & Nargo - -Although the template ships with a simple addition circuit, you can plug in Noir circuits by pointing to -this repo's shared libraries (`circuits/crates/libs/*`). Add dependencies in your `program/Cargo.toml` or -your Noir workspace's `Nargo.toml`: - -```toml -[dependencies] -safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } -``` - -Use the helper scripts in the root repo (`scripts/compile-circuits.sh`, `scripts/lint-circuits.sh`) as a -reference for formatting and compiling Noir workspaces via `nargo` and `bb`. Integrate similar scripts in -`my-first-e3/scripts/` if your application publishes verifiers alongside the template contracts. - -## Customizing Ciphernodes - -`enclave.config.yaml` includes multiple node profiles (`cn1`, `cn2`, `cn3`, `ag`). Update the addresses, -peers, and QUIC ports to match your deployment. For production, replace `autonetkey/autopassword` with -explicit secrets and run `enclave nodes up --detach` from a systemd service or container entrypoint. - -## Common tweaks - -- **Alternate compute providers**: edit `server/src/providers` to switch between RISC Zero dev-mode vs - real proving, or wire in a custom prover. -- **Program parameters**: `server/src/config/e3.ts` defines the default thresholds and time windows used - when calling `sdk.requestE3`. Adjust them to match your chain's latency. -- **Frontend UI**: `client/src/components/ResultCard.tsx` renders decrypted outputs—extend it with your - own domain logic. - -The template is intentionally opinionated so you can delete what you do not need while still referencing a -complete working stack. +--- +title: 'Project Template' +description: 'What gets generated by `enclave init` and how to customize it' +--- + +# Default Project Template + +Running `enclave init ` clones the `templates/default` workspace into your directory +and adds a tailor-made `enclave.config.yaml`. The goal is to give you a full-stack, reproducible +playground for building and testing E3 programs without copying the entire monorepo. + +## Layout + +``` +my-first-e3/ +├── contracts/ # Hardhat workspace with Enclave adapters + your E3 program contracts +├── program/ # RISC Zero guest code and runner +├── server/ # TypeScript coordination server +├── client/ # React + Vite frontend wired to @enclave-e3/sdk +├── deploy/ # Scripts + ignition configs +├── scripts/ # Helper scripts (start dev stack, ciphernodes, etc.) +├── tests/ # Integration + contract tests +├── enclave.config.yaml # Node + chain config consumed by the CLI +├── package.json # Dev orchestrator scripts +└── .enclave/ # cached CLI state (ignored by git) +``` + +Each workspace shares the same `pnpm` root so dependencies stay in sync. + +## Commands + +| Script | Purpose | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `pnpm dev:all` | Spins up Hardhat, deploys contracts, launches the RISC0 program server, coordination server, frontend, and ciphernodes. | +| `pnpm dev:evm` | Runs `hardhat node` on `http://localhost:8545`. | +| `pnpm dev:program` | Starts the RISC0 guest runner. Pass `--dev` to skip real proving. | +| `pnpm dev:server` | Boots the TypeScript coordination server with hot reload. | +| `pnpm dev:frontend` | Launches the Vite client on `http://localhost:3000`. | +| `pnpm dev:ciphernodes` | Calls the Enclave CLI to launch the nodes defined in `enclave.config.yaml`. | +| `pnpm compile` | Compiles Solidity contracts. | +| `pnpm test` | Runs Hardhat tests. | +| `pnpm test:integration` | Executes the end-to-end flow in `tests/`. | + +Before `dev:all` runs, the `predev:all` hook calls `enclave program compile` so the latest zkVM +image is ready; skip this by exporting `SKIP_PROGRAM_COMPILE=1`. + +## Environment files + +- `client/.env`: contains `VITE_` variables for contract addresses, RPC URLs, and optional feature + flags. +- `server/.env`: holds the operator wallet key (never commit), RPC endpoints, and cron API tokens. +- `enclave.config.yaml`: describes your Ciphernodes and aggregator profile. The default file mirrors + the template you saw earlier in this repo. + +## Integrating the SDK + +The template already wires the [Enclave SDK](/sdk): + +- `client/src/sdk.ts` exports a singleton `EnclaveSDK` +- `client/src/hooks/useE3.ts` wraps `useEnclaveSDK` +- `server/src/services/enclave.ts` instantiates a wallet-backed SDK for automation + +Update the `.env` files after every redeploy so the SDK listens to the correct contracts. + +## Noir circuits & Nargo + +Although the template ships with a simple addition circuit, you can plug in Noir circuits by +pointing to this repo's shared libraries (`circuits/crates/libs/*`). Add dependencies in your +`program/Cargo.toml` or your Noir workspace's `Nargo.toml`: + +```toml +[dependencies] +safe = { git = "https://github.com/gnosisguild/enclave", tag = "v0.1.5", directory = "circuits/crates/libs/safe" } +``` + +Use the helper scripts in the root repo (`scripts/compile-circuits.sh`, `scripts/lint-circuits.sh`) +as a reference for formatting and compiling Noir workspaces via `nargo` and `bb`. Integrate similar +scripts in `my-first-e3/scripts/` if your application publishes verifiers alongside the template +contracts. + +## Customizing Ciphernodes + +`enclave.config.yaml` includes multiple node profiles (`cn1`, `cn2`, `cn3`, `ag`). Update the +addresses, peers, and QUIC ports to match your deployment. For production, replace +`autonetkey/autopassword` with explicit secrets and run `enclave nodes up --detach` from a systemd +service or container entrypoint. + +## Common tweaks + +- **Alternate compute providers**: edit `server/src/providers` to switch between RISC Zero dev-mode + vs real proving, or wire in a custom prover. +- **Program parameters**: `server/src/config/e3.ts` defines the default thresholds and time windows + used when calling `sdk.requestE3`. Adjust them to match your chain's latency. +- **Frontend UI**: `client/src/components/ResultCard.tsx` renders decrypted outputs—extend it with + your own domain logic. + +The template is intentionally opinionated so you can delete what you do not need while still +referencing a complete working stack. diff --git a/docs/pages/quick-start.mdx b/docs/pages/quick-start.mdx index 2e6ee355fe..14a64ce372 100644 --- a/docs/pages/quick-start.mdx +++ b/docs/pages/quick-start.mdx @@ -106,7 +106,7 @@ Now that you have a working E3 program: 2. **Modify the computation**: Try changing the addition to multiplication 3. **Update the UI**: Customize the client in `./client/src/` 4. **Run real Ciphernodes**: Follow the [Ciphernode Operators guide](/ciphernode-operators) to bond -tokens, configure nodes, and join the shared network + tokens, configure nodes, and join the shared network 5. **Deploy**: Learn about production deployment Ready to dive deeper? Continue with our [Hello World Tutorial](/hello-world-tutorial) for a diff --git a/docs/pages/sdk.mdx b/docs/pages/sdk.mdx index 2e0643b948..ffb9a5ef5b 100644 --- a/docs/pages/sdk.mdx +++ b/docs/pages/sdk.mdx @@ -1,156 +1,152 @@ ---- -title: 'Enclave SDK' -description: 'Use the TypeScript + React SDKs to drive E3 programs from clients and services' ---- - -# Enclave SDK Overview - -The Enclave SDK (`@enclave-e3/sdk`) and React helpers (`@enclave-e3/react`) provide a batteries-included -client stack for requesting E3 computations, subscribing to protocol events, and coordinating custom -frontends or backend services. Both packages ship in this repository (see `packages/enclave-sdk` and -`packages/enclave-react`). - -## Installation - -```bash -pnpm add @enclave-e3/sdk # TypeScript SDK -pnpm add @enclave-e3/react # React hooks (optional) -``` - -For browser projects using WASM (encryption helpers, FHE keygen), configure Vite per the SDK README: - -```ts -// vite.config.ts -import wasm from 'vite-plugin-wasm' -import topLevelAwait from 'vite-plugin-top-level-await' - -export default defineConfig({ - optimizeDeps: { - exclude: ['@enclave-e3/wasm'], - }, - plugins: [wasm(), topLevelAwait()], -}) -``` - -## Core client - -```ts -import { EnclaveSDK, EnclaveEventType, RegistryEventType } from '@enclave-e3/sdk' -import { createPublicClient, createWalletClient, http, custom } from 'viem' - -const publicClient = createPublicClient({ transport: http(import.meta.env.VITE_RPC_URL) }) -const walletClient = createWalletClient({ transport: custom(window.ethereum) }) - -const sdk = new EnclaveSDK({ - publicClient, - walletClient, - contracts: { - enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, - ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, - }, - chainId: 11155111, -}) - -await sdk.initialize() -``` - -### Requesting computations - -```ts -const hash = await sdk.requestE3({ - threshold: [2, 3], - startWindow: [BigInt(Date.now()), BigInt(Date.now() + 5 * 60 * 1000)], - duration: BigInt(1800), - e3Program: '0x...', - e3ProgramParams: '0x', - computeProviderParams: '0x', - customParams: '0x', -}) -``` - -### Event subscriptions - -```ts -sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, (event) => { - console.log('New request', event.data) -}) - -sdk.onEnclaveEvent(RegistryEventType.CIPHERNODE_ADDED, (event) => { - console.log('Operator joined', event.data) -}) - -// Later, remember to clean up -sdk.off(EnclaveEventType.E3_REQUESTED, handler) -``` - -### React hook - -```tsx -import { useEnclaveSDK } from '@enclave-e3/react' - -export function Dashboard() { - const { - isInitialized, - requestE3, - onEnclaveEvent, - EnclaveEventType, - } = useEnclaveSDK({ - autoConnect: true, - contracts: { - enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, - ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, - }, - chainId: 31337, - }) - - useEffect(() => { - if (!isInitialized) return - const handle = (event) => console.log('Activated', event.data) - onEnclaveEvent(EnclaveEventType.E3_ACTIVATED, handle) - return () => off(EnclaveEventType.E3_ACTIVATED, handle) - }, [isInitialized]) - - return -} -``` - -## Configuration contract map - -Provide both the Enclave and CiphernodeRegistry addresses. The template exposes these via -`.env` / `enclave.config.yaml`, and CRISP scripts surface them in deployment logs. For multi-chain -apps, instantiate multiple SDKs or call `sdk.updateConfig({ contracts: { ... }, chainId })` whenever -wallets switch networks. - -## Working with the template - -`enclave init` generates the default template (see [Project Template](/project-template)). The client -already wires `@enclave-e3/sdk` and `@enclave-e3/react`: - -- `client/src/sdk.ts` builds the shared SDK instance -- `client/src/hooks/useE3.ts` uses `useEnclaveSDK` to expose helper hooks throughout the UI -- `server/src/services/enclave.ts` instantiates the SDK with a server wallet using `createWalletClient` - -When you add new contracts or E3 programs, update `client/.env` and `server/.env` with the new -addresses, then restart the dev server so the SDK reconnects. - -## Advanced usage - -- **Historical events**: `sdk.getHistoricalEvents(type, fromBlock, toBlock)` fetches logs without a - WebSocket provider; useful for CRON jobs or health checks. -- **Gas controls**: pass `gasLimit` to `requestE3`, `activateE3`, or `publishInput` if you want fixed - limits when interacting with Enclave on L2s. -- **Event polling**: `sdk.startEventPolling()` is handy in serverless environments where websockets - are unavailable. -- **Custom transports**: on the server, call `createWalletClient({ account, transport: http(rpc) })` - and load the private key from Vaults/KMS. - -## Troubleshooting - -| Symptom | Triage | -| --- | --- | -| `MISSING_PUBLIC_CLIENT` errors | Ensure `createPublicClient` uses an HTTP or WebSocket RPC reachable from the app. | -| `INVALID_ADDRESS` | Double-check contract addresses passed into the SDK match the current chain. | -| Hooks never initialize | Confirm `autoConnect` is true, wallet is connected, and React component is inside a provider that renders on the client. | -| No events arrive | Switch to a WebSocket RPC or call `sdk.startEventPolling()` so logs are polled over HTTP. | - -For additional API surface details see `packages/enclave-sdk/README.md` inside this repo. +--- +title: 'Enclave SDK' +description: 'Use the TypeScript + React SDKs to drive E3 programs from clients and services' +--- + +# Enclave SDK Overview + +The Enclave SDK (`@enclave-e3/sdk`) and React helpers (`@enclave-e3/react`) provide a +batteries-included client stack for requesting E3 computations, subscribing to protocol events, and +coordinating custom frontends or backend services. Both packages ship in this repository (see +`packages/enclave-sdk` and `packages/enclave-react`). + +## Installation + +```bash +pnpm add @enclave-e3/sdk # TypeScript SDK +pnpm add @enclave-e3/react # React hooks (optional) +``` + +For browser projects using WASM (encryption helpers, FHE keygen), configure Vite per the SDK README: + +```ts +// vite.config.ts +import wasm from 'vite-plugin-wasm' +import topLevelAwait from 'vite-plugin-top-level-await' + +export default defineConfig({ + optimizeDeps: { + exclude: ['@enclave-e3/wasm'], + }, + plugins: [wasm(), topLevelAwait()], +}) +``` + +## Core client + +```ts +import { EnclaveSDK, EnclaveEventType, RegistryEventType } from '@enclave-e3/sdk' +import { createPublicClient, createWalletClient, http, custom } from 'viem' + +const publicClient = createPublicClient({ transport: http(import.meta.env.VITE_RPC_URL) }) +const walletClient = createWalletClient({ transport: custom(window.ethereum) }) + +const sdk = new EnclaveSDK({ + publicClient, + walletClient, + contracts: { + enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, + ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, + }, + chainId: 11155111, +}) + +await sdk.initialize() +``` + +### Requesting computations + +```ts +const hash = await sdk.requestE3({ + threshold: [2, 3], + startWindow: [BigInt(Date.now()), BigInt(Date.now() + 5 * 60 * 1000)], + duration: BigInt(1800), + e3Program: '0x...', + e3ProgramParams: '0x', + computeProviderParams: '0x', + customParams: '0x', +}) +``` + +### Event subscriptions + +```ts +sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, (event) => { + console.log('New request', event.data) +}) + +sdk.onEnclaveEvent(RegistryEventType.CIPHERNODE_ADDED, (event) => { + console.log('Operator joined', event.data) +}) + +// Later, remember to clean up +sdk.off(EnclaveEventType.E3_REQUESTED, handler) +``` + +### React hook + +```tsx +import { useEnclaveSDK } from '@enclave-e3/react' + +export function Dashboard() { + const { isInitialized, requestE3, onEnclaveEvent, EnclaveEventType } = useEnclaveSDK({ + autoConnect: true, + contracts: { + enclave: import.meta.env.VITE_ENCLAVE_ADDRESS, + ciphernodeRegistry: import.meta.env.VITE_REGISTRY_ADDRESS, + }, + chainId: 31337, + }) + + useEffect(() => { + if (!isInitialized) return + const handle = (event) => console.log('Activated', event.data) + onEnclaveEvent(EnclaveEventType.E3_ACTIVATED, handle) + return () => off(EnclaveEventType.E3_ACTIVATED, handle) + }, [isInitialized]) + + return +} +``` + +## Configuration contract map + +Provide both the Enclave and CiphernodeRegistry addresses. The template exposes these via `.env` / +`enclave.config.yaml`, and CRISP scripts surface them in deployment logs. For multi-chain apps, +instantiate multiple SDKs or call `sdk.updateConfig({ contracts: { ... }, chainId })` whenever +wallets switch networks. + +## Working with the template + +`enclave init` generates the default template (see [Project Template](/project-template)). The +client already wires `@enclave-e3/sdk` and `@enclave-e3/react`: + +- `client/src/sdk.ts` builds the shared SDK instance +- `client/src/hooks/useE3.ts` uses `useEnclaveSDK` to expose helper hooks throughout the UI +- `server/src/services/enclave.ts` instantiates the SDK with a server wallet using + `createWalletClient` + +When you add new contracts or E3 programs, update `client/.env` and `server/.env` with the new +addresses, then restart the dev server so the SDK reconnects. + +## Advanced usage + +- **Historical events**: `sdk.getHistoricalEvents(type, fromBlock, toBlock)` fetches logs without a + WebSocket provider; useful for CRON jobs or health checks. +- **Gas controls**: pass `gasLimit` to `requestE3`, `activateE3`, or `publishInput` if you want + fixed limits when interacting with Enclave on L2s. +- **Event polling**: `sdk.startEventPolling()` is handy in serverless environments where websockets + are unavailable. +- **Custom transports**: on the server, call `createWalletClient({ account, transport: http(rpc) })` + and load the private key from Vaults/KMS. + +## Troubleshooting + +| Symptom | Triage | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | +| `MISSING_PUBLIC_CLIENT` errors | Ensure `createPublicClient` uses an HTTP or WebSocket RPC reachable from the app. | +| `INVALID_ADDRESS` | Double-check contract addresses passed into the SDK match the current chain. | +| Hooks never initialize | Confirm `autoConnect` is true, wallet is connected, and React component is inside a provider that renders on the client. | +| No events arrive | Switch to a WebSocket RPC or call `sdk.startEventPolling()` so logs are polled over HTTP. | + +For additional API surface details see `packages/enclave-sdk/README.md` inside this repo. diff --git a/docs/pages/use-cases.mdx b/docs/pages/use-cases.mdx index f38c769dd6..238a14e24e 100644 --- a/docs/pages/use-cases.mdx +++ b/docs/pages/use-cases.mdx @@ -1,62 +1,63 @@ ---- -title: 'Use Cases' ---- - -# Unlocking Enclave Use Cases - -Leading confidential-compute platforms such as Ritual, Fhenix, and Olas showcase their ecosystems by -highlighting concrete scenarios, personas, and playbooks. This page borrows that structure so you -can quickly map Enclave building blocks to the outcomes you need. - -## Confidential Governance (CRISP-style) - -- **Problem**: Public DAOs struggle to keep tallies, delegations, and vote rationales private during - sensitive decisions. -- **Pattern**: Use the CRISP template (client, Rust server, Noir circuits) with the Enclave SDK. -- **Flow**: DAO admins request an E3 round, contributors encrypt ballots in the browser, and - Ciphernodes publish a verifiable plaintext tally once the compute provider finishes. -- **Extras**: Plug Synpress or Playwright into the client for scripted voting drills. - -## Private Auctions & Matching Markets - -- **Problem**: Sealed-bid auctions or RFQ desks cannot run on public ledgers without leaking prices. -- **Pattern**: Model each bid as an input validated by account-specific ZKPs (range/whitelist) and - aggregate them off-chain using BFV-friendly arithmetic in your Secure Process. -- **Flow**: Traders submit encrypted bids, the compute provider selects the clearing price, and the - plaintext output unlocks settlement logic. -- **Extras**: Pair with Foundry scripts (similar to Fhenix's CoFHE quick starts) to simulate extreme - bidding volumes before mainnet. - -## AI Agent Coordination - -- **Problem**: Networks such as Ritual and Olas expose agent marketplaces; those agents still need a - privacy-preserving substrate for sensitive scoring, routing, or risk checks. -- **Pattern**: Treat each agent as a Data Provider, push policy enforcement into an `IInputValidator`, - and let Enclave host shared state transitions (e.g., allocating budget or updating trust scores). -- **Flow**: Agents encrypt telemetry, the Secure Process derives rankings, and downstream contracts or - marketplaces read the published plaintext. -- **Extras**: Use `customParams` inside `E3RequestParams` to tag rounds per agent vertical (NFT curation, - wallet assistants, on-chain AI retrieval). - -## Identity, Compliance, and Scoring - -- **Problem**: Identity attestations or credit scores leak sensitive attributes when stored directly - on-chain. -- **Pattern**: Build circuits that validate proofs of residency, KYC, or AML results without revealing - raw data; only the computed risk vector is decrypted. -- **Flow**: Validators encrypt attestations, the Secure Process derives the minimal disclosure blob, - and downstream protocols pull the plaintext via `PlaintextOutputPublished`. -- **Extras**: Combine with `customParams` to pin jurisdictional policy, similar to how Fhenix exposes - "Key Considerations" per sector. - -## Solution Matrix - -| Scenario | Typical Inputs | Secure Process Focus | Output Consumers | -| --- | --- | --- | --- | -| Confidential Governance | Wallet + ballot selections | Vote aggregation, quorum, randomness | DAO front-ends, multi-sigs | -| Private Auctions | Bid amount, bidder proofs | Price discovery, winner selection | Settlement contracts | -| AI Agent Coordination | Agent telemetry, task queue | Ranking, budget splits | Agent marketplaces, orchestrators | -| Identity / Compliance | Encrypted attestations | Risk flag derivation | On-chain registries, bridges | - -Next, explore the [Best Practices](/best-practices) and -[Putting It All Together](/putting-it-together) guides to tailor these patterns to your app. +--- +title: 'Use Cases' +--- + +# Unlocking Enclave Use Cases + +Leading confidential-compute platforms such as Ritual, Fhenix, and Olas showcase their ecosystems by +highlighting concrete scenarios, personas, and playbooks. This page borrows that structure so you +can quickly map Enclave building blocks to the outcomes you need. + +## Confidential Governance (CRISP-style) + +- **Problem**: Public DAOs struggle to keep tallies, delegations, and vote rationales private during + sensitive decisions. +- **Pattern**: Use the CRISP template (client, Rust server, Noir circuits) with the Enclave SDK. +- **Flow**: DAO admins request an E3 round, contributors encrypt ballots in the browser, and + Ciphernodes publish a verifiable plaintext tally once the compute provider finishes. +- **Extras**: Plug Synpress or Playwright into the client for scripted voting drills. + +## Private Auctions & Matching Markets + +- **Problem**: Sealed-bid auctions or RFQ desks cannot run on public ledgers without leaking prices. +- **Pattern**: Model each bid as an input validated by account-specific ZKPs (range/whitelist) and + aggregate them off-chain using BFV-friendly arithmetic in your Secure Process. +- **Flow**: Traders submit encrypted bids, the compute provider selects the clearing price, and the + plaintext output unlocks settlement logic. +- **Extras**: Pair with Foundry scripts (similar to Fhenix's CoFHE quick starts) to simulate extreme + bidding volumes before mainnet. + +## AI Agent Coordination + +- **Problem**: Networks such as Ritual and Olas expose agent marketplaces; those agents still need a + privacy-preserving substrate for sensitive scoring, routing, or risk checks. +- **Pattern**: Treat each agent as a Data Provider, push policy enforcement into an + `IInputValidator`, and let Enclave host shared state transitions (e.g., allocating budget or + updating trust scores). +- **Flow**: Agents encrypt telemetry, the Secure Process derives rankings, and downstream contracts + or marketplaces read the published plaintext. +- **Extras**: Use `customParams` inside `E3RequestParams` to tag rounds per agent vertical (NFT + curation, wallet assistants, on-chain AI retrieval). + +## Identity, Compliance, and Scoring + +- **Problem**: Identity attestations or credit scores leak sensitive attributes when stored directly + on-chain. +- **Pattern**: Build circuits that validate proofs of residency, KYC, or AML results without + revealing raw data; only the computed risk vector is decrypted. +- **Flow**: Validators encrypt attestations, the Secure Process derives the minimal disclosure blob, + and downstream protocols pull the plaintext via `PlaintextOutputPublished`. +- **Extras**: Combine with `customParams` to pin jurisdictional policy, similar to how Fhenix + exposes "Key Considerations" per sector. + +## Solution Matrix + +| Scenario | Typical Inputs | Secure Process Focus | Output Consumers | +| ----------------------- | --------------------------- | ------------------------------------ | --------------------------------- | +| Confidential Governance | Wallet + ballot selections | Vote aggregation, quorum, randomness | DAO front-ends, multi-sigs | +| Private Auctions | Bid amount, bidder proofs | Price discovery, winner selection | Settlement contracts | +| AI Agent Coordination | Agent telemetry, task queue | Ranking, budget splits | Agent marketplaces, orchestrators | +| Identity / Compliance | Encrypted attestations | Risk flag derivation | On-chain registries, bridges | + +Next, explore the [Best Practices](/best-practices) and +[Putting It All Together](/putting-it-together) guides to tailor these patterns to your app. diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index 76dcf2897e..900c89ec67 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -206,24 +206,27 @@ After deployment, you will see the addresses for the following contracts: #### Step 3: Configure Boundless (Optional) -> Please note that this step is optional for development only. By default, the program server runs in dev mode which uses fake proofs for fast local development. +> Please note that this step is optional for development only. By default, the program server runs +> in dev mode which uses fake proofs for fast local development. -For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update the `enclave.config.yaml` file in the CRISP root directory: +For production-grade zero-knowledge proofs with [Boundless](https://docs.beboundless.xyz/), update +the `enclave.config.yaml` file in the CRISP root directory: ```yaml program: - dev: false # Disable dev mode to use real proofs + dev: false # Disable dev mode to use real proofs risc0: - risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode + risc0_dev_mode: 0 # 0 = production (Boundless), 1 = dev mode boundless: - rpc_url: "https://sepolia.infura.io/v3/YOUR_KEY" # RPC endpoint - private_key: "YOUR_PRIVATE_KEY" # Wallet with funds for proving - pinata_jwt: "YOUR_PINATA_JWT" # Required for uploading programs to IPFS - program_url: "https://gateway.pinata.cloud/ipfs/YOUR_CID" # Pre-uploaded program URL - onchain: true # true = onchain requests, false = offchain + rpc_url: 'https://sepolia.infura.io/v3/YOUR_KEY' # RPC endpoint + private_key: 'YOUR_PRIVATE_KEY' # Wallet with funds for proving + pinata_jwt: 'YOUR_PINATA_JWT' # Required for uploading programs to IPFS + program_url: 'https://gateway.pinata.cloud/ipfs/YOUR_CID' # Pre-uploaded program URL + onchain: true # true = onchain requests, false = offchain ``` > **_Note:_** For production proving with Boundless, you need: +> > - An RPC endpoint (e.g., Infura, Alchemy) with funds > - A private key with sufficient ETH/tokens for proof generation > - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) @@ -236,16 +239,17 @@ When you make changes to the guest program in `program/`, you need to upload it 1. Build and upload your program: ```bash - enclave program upload + enclave program upload ``` 2. The command outputs an IPFS hash. Update `enclave.config.yaml` with the full URL: ```yaml - program_url: "https://gateway.pinata.cloud/ipfs/QmXxx..." + program_url: 'https://gateway.pinata.cloud/ipfs/QmXxx...' ``` -> **_Important:_** Every time you modify the guest program, rebuild and re-upload it to IPFS, then update the `program_url` in your configuration. +> **_Important:_** Every time you modify the guest program, rebuild and re-upload it to IPFS, then +> update the `program_url` in your configuration. #### Step 4: Set up Environment Variables From 36cb35be3e62aecfab846daa30f69dfec3205512 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 9 Dec 2025 21:26:30 +0500 Subject: [PATCH 09/19] chore: update docs --- docs/pages/ciphernode-operators.mdx | 240 ------------ docs/pages/ciphernode-operators/_meta.json | 6 +- .../exits-and-slashing.mdx | 236 ++++++++---- docs/pages/ciphernode-operators/index.mdx | 153 ++++---- .../pages/ciphernode-operators/operations.mdx | 357 ------------------ .../ciphernode-operators/registration.mdx | 292 +++++++++----- docs/pages/ciphernode-operators/running.mdx | 329 ++++++++++++++++ .../tickets-and-sortition.mdx | 226 ++++++----- 8 files changed, 917 insertions(+), 922 deletions(-) delete mode 100644 docs/pages/ciphernode-operators.mdx delete mode 100644 docs/pages/ciphernode-operators/operations.mdx create mode 100644 docs/pages/ciphernode-operators/running.mdx diff --git a/docs/pages/ciphernode-operators.mdx b/docs/pages/ciphernode-operators.mdx deleted file mode 100644 index 4d57c0b0a8..0000000000 --- a/docs/pages/ciphernode-operators.mdx +++ /dev/null @@ -1,240 +0,0 @@ ---- -title: 'Ciphernode Operators' -description: 'How to bond, configure, and operate Ciphernodes on the Enclave network' ---- - -# Ciphernode Operators - -Ciphernodes are the distributed workers that decrypt committee outputs, publish threshold key -shares, and keep the Enclave network alive. This guide walks through the economic requirements, -on-chain lifecycle, CLI workflow, networking expectations, and production deployment patterns for -running a Ciphernode. - -## Role overview - -Ciphernodes are expected to: - -- Maintain an online endpoint and participate in the event bus -- Bond license collateral (ENCL) and hold tickets (stablecoin-backed ETK) to earn committee slots -- Submit tickets on-chain during sortition and publish committee key material -- Produce decryption shares for every E3 the node was selected to serve -- Remain slash-aware: missed duties or malicious behavior can lose both ticket collateral and - license bonds - -The protocol is chain-agnostic. Each configured chain entry in `enclave.config.yaml` can track a -different Enclave + registry deployment, and each Ciphernode instance manages the lifecycle for its -configured chains simultaneously. - -## Contract references - -| Contract | Sepolia address | Notes | -| ------------------------ | -------------------------------------------- | -------------------------------- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration, committees | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Tracks license bonds + tickets | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash + ban workflow | -| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | - -> ⚠️ Always confirm the latest addresses from the docs. Addresses differ per network. - -## Economics & staking - -BondingRegistry constants on Sepolia: - -- **Ticket price**: `10_000_000` base units (10 USDC per ticket) -- **License bond requirement**: `100 ENCL` -- **Active license floor**: 80% of the required bond must remain bonded -- **Minimum ticket balance**: 1 ticket (10 USDC) -- **Exit delay**: `604_800 s` (7 days) - -Ticket balances are represented by the non-transferable `EnclaveTicketToken`. To mint tickets: - -1. Acquire the underlying stablecoin (`MockUSDC` on Sepolia) -2. Approve the BondingRegistry to pull funds -3. Call `addTicketBalance(amount)` - -The number of usable tickets is: - -``` -availableTickets = floor(ticketTokenBalance / ticketPrice) -``` - -Tickets control a node's probability of selection via sortition. - -License bonds are denominated in ENCL. Operators must keep at least 80% of `licenseRequiredBond` -bonded to remain `active`. - -SlashingManager penalties can remove both ticket balances and license bonds, and may ban an -operator. Appeals are time-bound by the policy's `appealWindow`. - -Rewards (any ERC20) are pushed by the configured `rewardDistributor` through -`BondingRegistry.distributeRewards`. Only registered operators receive payouts. - -## Lifecycle checklist - -1. **Acquire collateral** - - ENCL for license bonding - - USDC (or the configured fee token) for tickets -2. **Bond the license** - ```bash - cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -3. **Register as a ciphernode** - ```bash - cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -4. **Deposit tickets** - ```bash - cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - ``` -5. **Verify status** - - `BondingRegistry.isRegistered(address)` must be `true` - - `BondingRegistry.isActive(address)` turns `true` after ticket + license thresholds -6. **Stay online** - - Run the CLI (see below) so your node listens for events and participates in sortition -7. **Handle exits** - - Call `deregisterOperator(siblingProof)` to begin exit - - Wait 7 days, then `claimExits(maxTickets, maxLicense)` to withdraw - -> ℹ️ The sibling proof passed to `deregisterOperator` is the path needed to remove the node from the -> registry IMT. Capture it from the Merkle proof emitted in `CiphernodeAdded` events or by querying -> the registry before exit. - -## CLI workflow - -The `enclave` CLI wraps node orchestration, credentials, and repository tooling. - -### Initialize configuration - -```bash -enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS -``` - -This creates `~/.config/enclave/config.yaml` (or the path you pass with `--config`). Most operators -instead commit an `enclave.config.yaml` alongside deployment manifests (see sample below) and pass -it with `--config /path/to/config.yaml` on every command. - -### Manage credentials - -| Secret | Command | Notes | -| ---------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- | -| Password (encrypts keystore + datastore) | `enclave password set --password ` | Use `enclave password delete` to remove | -| Network key (libp2p ed25519) | `enclave net keypair generate` or `enclave net keypair set --net-keypair 0x…` | `enclave net peer-id purge` clears cached peer IDs | -| Wallet key (signs on-chain tx) | `enclave wallet set --private-key 0x…` | Needed for the node to submit on-chain txs | - -The entrypoint automatically runs `autopassword`, `autonetkey`, and `autowallet` when the config -sets those flags. - -### Run nodes - -```bash -enclave nodes up --detach # start every node profile defined in config -enclave nodes ps # list process status -enclave nodes status cn1 # query single node -enclave nodes restart cn1 # restart one node -enclave nodes down # stop everything -enclave nodes purge # wipe local db + secrets (irreversible) -``` - -To run a single node profile outside the supervisor, use -`enclave start --config /path/to/config.yaml`. Pass peers with -`--peer /dns4/bootstrap.enclave.gg/udp/5901/quic-v1` to override the config at runtime. - -## Networking & configuration - -Every node section in `enclave.config.yaml` defines how the CLI spawns that instance: - -```yaml -node: - address: '0x7099…79C8' - quic_port: 9201 - peers: - - '/dns4/bootstrap.enclave.gg/udp/5901/quic-v1' - autonetkey: true - autopassword: true -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8B…FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F6…0b1C7' - bonding_registry: - address: '0x5636…406E3' - fee_token: - address: '0xB58B…4De0' -``` - -Notes: - -- `peers` expects libp2p multiaddrs (`/dns4//udp//quic-v1`). Provide at least one - bootstrap peer. For production, run a static bootstrap service (planned: `bootstrap.enclave.gg`). -- `quic_port` must match firewall rules; expose UDP. -- Each node can override `data_dir` and `config_dir` if the defaults under `~/.local/share/enclave` - and `~/.config/enclave` are unsuitable. -- Set `role.type: aggregator` for nodes tasked with publishing plaintext outputs. - -## Deployment manifests & secrets - -The repository ships a Docker Swarm example under `deploy/` that you can adapt: - -- `cn*.yaml` / `agg.yaml`: minimal configs templated with `${ADDRESS}` and `${RPC_URL}` -- `docker-compose.yml`: runs multiple Ciphernodes plus an aggregator with shared overlay network -- Secrets files (`cn1.secrets.json`, etc.) follow: - ```json - { - "password": "changeme", - "private_key": "0x…", - "network_private_key": "0x…" - } - ``` -- `ciphernode-entrypoint.sh` loads the config + secrets, runs the CLI commands - (`enclave password set`, `enclave net keypair set`, `enclave wallet set`), then execs - `enclave start -v` - -This pattern is also useful for Kubernetes Jobs or systemd units: mount a config, mount an encrypted -secret bundle, run the entrypoint. - -## Sortition & operations - -- Committee requests originate from the Enclave contract. The registry snapshots ticket balances at - `requestBlock - 1`, so topping up tickets after a request starts will not help that round. -- Submission window defaults to 10 seconds on Sepolia (`sortitionSubmissionWindow`). Nodes must call - `submitTicket(e3Id, ticketNumber)` before it expires. The CLI handles this automatically using the - event bus. -- `finalizeCommittee` can be called by anyone once the window closes and at least `threshold_m` - submissions exist. After finalization, nodes publish key shares, aggregate the public key, and - submit it via `publishCommittee`. -- If a node is offline during submission, it misses the round but remains active provided its stake - satisfies the requirements. Repeated failures risk slashing. - -## Rewards, slashing, and exits - -- **Rewards**: Watch for `RewardDistributed` (BondingRegistry) logs. Ensure the operator wallet can - receive the reward token. -- **Slashing**: `SlashingManager` proposals reference reason codes. Operators should monitor - `SlashProposed` and be ready to file `fileAppeal()` before `appealWindow` expires when proof is - not required. Banned nodes cannot reregister until governance clears them via `updateBanStatus`. -- **Exits**: `deregisterOperator()` burns tickets immediately and queues withdrawals. The exit queue - tracks amounts per operator; call `pendingExits(address)` or `previewClaimable(address)` to view - status. - -## Troubleshooting - -| Symptom | Checks | -| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `enclave start` exits immediately | Ensure `enclave config-set` ran or `--config` points to a file. Missing configs trigger auto-init. | -| Node never `isActive` | Confirm you bonded `>= 80` ENCL, deposited at least 1 ticket, and were not banned/slashed. | -| Cannot connect to peers | Open UDP `quic_port`, provide working multiaddrs, and consider `enclave start --peer …` to override. | -| Sortition submissions fail | Node must be registered + active _before_ `Enclave.request`. Inspect logs for `NodeNotEligible` or `SubmissionWindowClosed`. | -| `ExitNotReady` on `claimExits` | Wait until `block.timestamp >= exitUnlocksAt` plus the queued delay. Use `previewClaimable`. | -| Slashing appeal rejected | Review `SlashPolicy` for that reason—policies requiring proofs skip appeals. | - -Maintaining high uptime, redundant networking, and alerting on contract events are the best ways to -protect your stake. Use the CLI supervisors plus infrastructure automation to ensure secrets and -configs stay consistent across restarts. diff --git a/docs/pages/ciphernode-operators/_meta.json b/docs/pages/ciphernode-operators/_meta.json index f94f5188ed..45ca46dda4 100644 --- a/docs/pages/ciphernode-operators/_meta.json +++ b/docs/pages/ciphernode-operators/_meta.json @@ -2,12 +2,12 @@ "index": { "title": "Overview" }, + "running": { + "title": "Running a Ciphernode" + }, "registration": { "title": "Registration & Licensing" }, - "operations": { - "title": "Running a Ciphernode" - }, "tickets-and-sortition": { "title": "Tickets & Sortition" }, diff --git a/docs/pages/ciphernode-operators/exits-and-slashing.mdx b/docs/pages/ciphernode-operators/exits-and-slashing.mdx index e574d13cc1..abedefcc4b 100644 --- a/docs/pages/ciphernode-operators/exits-and-slashing.mdx +++ b/docs/pages/ciphernode-operators/exits-and-slashing.mdx @@ -1,102 +1,212 @@ --- title: 'Exits, Rewards & Slashing' +description: 'Collect rewards, respond to slashing, and exit safely' --- # Exits, Rewards & Slashing -Understand how to collect rewards, respond to slashing proposals, and exit the registry safely. +This guide covers the end-of-lifecycle operations: collecting rewards, handling slashing proposals, +and safely exiting the registry. ## Rewards -- Distributed via `BondingRegistry.distributeRewards` (any ERC20) -- Watch for `RewardsDistributed` events and map them back to the source `e3Id` -- Keep the operator wallet funded; payouts are on-chain transfers and still require gas when claimed - through automation scripts +Rewards are distributed through `BondingRegistry.distributeRewards` after successful E3 completions. -Pair reward monitoring with lightweight probes: +### How Rewards Work + +1. E3 completes successfully with plaintext output published +2. Reward distributor calls `distributeRewards` with the reward token +3. Committee members receive payouts based on participation +4. `RewardsDistributed` event is emitted + +### Monitoring Rewards + +Watch for reward events and ensure your wallet can receive the reward token: ```bash -cast call $BONDING "pendingExits(address)" $OPERATOR -cast call $BONDING "getTicketBalance(address)" $OPERATOR -cast call $BONDING "licenseRequiredBond()" +# Check your status including any pending rewards +enclave ciphernode status ``` -Seeing rewards fall while balances remain healthy is an early indicator of missed jobs or RPC -issues. +> Keep your operator wallet funded with ETH for gas - claiming rewards through automation scripts +> still requires transaction fees. -## Slashing lifecycle +## Slashing -1. `SlashingManager` emits `SlashProposed` referencing a policy + reason code. -2. Operators inspect the evidence (if any) and the associated `SlashPolicy` parameters. -3. File an appeal with `fileAppeal(e3Id, reason, evidenceURI)` before `appealWindow` expires, if the - policy allows it. -4. Once finalized, penalties may burn tickets, confiscate license bonds, and optionally ban the - operator. +Slashing penalizes operators who miss duties or behave maliciously. The `SlashingManager` contract +handles proposals, appeals, and execution. -Stay alert for: +### Slashing Lifecycle -- `appealWindow` values per policy (some reasons skip appeals entirely) -- `updateBanStatus` (governance must lift bans before re-registration) +```mermaid +flowchart LR + A[Violation Detected] --> B[SlashProposed] + B --> C{Appealable?} + C -->|Yes| D[Appeal Window] + D -->|Appeal Filed| E[Review] + D -->|No Appeal| F[Slash Executed] + C -->|No| F + E -->|Rejected| F + E -->|Accepted| G[Slash Cancelled] + F --> H[Penalties Applied] +``` + +### Slash Policy Structure -Policy anatomy: +Each slash reason has an associated policy: ```solidity struct SlashPolicy { - uint256 ticketPenalty; - uint256 licensePenalty; - bool requiresProof; - uint64 appealWindow; - bool appealable; + uint256 ticketPenalty; // Tickets to burn + uint256 licensePenalty; // ENCL to confiscate + bool requiresProof; // Whether evidence is needed + uint64 appealWindow; // Time to file appeal + bool appealable; // Whether appeals are allowed } ``` -Never assume a slash is appealable without fetching the latest policy via `SlashingManager`. - -## Exit process - -1. **Deregister** — Call `deregisterOperator(uint256[] siblingNodes)` with a valid IMT proof. The - CLI logs the proof when you first register; stash it alongside your secrets bundle. -2. **Queue assets** — Ticket balances burn immediately. License bonds slide into the exit queue and - set `exitUnlocksAt = block.timestamp + exitDelay`. -3. **Wait out `exitDelay()`** — Default is 7 days on Sepolia. Automation should poll - `exitUnlocksAt(address)` to know when to attempt a claim. -4. **Claim exits** — Once the unlock timestamp passes, drain the queue: +### Responding to Slashing +1. **Monitor for proposals**: Watch `SlashProposed` events targeting your address +2. **Review the policy**: Check if appeals are allowed and the window duration +3. **File appeal if applicable**: ```bash - cast send $BONDING "claimExits(uint256,uint256)" $MAX_TICKETS $MAX_LICENSE \ + # Using cast (or implement in automation) + cast send $SLASHING "fileAppeal(uint256,string,string)" $E3_ID "reason" "evidence_uri" \ --rpc-url $RPC --private-key $OPERATOR_KEY ``` +4. **Track resolution**: Watch for finalization events + +### Slashing Penalties + +| Penalty Type | Effect | +| --------------- | ------------------------------------------------ | +| Ticket penalty | Burns ETK from your balance | +| License penalty | Confiscates ENCL from your bond | +| Ban | Prevents re-registration until governance clears | + +> Some policies skip the appeal process entirely. Always check the policy before assuming you can +> appeal. + +## Exit Process + +To safely exit the ciphernode registry: - Pass `type(uint256).max` to withdraw the full pending amount. The call reverts with - `ExitNotReady` if neither queue matured yet. +### Step 1: Deregister + +Request deregistration with your IMT proof siblings: + +```bash +enclave ciphernode deregister --proof 0x123...,0x456...,0x789... +``` + +> Save your sibling proof from the `CiphernodeAdded` event when you first register. You'll need it +> to deregister. + +### Step 2: Wait for Exit Delay + +Assets enter a queue with a delay period (7 days on Sepolia): + +| Asset | Behavior | +| ------- | ------------------------------------- | +| Tickets | Burned immediately, USDC enters queue | +| License | ENCL enters exit queue | + +Check your exit status: + +```bash +enclave ciphernode status +``` -5. **Cancel if needed** — Calling `registerOperator()` before `claimExits` clears the exit and puts - you back into the registry. +Look for "Exit pending" and "Pending exits" fields. -Helpful getters: +### Step 3: Claim Exits + +After the delay period: + +```bash +# Claim all pending exits +enclave ciphernode license claim + +# Or specify maximum amounts +enclave ciphernode license claim --max-ticket 100 --max-license 50 +``` + +### Cancel Exit + +To cancel an exit and return to active status: + +```bash +enclave ciphernode register +``` + +This clears the exit queue and re-registers you in the registry. + +## CLI Commands Summary + +| Command | Description | +| ----------------------------------------- | ---------------------------------- | +| `enclave ciphernode status` | Check registration and exit status | +| `enclave ciphernode deregister --proof X` | Start exit process | +| `enclave ciphernode license claim` | Claim unlocked exits | +| `enclave ciphernode register` | Cancel exit and re-register | +| `enclave ciphernode deactivate` | Withdraw stakes to become inactive | + +## Monitoring Checklist + +| Check | Command / Event | +| --------------------- | ------------------------------------------- | +| Exit queue status | `enclave ciphernode status` | +| Pending exits amounts | `pendingExits(address)` on BondingRegistry | +| Exit unlock time | `exitUnlocksAt(address)` on BondingRegistry | +| Slash proposals | Watch `SlashProposed` events | +| Rewards distribution | Watch `RewardsDistributed` events | + +## Troubleshooting + +| Issue | Cause | Solution | +| --------------------------- | ------------------------------------ | ------------------------------------ | +| `ExitNotReady` on claim | Exit delay hasn't passed | Wait until `exitUnlocksAt` timestamp | +| Appeal rejected immediately | Policy doesn't allow appeals | Check `SlashPolicy.appealable` | +| `isActive` suddenly false | Slashing reduced stake below minimum | Add more tickets or license bond | +| Missed reward payouts | Deregistered or banned during E3 | Re-register before next request | + +## Post-Exit Cleanup + +After successfully claiming exits: + +1. **Wipe local secrets**: + + ```bash + enclave purge-all + ``` -- `pendingExits(address)` → pending ticket + license totals -- `exitUnlocksAt(address)` → timestamp when claims unlock -- `hasExitInProgress(address)` → guard before attempting to re-register +2. **Revoke access**: + - RPC credentials + - Firewall rules + - Any automation keys -## Health checklist +3. **Document for compliance**: + - Exit timestamp + - Final balances + - Reason for exit -| Symptom | Actions | -| ------------------------------------- | --------------------------------------------------------------------------------------------------------- | -| `ExitNotReady` on `claimExits` | Confirm `block.timestamp` passed `exitUnlocksAt` and delay. Call `previewClaimable`. | -| Slashing appeal rejected immediately | Policy likely disables appeals. Review policy metadata. | -| `isActive` toggles false unexpectedly | Check ticket balance (>= 1) and verify bonded ENCL >= 80% requirement. | -| Missed reward payouts | Ensure registry still lists the operator, RPC did not drop events, and reward token address is supported. | +## Slashing Prevention -## Post-exit +To minimize slashing risk: -- Securely wipe local secrets (`enclave purge-all` to clear caches and databases, delete keystores) -- Revoke RPC credentials and firewall openings -- Document the exit reason for future audits or compliance +1. **Stay online during active E3s** - Check for ongoing jobs before maintenance +2. **Monitor events** - Alert on `SlashProposed` targeting your address +3. **Archive logs** - You'll need evidence for appeals +4. **Verify `isActive` after changes** - Any stake modification could deactivate you -## Slashing prevention checklist +## Summary -- Monitor active jobs before scheduled maintenance to avoid abandoning active work. -- Alert on `SlashProposed` events tagged with your operator address. -- Archive CLI + RPC logs for every incident; you need them for appeals. -- Double-check `isActive` after any ticket removal or license unbond to avoid accidental downtime. +| Phase | Key Actions | +| -------------- | ------------------------------------------- | +| **Active** | Monitor rewards, watch for slash proposals | +| **Slashing** | Review policy, file appeal if allowed, wait | +| **Exit Start** | Call deregister with proof | +| **Exit Wait** | Wait 7 days (check `exitUnlocksAt`) | +| **Exit Claim** | Claim tickets and license | +| **Post-Exit** | Purge secrets, revoke access, document | diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx index fcb60e7e3c..feea53c66f 100644 --- a/docs/pages/ciphernode-operators/index.mdx +++ b/docs/pages/ciphernode-operators/index.mdx @@ -1,104 +1,103 @@ --- title: 'Ciphernode Operators' -description: 'Role overview, prerequisites, and quick links for node operators' +description: 'Overview of ciphernode operations, contracts, and lifecycle' --- # Ciphernode Operators -Ciphernodes decrypt committee outputs, publish threshold key shares, and keep the Enclave request -pipeline moving. This section organizes everything operators need—from bonding requirements to exit -procedures—into focused guides. +Ciphernodes are the distributed workers that power the Enclave network. They participate in +threshold cryptography to enable encrypted computations (E3s) while ensuring no single party can +access the underlying data. -## Responsibilities at a glance +## What is a Ciphernode? -Operators are expected to cover four concurrent tracks: +A ciphernode is a node operator that: -- **Key management**: generate PVSS shares, keep private key material encrypted at rest, and publish - committee public keys once the threshold is met. -- **Decryption work**: watch for ciphertext outputs, craft decryption shares, and ensure plaintext - gets relayed on-chain. -- **Network availability**: run a QUIC/libp2p endpoint that stays reachable, stay synced to the - event bus, and keep RPC endpoints redundant. -- **Operational hygiene**: rotate secrets, snapshot configs, monitor sortition + job logs, and react - to slashing proposals or bans quickly. +- **Generates key shares**: Creates PVSS (Publicly Verifiable Secret Sharing) key shares for each + committee +- **Publishes public keys**: Contributes to aggregated committee public keys used for encryption +- **Produces decryption shares**: Decrypts computation outputs when the threshold is met +- **Maintains availability**: Stays online and responsive to participate in sortition and committee + duties -## Role overview +Ciphernodes earn rewards for successful participation and risk slashing for missed duties or +malicious behavior. -Operators are expected to: +## Contract Architecture -- Maintain a QUIC/libp2p endpoint that stays reachable 24/7 -- Bond license collateral (ENCL) and hold ticket balances (ETK) to remain eligible for committees -- Stay synced with the event bus so sortition submissions and key shares happen on time -- Produce decryption shares for every E3 assigned to their committee -- Monitor slashing proposals, appeals, and rewards distribution +The Enclave protocol uses several contracts that work together: -Each node profile in `enclave.config.yaml` can point to a different network (mainnet, testnet, or -local dev). The CLI supervises all configured chains concurrently. +| Contract | Purpose | +| ---------------------- | ------------------------------------------------------------------------------ | +| **Enclave** | Core coordinator that manages E3 requests and computation lifecycle | +| **CiphernodeRegistry** | Tracks registered operators and manages committee formation | +| **BondingRegistry** | Handles license bonds (ENCL) and ticket balances (ETK) | +| **SlashingManager** | Processes slashing proposals, appeals, and ban enforcement | +| **EnclaveToken** | ENCL token used for license bonding | +| **EnclaveTicketToken** | Non-transferable ETK token representing ticket balances (backed by stablecoin) | -## Why operate a Ciphernode? +### Sepolia Contract Addresses -- **Rewards & upside**: committee participation and steady uptime translate to ERC20 payouts through - `distributeRewards`. -- **Governance voice**: active operators are closest to the protocol and shape roadmap + policy - discussions. -- **Visibility**: infra partners highlight high-performing nodes in working group updates and future - customer routes. +| Contract | Address | +| -------------------- | -------------------------------------------- | +| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | +| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | +| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | +| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | +| EnclaveTicketToken | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | +| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | +| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | -Balance rewards against the capital tied up in ENCL bonds and ETK tickets plus infra costs. The -Scenarios page includes quick ROI checklists. +> Always verify addresses from `packages/enclave-contracts/deployed_contracts.json` or your +> deployment output. Addresses differ per network. -## Contract references +## Operator Lifecycle -| Contract | Sepolia address | Notes | -| ------------------------ | -------------------------------------------- | --------------------------------- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | Core coordinator | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | Handles registration + committees | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | Manages license bonds + tickets | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | Slash & ban workflow | -| EnclaveTicketToken (ETK) | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | Ticket wrapper around USDC | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | License bond token | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | Underlying asset for ETK | +A ciphernode moves through several states during its lifecycle: -> ⚠️ Confirm addresses in `packages/enclave-contracts/deployed_contracts.json` or your deployment -> output before funding a node. Values differ per network. +```mermaid +stateDiagram-v2 + [*] --> Unbonded + Unbonded --> Licensed: bondLicense(amount >= requiredBond) + Licensed --> Registered: registerOperator() + Registered --> Active: addTicketBalance(balance >= minBalance) + Active --> Inactive: removeTicketBalance() OR unbondLicense() + Inactive --> Active: addTicketBalance() OR bondLicense() + Active --> ExitPending: deregisterOperator() + Inactive --> ExitPending: deregisterOperator() + Registered --> ExitPending: deregisterOperator() + ExitPending --> [*]: claimExits() after exitDelay + ExitPending --> Registered: registerOperator() (cancels exit) +``` -## Requirements checklist +### State Descriptions -| Track | What you need | Notes | -| ---------------------------- | --------------------------------------------------------------------------------- | ------------- | -| Financial | ≥ `licenseRequiredBond` ENCL, ≥ `minTicketBalance * ticketPrice` USDC, plus gas | Top up | -| ahead of big request windows | -| Technical | Linux/macOS host, 4 cores / 8 GB RAM minimum, open UDP ports for QUIC | Containers or | -| bare metal both work | -| Operational | CLI >= current release, secrets storage (password, wallet, net key), monitoring + | -| pager | Bake into `ciphernode-entrypoint.sh` in `deploy/` | +| State | Description | +| --------------- | ---------------------------------------------------------------------- | +| **Unbonded** | No license bond deposited; cannot register | +| **Licensed** | ENCL bonded but not yet registered in the registry | +| **Registered** | In the registry but lacking minimum ticket balance | +| **Active** | Fully operational; eligible for committee selection via sortition | +| **Inactive** | Registered but below minimum requirements (tickets or license bond) | +| **ExitPending** | Deregistration requested; waiting for exit delay before claiming funds | -## Section map +## Requirements -- [Registration & Licensing](./registration) — economic requirements, bonding steps, CLI commands -- [Tickets & Sortition](./tickets-and-sortition) — how ETK balances influence committee selection -- [Operations & Responsibilities](./operations) — CLI workflow, networking, deployment manifests -- [Exits, Rewards & Slashing](./exits-and-slashing) — life after registration, penalties, exits -- [Runbook Scenarios](./scenarios) — ready-made playbooks for common situations +Before operating a ciphernode, ensure you have: -Use these pages sequentially when onboarding a new operator or jump to the topic you need. +| Requirement | Details | +| --------------- | ------------------------------------------------------------------------ | +| **ENCL Tokens** | At least `100 ENCL` for the license bond (check `licenseRequiredBond()`) | +| **Stablecoin** | USDC (or configured fee token) for tickets; minimum 1 ticket worth | +| **ETH** | Gas for transactions on your target network | +| **Hardware** | Linux/macOS, 4+ cores, 8GB+ RAM, stable internet with open UDP port | +| **Software** | Enclave CLI installed, WebSocket RPC endpoint | -## Lifecycle states +## Getting Started -```mermaid -stateDiagram-v2 - [*] --> Unbonded - Unbonded --> Licensed: bondLicense(amount >= requiredBond) - Licensed --> Registered: registerOperator() - Registered --> Active: addTicketBalance(balance >= minBalance) - Active --> Inactive: removeTicketBalance() OR unbondLicense() - Inactive --> Active: addTicketBalance() OR bondLicense() - Active --> ExitPending: deregisterOperator() - Inactive --> ExitPending: deregisterOperator() - Registered --> ExitPending: deregisterOperator() - ExitPending --> [*]: claimExits() after exitDelay - ExitPending --> Registered: registerOperator() (cancels exit) -``` +Follow these guides in order to become an active ciphernode operator: -Refer back here while reading the rest of the section; each guide calls out which state transitions -it affects. +1. **[Running a Ciphernode](./running)** - Set up your node using DappNode, Enclave CLI, or Docker +2. **[Registration & Licensing](./registration)** - Bond your license, register, and add tickets +3. **[Tickets & Sortition](./tickets-and-sortition)** - Understand how committee selection works +4. **[Exits, Rewards & Slashing](./exits-and-slashing)** - Learn about rewards and exit procedures diff --git a/docs/pages/ciphernode-operators/operations.mdx b/docs/pages/ciphernode-operators/operations.mdx deleted file mode 100644 index c45ab41efa..0000000000 --- a/docs/pages/ciphernode-operators/operations.mdx +++ /dev/null @@ -1,357 +0,0 @@ ---- -title: 'Running a Ciphernode' ---- - -# Running a Ciphernode - -This guide walks you through setting up and running a ciphernode, then explains the complete -computation flow from E3 request to plaintext decryption. - -## Deployment paths - -### DAppNode UI (IPFS package) - -If you're already running DAppNode, install the packaged service instead of hand-building -containers: - -1. Open **Packages → Install from IPFS hash** in the DAppNode UI, then paste - `QmeX7jxDFcwbW7kAbs8Tgn5T4vonYxe4WmemUQsaca8xDQ`. This pulls - `enclave-ciphernode.public.dappnode.eth@0.1.0`. -2. After the download finishes, click **Configure** on the package tile to launch the wizard. -3. Fill the wizard fields with the same addresses listed in the contract table on this page. The - following values keep you in-sync with the public Sepolia network: - -| Wizard field | Value / Notes | -| ------------------------------------------------ | ------------------------------------------------------------------------------------------- | -| `Network` | `sepolia` (mainnet + localhost are also available) | -| `RPC URL` | WebSocket endpoint, e.g. `wss://ethereum-sepolia.publicnode.com` | -| `Node Address` | Operator address funded with ENCL and the stable token (ETK backing) | -| `Private Key` | Matches `Node Address`; stored as a secret in the container | -| `Bootstrap Peers` | `/dnsaddr/bootstrap.enclave.gg` (add more comma-separated peers as needed) | -| `Node Role` | `ciphernode` (switch to `aggregator` only if this host should aggregate plaintext) | -| `Enclave / CiphernodeRegistry / BondingRegistry` | Use the Sepolia addresses from this doc or your deployment artifact | -| `*_DEPLOY_BLOCK` | Block numbers for each contract (Sepolia example: Enclave `9615399`) | -| `ENCRYPTION_PASSWORD`, `NETWORK_PRIVATE_KEY` | Provide values to keep deterministic peer IDs across restarts; leave blank to auto-generate | - -The wizard writes `config.yaml` from `config.template.yaml`, injects your answers as environment -variables, and persists `/data` so restarts do not erase the node database. After the wizard -completes: - -- Click **Start** to boot the service. DAppNode automatically runs `enclave start -v` with your - config. -- Use the **Logs** tab or `docker logs -f enclave-ciphernode.public.dappnode.eth` to watch the - bootstrap process. -- To override CLI arguments, edit the package's `EXTRA_OPTS` field (for example, to add - `--peer /dnsaddr/bootstrap.enclave.gg` while testing new peers). -- When you need to refresh secrets, stop the service, update the wizard values, and start it again. - -### Standalone Docker container - -Prefer to run a single node outside DAppNode? Build from the repo and mount your config + secrets: - -```bash -# From the repository root -docker build -f crates/Dockerfile -t enclave-ciphernode:latest . - -mkdir -p ops/enclave/config ops/enclave/data -cat <<'EOF' > ops/enclave/config/enclave.config.yaml -node: - address: '0xYourOperator' - quic_port: 9201 - peers: - - '/dnsaddr/bootstrap.enclave.gg' - autonetkey: true - autopassword: true -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' - bonding_registry: - address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' - fee_token: - address: '0xB58B762748c64f1a36B34012d1C52503617f4De0' -EOF - -cat <<'EOF' > ops/enclave/secrets.json -{ - "password": "choose-a-long-passphrase", - "private_key": "0x", - "network_private_key": "0x" -} -EOF - -docker run -d --name enclave-cn1 --restart unless-stopped \ - -p 9201:9201/udp \ - -v $PWD/ops/enclave/config:/home/ciphernode/.config/enclave \ - -v $PWD/ops/enclave/data:/home/ciphernode/.local/share/enclave \ - -v $PWD/ops/enclave/secrets.json:/run/secrets/secrets.json:ro \ - -e AGGREGATOR=false \ - enclave-ciphernode:latest -``` - -- The entrypoint reads `/run/secrets/secrets.json`, sets your password + keys, and then runs - `enclave start -v --config /home/ciphernode/.config/enclave/config.yaml`. -- Switch `AGGREGATOR=true` for plaintext aggregators. -- Mount any additional configs (TLS certs, Grafana agents, etc.) under the same directory and - reference them from `enclave.config.yaml`. -- To run CLI commands inside the container, use - `docker exec -it enclave-cn1 enclave ciphernode status --chain sepolia`. - -## Manual setup: initialize your ciphernode - -Start by running `enclave init` to create the initial configuration: - -```bash -enclave init -``` - -This command will: - -- Create `~/.config/enclave/config.yaml` with your node configuration -- Generate a network keypair in `~/.config/enclave/key` -- Set up the data directory at `~/.local/share/enclave/` - -During initialization, you'll be prompted for: - -- Your Ethereum address (the address that will participate in committees) -- A password to encrypt sensitive data -- RPC URL for the chain you want to connect to - -## Configuration - -After initialization, edit your `~/.config/enclave/config.yaml` to configure: - -### 1. Contract Addresses - -Update the contract addresses to match the network you're connecting to: - -```yaml -chains: - - name: sepolia - rpc_url: 'wss://ethereum-sepolia.publicnode.com' - contracts: - enclave: - address: '0x1E8B…FAa6' - deploy_block: 9615399 - ciphernode_registry: - address: '0x11F6…0b1C7' - bonding_registry: - address: '0x5636…406E3' - fee_token: - address: '0xB58B…4De0' -``` - -### 2. Bootstrap Peers - -Add the bootstrap peer to join the network: - -```yaml -node: - address: '0xYourAddress' - quic_port: 9201 - peers: - - '/dnsaddr/bootstrap.enclave.gg' - autonetkey: true - autopassword: true -``` - -### 3. Set Your Wallet - -Configure your private key to sign transactions: - -```bash -enclave wallet set --private-key "0xYourPrivateKey" -``` - -**Warning:** Never share your private key. Keep it secure. - -## Starting Your Node - -Once configured, start your ciphernode: - -```bash -enclave start -``` - -Your node will: - -- Connect to the bootstrap peer(s) -- Subscribe to blockchain events -- Begin participating in sortition when E3s are requested - -## CLI lifecycle after deployment - -With the node running (via DAppNode, Docker, or bare metal) and your wallet already funded with the -required ENCL + stable tokens, move through the registry lifecycle using the CLI. Every command -accepts `--chain ` to select the chain entry from your config file and `--config ` if -you store configs outside the default. - -| Goal | Command | Result | -| ----------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------ | -| Bond ENCL license collateral | `enclave ciphernode license bond --amount 100 --chain sepolia` | Approves + bonds ENCL into the BondingRegistry | -| Deposit ticket backing (stablecoin) | `enclave ciphernode tickets buy --amount 100 --chain sepolia` | Approves fee token, mints ETK tickets | -| Register the operator | `enclave ciphernode register --chain sepolia` | Calls `registerOperator()` and unlocks sortition eligibility | -| Force an activation check | `enclave ciphernode activate --chain sepolia` | Replays `registerOperator()` if status drifted | -| Inspect state | `enclave ciphernode status --chain sepolia` | Prints bonded amounts, tickets, exits, and requirements | -| Remove stake during an exit | `enclave ciphernode deactivate --tickets 10 --license 20 --chain sepolia` | Withdraws tickets / unbonds license into the exit queue | -| Deregister completely | `enclave ciphernode deregister --proof 0xabc,0xdef --chain sepolia` | Calls `deregisterOperator()`, burning tickets immediately | -| Claim finished exits | `enclave ciphernode license claim --max-ticket 100 --max-license 100 --chain sepolia` | Calls `claimExits()` to pull unlocked funds | - -- For `tickets buy` and `license bond`, the CLI automatically checks ERC20 allowances and submits - approvals before calling the BondingRegistry. -- Capture the IMT siblings emitted in `CiphernodeAdded` to reuse later with the `--proof` flag. -- When running inside Docker/DAppNode, wrap commands with `docker exec -it ` so they can - access the mounted config and keystore. -- The lifecycle diagram in `ciphernode-operators/index.mdx` matches the sequence above: bond → - register → add tickets → stay active → deactivate/deregister → claim exits. - -## The Complete E3 Flow - -Here's what happens when an E3 (Encrypted Execution Environment) computation is requested: - -### Phase 1: E3 Request - -1. Someone calls `request()` on the Enclave contract with computation parameters -2. A new E3 ID is created with a random seed -3. The contract emits an `E3Requested` event - -### Phase 2: Committee Selection (Sortition) - -1. **Ticket Submission**: Your ciphernode listens for `E3Requested` events -2. **Score Calculation**: Your node calculates a sortition score based on: - - The E3 seed - - Your tickets/stake - - Your node's tickets -3. **Committee Finalization**: The top N nodes with the best scores are selected -4. If selected, you'll receive a `CommitteeFinalized` event with your party ID - -### Phase 3: Keyshare Generation - -When your node is selected for a committee: - -1. **Generate Secret**: Your node generates a secret key share and public key share -2. **Publish Keyshare**: The public key share is broadcast via libp2p and published onchain -3. **Storage**: The secret is encrypted and stored in `~/.local/share/enclave/jobs//` - -### Phase 4: Public Key Aggregation - -1. **Collect Keyshares**: An aggregator node collects all N public key shares from the committee -2. **Aggregate**: Once all shares are received, they're combined into a single public encryption key -3. **Publish**: The aggregated public key is published onchain via `publishPublicKey()` -4. The contract emits `PublicKeyAggregated` event -5. The E3 is now activated and ready to receive encrypted inputs - -### Phase 5: Input Window - -During this phase: - -1. Data providers encrypt their inputs using the aggregated public key -2. They submit encrypted data to the contract via `publishInput()` -3. The E3 Program validates each input -4. Input hashes are added to a Merkle tree onchain - -### Phase 6: Computation - -1. **Deadline Passes**: Once the input window closes, computation can begin -2. **Compute Provider Execution**: A compute provider (or E3 program) retrieves all encrypted inputs -3. **FHE Computation**: The computation runs entirely on encrypted data -4. **Output Generation**: The result is produced as encrypted ciphertext with a ZK proof - -### Phase 7: Ciphertext Publishing - -1. The compute provider calls `publishCiphertextOutput()` with the encrypted result and proof -2. The contract verifies the proof -3. Contract emits `CiphertextOutputPublished` event -4. All committee members are notified to begin decryption - -### Phase 8: Decryption Share Generation - -When your ciphernode receives `CiphertextOutputPublished`: - -1. **Load Secret**: Your node retrieves the encrypted secret key share from storage -2. **Decrypt Secret**: The secret is decrypted using your node's cipher -3. **Generate Share**: Your node creates a decryption share by partially decrypting the ciphertext -4. **Publish Share**: The decryption share is broadcast via libp2p and published onchain -5. Your node emits `DecryptionshareCreated` event - -### Phase 9: Plaintext Aggregation - -1. **Collect Shares**: An aggregator node collects decryption shares from committee members -2. **Threshold Met**: Once M-of-N threshold shares are received (e.g., 3 of 5) -3. **Aggregate**: The aggregator combines the shares to decrypt the final plaintext -4. **Publish Result**: The plaintext is published onchain via `publishPlaintextOutput()` -5. Contract emits `PlaintextOutputPublished` event -6. **Rewards**: Committee members receive their rewards for successful completion - -### Phase 10: Completion - -1. The plaintext output is now available onchain -2. Anyone can query `getE3()` to retrieve the result -3. Your node clears the secret from memory -4. The E3 round is complete - -## Monitoring Your Node - -### Check Node Status - -View your node's logs depending on how you're running it: - -```bash -# If running as a systemd service -journalctl -u enclave -f - -# If running directly or in a container, check the process -ps aux | grep enclave - -# Or check container logs if using Docker -docker logs -f -``` - -### What to Watch For - -Your node logs will show: - -- `E3Requested` - New computation request detected -- `TicketGenerated` - Your sortition ticket was calculated -- `CiphernodeSelected` - You were selected for a committee -- `KeyshareCreated` - Your keyshare was generated -- `PublicKeyAggregated` - Committee public key is ready -- `CiphertextOutputPublished` - Time to generate decryption share -- `DecryptionshareCreated` - Your decryption share was published -- `PlaintextAggregated` - Final result is available - -## Important Notes - -### Stay Online - -- Your node must be online and responsive during all phases of an E3 you're selected for -- Missing keyshare publication or decryption share submission may result in slashing - -### Network Connectivity - -- Ensure your `quic_port` (UDP) is accessible from the internet -- Maintain stable connections to bootstrap peers -- Consider running your own bootstrap node for redundancy - -### RPC Reliability - -- Use reliable RPC endpoints (consider running your own node) -- Have backup RPC URLs configured -- Monitor RPC connectivity and switch if needed - -### Data Persistence - -- The `~/.local/share/enclave/` directory contains critical job data -- Back up this directory regularly -- Do not delete data for active E3s - -### Key Security - -- Your network keypair is stored in `~/.config/enclave/key` -- Your wallet private key is encrypted in the config -- Never share these files or your private keys diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx index 7f373d2ab1..080e2ef5f4 100644 --- a/docs/pages/ciphernode-operators/registration.mdx +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -1,117 +1,233 @@ --- title: 'Registration & Licensing' +description: 'Bond your license, register as an operator, and add tickets' --- # Registration & Licensing -This guide covers everything required to become an active Ciphernode: collateral, bonding, -registration transactions, and config secrets. +This guide walks you through the complete registration process to become an active ciphernode +operator. Make sure your node is already [running](./running) before proceeding. -## Before you start +## Prerequisites -| Track | Checklist | -| ----------- | ----------------------------------------------------------------------------------------------------------------------- | -| Financial | ENCL covering `licenseRequiredBond`, USDC covering at least `minTicketBalance * ticketPrice`, and ETH for gas | -| Technical | Enclave CLI ≥ current release, WebSocket RPC, `enclave password/net keypair/wallet` secrets set | -| Operational | `enclave.config.yaml` committed, secrets mirrored into `deploy/*.secrets.json`, monitoring hooks for registration state | +Before registering, ensure your wallet has: -Adjust the numbers using `cast call $BONDING` for `licenseRequiredBond()`, `ticketPrice()` and -`minTicketBalance()` on your target network. +| Token | Amount Required | Purpose | +| ----------------------- | ---------------------------------------- | ---------------------------- | +| **ENCL** | ≥ 100 ENCL (check `licenseRequiredBond`) | License bond collateral | +| **USDC** (or fee token) | ≥ 10 USDC per ticket (minimum 1 ticket) | Ticket balance for sortition | +| **ETH** | Sufficient for gas | Transaction fees | -## Economic requirements +> On Sepolia testnet, use MockUSDC at `0xB58B762748c64f1a36B34012d1C52503617f4De0` and ENCL at +> `0xc93f71D10874F09F7F514a3d160E5be21fD624ab`. -Sepolia defaults (check `BondingRegistry` on your network): +## Registration Steps -- **Ticket price**: `10_000_000` base units (10 USDC per ticket) -- **License bond requirement**: `100 ENCL` -- **Active license floor**: 80% of the required bond must remain locked -- **Minimum ticket balance**: 1 ticket (10 USDC) -- **Exit delay**: `604_800 s` (7 days) +### Step 1: Check Current Status -Tickets live inside the non-transferable `EnclaveTicketToken`. Mint them by depositing the -underlying stablecoin (MockUSDC on Sepolia) via `BondingRegistry.addTicketBalance`. The usable -ticket count is: +First, verify your current on-chain status: -`availableTickets = floor(ticketTokenBalance / ticketPrice)` +```bash +enclave ciphernode status +``` + +Example output: + +``` +Ciphernode status on sepolia: + Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 + Registered: false + Active: false + Exit pending: false + Ticket balance: 0 (0 available) + License bond: 0 + Pending exits: tickets=0, license=0 + Requirements: minTickets=1, ticketPrice=10 EKT, licenseBond=100 ENCL +``` + +### Step 2: Bond Your License + +Bond ENCL tokens to meet the license requirement: + +```bash +enclave ciphernode license bond --amount 100 +``` + +This command: + +- Approves the BondingRegistry to spend your ENCL (if needed) +- Calls `bondLicense(100e18)` on the BondingRegistry contract + +> You can bond more than the minimum for a buffer against slashing. The active license floor is 80% +> of the required bond. + +### Step 3: Register as an Operator + +Register your address in the CiphernodeRegistry: + +```bash +enclave ciphernode register +``` + +After registration, your node will be added to the registry's Merkle tree and can participate in +committee formation once you have tickets. + +### Step 4: Add Ticket Balance + +Purchase tickets by depositing the underlying stablecoin: + +```bash +enclave ciphernode tickets buy --amount 100 +``` + +This deposits 100 USDC (or fee token units) and mints the equivalent in non-transferable ETK +(EnclaveTicketToken). + +The number of usable tickets is calculated as: + +``` +availableTickets = floor(ticketTokenBalance / ticketPrice) +``` + +With a ticket price of 10 USDC and a 100 USDC deposit, you get 10 available tickets. + +### Step 5: Verify Active Status + +Confirm your registration is complete: + +```bash +enclave ciphernode status +``` + +Expected output for an active operator: -License bonds are denominated in ENCL. Falling below 80% of `licenseRequiredBond` moves the operator -back to `inactive` even if tickets remain. +``` +Ciphernode status on sepolia: + Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 + Registered: true + Active: true + Exit pending: false + Ticket balance: 100 (10 available) + License bond: 100 + Pending exits: tickets=0, license=0 + Requirements: minTickets=1, ticketPrice=10 EKT, licenseBond=100 ENCL +``` -## CLI prerequisites +## CLI Command Reference -Before bonding, prepare local secrets: +### License Commands ```bash -# Set up config (or pass --config later) -enclave config-set --rpc-url $RPC --eth-address $OPERATOR_ADDRESS - -# Store secrets (optional if using automation) -enclave password set --password "$PASSWORD" -enclave net keypair -enclave wallet set --private-key $OPERATOR_KEY -``` - -These commands populate `~/.config/enclave` and `~/.local/share/enclave`. For containerized -deployments, bake the steps into `ciphernode-entrypoint.sh` (see `deploy/`). - -## Lifecycle checklist - -1. **Acquire collateral** - - ENCL for license bonds - - USDC (or the configured fee token) for tickets -2. **Bond the license** - ```bash - cast send $BONDING "bondLicense(uint256)" 100e18 --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -3. **Register the operator** - ```bash - cast send $BONDING "registerOperator()" --private-key $OPERATOR_KEY --rpc-url $RPC - ``` -4. **Deposit tickets** - ```bash - cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY - ``` -5. **Verify status** - ```bash - cast call $BONDING "isRegistered(address)" $OPERATOR - cast call $BONDING "isActive(address)" $OPERATOR - cast call $BONDING "getLicenseBond(address)" $OPERATOR - cast call $BONDING "getTicketBalance(address)" $OPERATOR - ``` -6. **Add buffers (optional)** - - Maintain ≥ 1.1× the minimum license bond so transient unbonds or slashes do not deactivate you - - Keep a few extra tickets so `availableTickets` never dips below the floor -7. **Snapshot config for production** - - Commit `enclave.config.yaml` alongside deployment manifests - - Store secrets in JSON (see `deploy/cn1.secrets.json`) and mount them securely - -> The wallet private key is encrypted and stored in the config. Ensure you have set the correct -> operator key with `enclave wallet set` before running bonding transactions. - -## One-command bootstrap (optional) - -Hardhat ships with a helper task that strings approvals + bonding + registration together: +# Bond ENCL tokens +enclave ciphernode license bond --amount + +# Unbond ENCL (moves to exit queue) +enclave ciphernode license unbond --amount + +# Claim unlocked exits +enclave ciphernode license claim +enclave ciphernode license claim --max-ticket 50 --max-license 100 +``` + +### Ticket Commands ```bash -npx hardhat ciphernode:add \ - --license-bond-amount 100000000000000000000 \ - --ticket-amount 10000000 +# Buy tickets (deposit stablecoin) +enclave ciphernode tickets buy --amount + +# Burn tickets (withdraw stablecoin) +enclave ciphernode tickets burn --amount ``` -It calls `bondLicense`, `registerOperator`, and `addTicketBalance` under the hood. Production nodes -usually stick with explicit `cast` or `enclave` commands for better observability and auditing. +### Lifecycle Commands + +```bash +# Register as an operator +enclave ciphernode register + +# Deregister (requires IMT proof) +enclave ciphernode deregister --proof -## Status probes to monitor +# Force activation check +enclave ciphernode activate -Once bonded, keep lightweight probes in your monitoring stack: +# Deactivate by withdrawing stake +enclave ciphernode deactivate --tickets --license + +# Check status +enclave ciphernode status +``` + +### Multi-Chain Support + +Specify a chain when operating on multiple networks: ```bash -cast call $BONDING "minTicketBalance()" -cast call $BONDING "ticketPrice()" -cast call $BONDING "licenseRequiredBond()" -cast call $BONDING "hasExitInProgress(address)" $OPERATOR +enclave ciphernode status --chain mainnet +enclave ciphernode license bond --amount 100 --chain sepolia ``` -Pause automation if any probe changes unexpectedly until you reconcile it with a governance action -or migration plan. +The `--chain` parameter matches the `name` field in your config's `chains` array. + +## Economic Parameters + +Current Sepolia defaults (verify on-chain before depositing): + +| Parameter | Value | Description | +| --------------------- | -------------------- | ---------------------------------- | +| `ticketPrice` | 10,000,000 (10 USDC) | Cost per ticket in fee token units | +| `licenseRequiredBond` | 100 ENCL | Minimum ENCL to bond | +| `minTicketBalance` | 1 ticket | Minimum tickets to be active | +| `exitDelay` | 604,800s (7 days) | Wait time before claiming exits | + +Query these values on-chain: + +```bash +# Using cast (foundry) +cast call $BONDING "ticketPrice()" --rpc-url $RPC +cast call $BONDING "licenseRequiredBond()" --rpc-url $RPC +cast call $BONDING "minTicketBalance()" --rpc-url $RPC +cast call $BONDING "exitDelay()" --rpc-url $RPC +``` + +## Best Practices + +### Maintain Buffer Amounts + +- **License bond**: Keep 10-20% above the minimum to absorb potential slashing without losing active + status +- **Tickets**: Maintain extra tickets so you're not deactivated if one is consumed or slashed + +### Monitor Your Status + +Set up alerts for: + +- `isActive` changing to `false` +- `SlashProposed` events targeting your address +- Low ticket balance approaching minimum + +### Backup Your IMT Proof + +When you register, save the sibling nodes from the `CiphernodeAdded` event. You'll need these to +deregister: + +```bash +# Store the proof when you register +enclave ciphernode deregister --proof 0x123...,0x456...,0x789... +``` + +## Troubleshooting + +| Issue | Cause | Solution | +| ------------------------- | -------------------------------------- | ------------------------------------- | +| `isActive` is false | Below minimum license (80%) or tickets | Add more ENCL or tickets | +| Registration fails | Already registered or banned | Check `isRegistered()` and ban status | +| Ticket purchase fails | Insufficient stablecoin or allowance | Ensure balance and approve spending | +| "NodeNotEligible" in logs | Not registered before E3 request | Register before requests are made | + +## Next Steps + +Once registered and active: + +1. **[Tickets & Sortition](./tickets-and-sortition)** - Learn how committee selection works +2. **[Exits & Slashing](./exits-and-slashing)** - Understand rewards and exit procedures diff --git a/docs/pages/ciphernode-operators/running.mdx b/docs/pages/ciphernode-operators/running.mdx new file mode 100644 index 0000000000..44b6391d1c --- /dev/null +++ b/docs/pages/ciphernode-operators/running.mdx @@ -0,0 +1,329 @@ +--- +title: 'Running a Ciphernode' +description: 'Three ways to run a ciphernode: DappNode, Enclave CLI, or Docker' +--- + +# Running a Ciphernode + +This guide covers three methods to run a ciphernode, from easiest to most flexible. Choose the +method that best fits your infrastructure. + +## Method 1: DappNode (Easiest) + +DappNode provides a user-friendly interface for running a ciphernode with minimal configuration. + +### Installation + +1. Open your DappNode UI (`http://my.dappnode`) +2. Search for **"Enclave Ciphernode"** and install the package +3. The setup wizard will prompt you for: + - `RPC_URL` - WebSocket RPC endpoint (e.g., `wss://ethereum-sepolia-rpc.publicnode.com`) + - `NETWORK` - Network name (e.g., `sepolia`, `mainnet`) + - Contract addresses and deploy blocks + - Node role (`ciphernode` or `aggregator`) + - Optional: encryption password, network key, private key + +4. Confirm and complete the installation +5. Check **Packages → enclave-ciphernode → Logs** to verify the node started + +### Configuration via Environment Variables + +| Variable | Description | Required | +| --------------------- | -------------------------------------------- | -------- | +| `RPC_URL` | WebSocket RPC endpoint | Yes | +| `NETWORK` | Network name (sepolia, mainnet, etc.) | No | +| `NODE_ROLE` | `ciphernode` or `aggregator` | No | +| `NODE_ADDRESS` | Your Ethereum address | No | +| `QUIC_PORT` | UDP port for P2P networking (default: 37173) | No | +| `ENCRYPTION_PASSWORD` | Password to encrypt local data | No | +| `NETWORK_PRIVATE_KEY` | libp2p network key (ed25519) | No | +| `PRIVATE_KEY` | Ethereum private key (for aggregator) | No | +| `PEERS` | Comma-separated peer multiaddresses | No | + +--- + +## Method 2: Enclave CLI (Recommended) + +The Enclave CLI provides the most control and is recommended for production deployments. + +### Install the CLI + +```bash +# Quick install +curl -fsSL https://raw.githubusercontent.com/gnosisguild/enclave/main/install | bash + +# Then install the CLI +enclaveup install +``` + +### Initialize Configuration + +```bash +enclave config-set \ + --rpc-url wss://ethereum-sepolia-rpc.publicnode.com \ + --eth-address 0xYourAddress +``` + +This creates `~/.config/enclave/config.yaml`. You'll be prompted for a password to encrypt sensitive +data. + +### Set Up Credentials + +```bash +# Set encryption password (encrypts local keystore) +enclave password set + +# Generate or set network keypair (for libp2p) +enclave net keypair generate +# Or import an existing key: +# enclave net keypair set --net-keypair 0x... + +# Set your wallet private key (for on-chain transactions) +enclave wallet set --private-key 0xYourPrivateKey +``` + +### Configure Your Node + +Edit `~/.config/enclave/config.yaml`: + +```yaml +node: + address: '0xYourAddress' + quic_port: 9091 + peers: + - '/dnsaddr/bootstrap.enclave.gg' + autonetkey: true + autopassword: true + +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia-rpc.publicnode.com' + contracts: + enclave: + address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + bonding_registry: + address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' +``` + +### Start Your Node + +```bash +# Start in foreground with verbose logging +enclave start -v + +# Or use the node supervisor for multiple nodes +enclave nodes up --detach +enclave nodes ps # Check status +enclave nodes logs cn1 # View logs +enclave nodes down # Stop all nodes +``` + +### CLI Commands Reference + +| Command | Description | +| ------------------------------ | -------------------------------------- | +| `enclave start` | Start the node in foreground | +| `enclave nodes up` | Start all configured nodes | +| `enclave nodes down` | Stop all nodes | +| `enclave nodes ps` | List running nodes | +| `enclave nodes status ` | Check specific node status | +| `enclave nodes restart ` | Restart a specific node | +| `enclave ciphernode status` | Show on-chain registration status | +| `enclave purge-all` | Wipe all local data (use with caution) | + +--- + +## Method 3: Docker + +For containerized deployments, you can run the ciphernode Docker image directly. + +### Pull the Image + +```bash +docker pull ghcr.io/gnosisguild/ciphernode:latest +``` + +### Create Configuration + +Create a `config.yaml` file: + +```yaml +node: + address: '0xYourAddress' + quic_port: 9091 + peers: + - '/dnsaddr/bootstrap.enclave.gg' + autonetkey: true + autopassword: true + +chains: + - name: sepolia + rpc_url: 'wss://ethereum-sepolia-rpc.publicnode.com' + contracts: + enclave: + address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' + deploy_block: 9615399 + ciphernode_registry: + address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + bonding_registry: + address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' +``` + +### Run the Container + +```bash +docker run -d \ + --name ciphernode \ + -v $(pwd)/config.yaml:/home/ciphernode/.config/enclave/config.yaml:ro \ + -v ciphernode-data:/home/ciphernode/.local/share/enclave \ + -p 9091:9091/udp \ + -e ENCRYPTION_PASSWORD=your_password \ + -e PRIVATE_KEY=0xYourPrivateKey \ + ghcr.io/gnosisguild/ciphernode:latest +``` + +### Docker Compose + +For a more manageable setup, use Docker Compose: + +```yaml +services: + ciphernode: + image: ghcr.io/gnosisguild/ciphernode:latest + restart: unless-stopped + volumes: + - ./config.yaml:/home/ciphernode/.config/enclave/config.yaml:ro + - ciphernode-data:/home/ciphernode/.local/share/enclave + ports: + - '9091:9091/udp' + environment: + ENCRYPTION_PASSWORD: ${ENCRYPTION_PASSWORD} + PRIVATE_KEY: ${PRIVATE_KEY} + +volumes: + ciphernode-data: +``` + +### View Logs + +```bash +docker logs -f ciphernode +``` + +--- + +## Configuration Reference + +### Node Configuration + +| Field | Description | Default | +| -------------- | ------------------------------------ | ------------------------ | +| `address` | Your Ethereum address | Required | +| `quic_port` | UDP port for QUIC/libp2p networking | `9091` | +| `peers` | Bootstrap peer multiaddresses | `[]` | +| `autonetkey` | Auto-generate network key if missing | `false` | +| `autopassword` | Auto-generate password if missing | `false` | +| `autowallet` | Auto-load wallet from environment | `false` | +| `data_dir` | Override data directory | `~/.local/share/enclave` | +| `config_dir` | Override config directory | `~/.config/enclave` | + +### Chain Configuration + +| Field | Description | Required | +| ----------- | ------------------------------------ | -------- | +| `name` | Chain identifier | Yes | +| `rpc_url` | WebSocket RPC endpoint | Yes | +| `contracts` | Contract addresses and deploy blocks | Yes | + +### Contract Addresses + +Each chain requires these contract addresses: + +| Contract | Description | +| --------------------- | ---------------------------------------- | +| `enclave` | Main Enclave coordinator | +| `ciphernode_registry` | Tracks registered operators | +| `bonding_registry` | Manages bonds and tickets | +| `fee_token` | Optional: stablecoin address for tickets | + +--- + +## Networking Requirements + +### Firewall Configuration + +Open the following ports: + +| Port | Protocol | Purpose | +| ------ | -------- | -------------------------- | +| `9091` | UDP | QUIC/libp2p P2P networking | + +### Bootstrap Peers + +Connect to the Enclave bootstrap network: + +```yaml +peers: + - '/dnsaddr/bootstrap.enclave.gg' +``` + +Or specify individual peers: + +```yaml +peers: + - '/dns4/node1.example.com/udp/9091/quic-v1' + - '/ip4/192.168.1.100/udp/9091/quic-v1' +``` + +--- + +## Data Directories + +| Directory | Contents | +| ------------------------------ | --------------------------------- | +| `~/.config/enclave/` | Configuration files, network keys | +| `~/.local/share/enclave/` | Databases, job data, keystores | +| `~/.local/share/enclave/jobs/` | Per-E3 secret shares and state | + +> Back up these directories regularly. The `jobs/` directory contains encrypted key shares for +> active E3s - losing this data while participating in a committee may result in slashing. + +--- + +## Monitoring + +### Log Levels + +Control verbosity with the `-v` flag: + +| Flag | Level | Description | +| ------ | ----- | ------------------------ | +| (none) | WARN | Warnings and errors only | +| `-v` | INFO | Normal operation logs | +| `-vv` | DEBUG | Detailed debug output | +| `-vvv` | TRACE | Full trace logging | + +### Key Events to Watch + +| Event | Meaning | +| --------------------------- | ------------------------------------ | +| `E3Requested` | New computation request detected | +| `TicketGenerated` | Your sortition ticket was calculated | +| `CiphernodeSelected` | You were selected for a committee | +| `KeyshareCreated` | Your key share was generated | +| `PublicKeyAggregated` | Committee public key is ready | +| `CiphertextOutputPublished` | Time to generate decryption share | +| `DecryptionshareCreated` | Your decryption share was published | +| `PlaintextAggregated` | Final result is available | + +--- + +## Next Steps + +Once your node is running: + +1. **[Register & License](./registration)** - Bond ENCL and register as an operator +2. **[Add Tickets](./tickets-and-sortition)** - Purchase tickets to participate in sortition diff --git a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx index 449af514c4..a70986fe41 100644 --- a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx +++ b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx @@ -1,139 +1,177 @@ --- title: 'Tickets & Sortition' +description: 'How ticket balances influence committee selection' --- # Tickets & Sortition -> Ticket availability: `availableTickets = floor(ticketTokenBalance / ticketPrice)` +Tickets determine your probability of being selected for E3 committees. This guide explains the +ticket system and sortition algorithm. -| Stake | Token | Purpose | Key calls | -| ------------ | -------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------- | -| License bond | ENCL | Unlock registration + maintain eligibility | `bondLicense`, `unbondLicense`, `getLicenseBond` | -| Tickets | ETK (non-transferable, backed by USDC) | Determine committee probability | `addTicketBalance`, `removeTicketBalance`, `getTicketBalance`, `availableTickets` | +## Ticket Overview -- Keep ≥ `licenseRequiredBond * 0.8` bonded or `isActive` flips false. -- Hold ≥ `minTicketBalance` tickets so the registry considers you for committees. -- Check `hasExitInProgress` / `pendingExits` before rebonding; queued exits block new registrations. +| Token | Purpose | Transferable | +| -------- | -------------------------------------------------- | ------------ | +| **ENCL** | License bond - required to register | Yes | +| **ETK** | Ticket token - determines committee selection odds | No | +| **USDC** | Underlying asset for tickets (fee token) | Yes | -## Ticket economics +Tickets are priced in stablecoins and minted into non-transferable ETK balances: -- Tickets are priced in stablecoins, minted into non-transferable ETK balances, and track intent to - work. -- Committee probability scales linearly with `availableTickets`; doubling tickets doubles your odds - if peers stay constant. -- Balances are snapshotted at `requestBlock - 1`. Adding tickets after the request event does not - change that round. -- Rewards accrue only when committees form and you complete duties, so idle tickets still incur the - opportunity cost of locked capital. +``` +availableTickets = floor(ticketTokenBalance / ticketPrice) +``` + +## Managing Tickets + +### Buy Tickets -### Managing ticket balance +Deposit stablecoins to mint tickets: ```bash -# Approve USDC (or configured fee token) -cast send $FEE_TOKEN "approve(address,uint256)" $BONDING 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY +# Buy tickets worth 100 USDC +enclave ciphernode tickets buy --amount 100 +``` + +This: + +1. Approves the ticket contract to spend your USDC (if needed) +2. Deposits the stablecoin +3. Mints equivalent ETK to your balance + +### Burn Tickets -# Add tickets (mints ETK) -cast send $BONDING "addTicketBalance(uint256)" 1000e6 --rpc-url $RPC --private-key $OPERATOR_KEY +Withdraw the underlying stablecoin: -# Remove tickets (burns ETK, returns USDC) -cast send $BONDING "removeTicketBalance(uint256)" 500e6 --rpc-url $RPC --private-key $OPERATOR_KEY +```bash +# Burn tickets and withdraw 50 USDC worth +enclave ciphernode tickets burn --amount 50 ``` -`removeTicketBalance` takes effect immediately. Dropping below the minimum ticket balance makes you -inactive until you top up again. +> Burning tickets takes effect immediately. Dropping below the minimum ticket balance makes you +> inactive until you top up again. + +### Check Balance + +```bash +enclave ciphernode status +``` + +Look for the "Ticket balance" and "available" fields in the output. + +## Ticket Economics -### Rebalancing tips +- **Committee probability scales linearly** with your available tickets relative to other operators +- **Doubling your tickets doubles your odds** (assuming peers stay constant) +- **Balances are snapshotted** at `requestBlock - 1` - adding tickets after a request won't help + that round +- **Idle tickets have opportunity cost** - rewards only accrue when you're selected and complete + duties -- Add tickets one or two requests ahead of anticipated demand to avoid race-condition gas spikes. -- Keep a small ticket buffer so slashing or removals do not instantly deactivate you. -- Monitor `ticketPrice()` and `minTicketBalance()` before automating deposits on multiple networks. +### Rebalancing Tips -## Sortition algorithm +- Add tickets **one or two requests ahead** of anticipated demand to avoid gas spikes +- Keep a **small buffer** so slashing or removals don't instantly deactivate you +- Monitor `ticketPrice()` and `minTicketBalance()` before automating deposits on multiple networks + +## Sortition Algorithm + +The sortition process selects committees deterministically based on a random seed: ```mermaid flowchart TD - A[E3Requested event] --> B[Snapshot balances (requestBlock - 1)] - B --> C[CLI filters active + ticketed operators] - C --> D[Submit numbered tickets via submitTicket] - D --> E[TicketSubmitted events expose scores] - E --> F[Finalize committee after submission deadline] - F --> G[Publish committee public key] - G --> H[Execute jobs (keyshares, ciphertext, decryption)] + A[E3Requested event] --> B[Snapshot balances at requestBlock - 1] + B --> C[Filter eligible operators] + C --> D[Calculate ticket scores] + D --> E[Submit winning tickets on-chain] + E --> F[Finalize committee after deadline] + F --> G[Generate and publish key shares] ``` -### 1. Event intake & eligibility +### 1. Eligibility Check -1. `Enclave` requests a committee, triggering `CommitteeRequested` with the round seed, threshold, - and submission deadline. -2. Nodes snapshot balances at `requestBlock - 1` and build an **eligible set** where operators are: - - Registered and not banned - - `isActive` (bond + ticket minimums satisfied) - - Not in the middle of an exit +When `CommitteeRequested` fires, nodes check if they're eligible: -### 2. Score-based selection +- Registered and not banned +- `isActive` (bond + ticket minimums satisfied) +- No exit in progress -Sortition is deterministic once the seed and eligible set are known: +### 2. Score Calculation -1. Derive per-ticket scores with `keccak256(seed, operator, ticketNumber)`. -2. Sort scores and take the top `threshold_n` entries. -3. Because the same inputs yield the same winners, every honest node converges on the same - committee. +For each ticket you hold, a score is calculated: -### 3. Ticket submissions & committee finalization +``` +score = keccak256(seed, operator, ticketNumber) +``` -1. Operators submit each winning ticket via `submitTicket(e3Id, ticketNumber)` during the - `sortitionSubmissionWindow` (10s on Sepolia). -2. Every submission emits `TicketSubmitted(e3Id, operator, ticketNumber, score)` so you can audit - progress. -3. After the window closes and ≥ `threshold_m` tickets are present, anyone calls - `finalizeCommittee(e3Id)`; the registry emits `CommitteeFinalized`. -4. Once enough key shares are ready, the CLI drives `publishCommittee`, emitting - `CommitteePublished` with the aggregated key. +The same inputs always produce the same scores, so all honest nodes converge on the same committee. -### 4. Committee operations +### 3. Ticket Submission -- Generate and encrypt PVSS key shares for the round. -- Publish the committee public key once the threshold is met. -- Stay online for `CiphertextOutputPublished` and respond with decryption shares until - `PlaintextOutputPublished` confirms completion. +Operators submit their winning tickets during the submission window (10 seconds on Sepolia): -See the [Operations & Responsibilities](./operations) page for the detailed job lifecycle. +```bash +# The CLI handles this automatically when running +submitTicket(e3Id, ticketNumber) +``` -## Parameter reference +Each submission emits `TicketSubmitted(e3Id, operator, ticketNumber, score)`. -```solidity -uint32[2] threshold; // [threshold_m, threshold_n] -``` +### 4. Committee Finalization + +After the window closes and ≥ `threshold_m` tickets are present: + +1. Anyone can call `finalizeCommittee(e3Id)` +2. Registry emits `CommitteeFinalized` +3. Selected nodes generate and publish key shares +4. Aggregated public key is published via `publishCommittee` + +## Parameters + +| Parameter | Sepolia Value | Description | +| --------------------------- | ------------- | ----------------------------------- | +| `ticketPrice` | 10 USDC | Cost per ticket | +| `minTicketBalance` | 1 ticket | Minimum to be active | +| `sortitionSubmissionWindow` | 10 seconds | Time to submit winning tickets | +| `threshold_m` | Varies | Minimum operators needed for duties | +| `threshold_n` | Varies | Total committee size | + +## Monitoring + +### Events to Watch + +| Event | Meaning | +| -------------------- | ------------------------------------ | +| `CommitteeRequested` | New committee formation started | +| `TicketSubmitted` | A ticket was submitted for selection | +| `CommitteeFinalized` | Committee members confirmed | +| `CommitteePublished` | Aggregated public key ready | -- `threshold_m` — Minimum number of operators needed for duties (e.g., 3). -- `threshold_n` — Committee size (e.g., 5). The CLI submits up to this many tickets per E3. -- Use `CiphernodeRegistry.sortitionSubmissionWindow()` to size your submission workers. +### Log Messages -## Monitoring & troubleshooting +Watch your node logs for: -### Signals to watch +- `sortition::submitted` - Successfully submitted tickets +- `sortition::missed` - Failed to submit in time +- `jobs::selected` - You were selected for a committee -- `CommitteeRequested`, `TicketSubmitted`, `CommitteeFinalized`, and `CommitteePublished` events. -- CLI logs: `sortition::submitted`, `sortition::missed`, `jobs::selected`. -- Contract reads: `submissions(e3Id, operator)` to confirm ticket IDs and `getCommitteeNodes(e3Id)` - post-finalization. +## Troubleshooting -### Common issues +| Symptom | Possible Cause | Solution | +| ------------------------------- | ------------------------------------- | -------------------------------- | +| Never being selected | Low ticket count relative to peers | Add more tickets | +| `isActive` is false | Below minimum tickets or license bond | Top up tickets or rebond license | +| `SubmissionWindowClosed` errors | RPC latency or slow submission | Use faster RPC, check network | +| Committee missing your operator | Submission didn't succeed | Check logs, retry next round | -| Symptom | Checks | Fix | -| ------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -| Not being selected | Verify `isActive`, ticket balance ≥ minimum, no bans, and compare tickets to peers | Add tickets, rebond license, or appeal bans | -| `SubmissionWindowClosed` errors | Ensure submissions start immediately after `CommitteeRequested` and that RPC latency is low | Increase submission workers, reduce per-ticket delays | -| Committee missing operator | Confirm CLI derived the same winners (seed + tickets) and that submissions succeeded | Replay submissions, inspect `TicketSubmitted` logs, retry with correct ticket IDs | +## Best Practices -## Best practices +1. **Stagger ticket top-ups** - Avoid last-minute gas competition +2. **Alert on missed submissions** - Human intervention before committee deadlines +3. **Batch networks separately** - Run separate CLI instances per chain +4. **Track governance changes** - `sortitionSubmissionWindow`, `ticketPrice`, and + `licenseRequiredBond` may change -- **Stagger ticket top-ups** to avoid last-minute gas spikes. -- **Alert on missed submissions** so humans can intervene before committee deadlines. -- **Batch networks** by running separate CLI supervisors per chain; congestion on one network should - not block another. -- **Track governance knobs** like `sortitionSubmissionWindow`, `ticketPrice`, and - `licenseRequiredBond` so automation adapts when values change. +## Next Steps -For deeper visuals, skim `crates/sortition/README` or the ciphernodes architecture docs; they mirror -the same deterministic score-based flow described here. +- **[Exits, Rewards & Slashing](./exits-and-slashing)** - Understand rewards and how to exit safely From 60d47be8a794829968467bc5b2942130c6271be8 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 10 Dec 2025 20:43:33 +0500 Subject: [PATCH 10/19] chore: update docs --- docs/pages/ciphernode-operators/index.mdx | 18 +++++++++--------- docs/pages/ciphernode-operators/running.mdx | 16 +++++++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/pages/ciphernode-operators/index.mdx b/docs/pages/ciphernode-operators/index.mdx index feea53c66f..51bee02927 100644 --- a/docs/pages/ciphernode-operators/index.mdx +++ b/docs/pages/ciphernode-operators/index.mdx @@ -38,15 +38,15 @@ The Enclave protocol uses several contracts that work together: ### Sepolia Contract Addresses -| Contract | Address | -| -------------------- | -------------------------------------------- | -| Enclave | `0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6` | -| CiphernodeRegistry | `0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7` | -| BondingRegistry | `0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3` | -| SlashingManager | `0x50dfC643226f09423d51F81c7f37F7a5F1e8f359` | -| EnclaveTicketToken | `0x72691272E10a8CA6499c3aa0d59c76E4C090c9E2` | -| EnclaveToken (ENCL) | `0xc93f71D10874F09F7F514a3d160E5be21fD624ab` | -| MockUSDC (fee token) | `0xB58B762748c64f1a36B34012d1C52503617f4De0` | +| Contract | Address | Deploy block | +| -------------------- | -------------------------------------------- | ------------ | +| Enclave | `0x01E657C16192854E8d7D7055228C7D6532E345Be` | 9761354 | +| CiphernodeRegistry | `0x754490FF874f24fe36124006f9fE0bBaCADDd746` | 9761351 | +| BondingRegistry | `0xA8E7583955797F4C3827eC7bf20872C687bD6313` | 9761313 | +| SlashingManager | `0x2EA642a7431C0d4D958Ce69f0A10c64D49977127` | 9761309 | +| EnclaveTicketToken | `0xE375634734eC04E94c77907804F8DfF2A45EcFc5` | 9761309 | +| EnclaveToken (ENCL) | `0x8F079950F69FB1574B30737F4879F5BE620d3028` | 9761309 | +| MockUSDC (fee token) | `0x00b322ED68246EcD66069BBE4F2C5070d2973efE` | 9761309 | > Always verify addresses from `packages/enclave-contracts/deployed_contracts.json` or your > deployment output. Addresses differ per network. diff --git a/docs/pages/ciphernode-operators/running.mdx b/docs/pages/ciphernode-operators/running.mdx index 44b6391d1c..cbe489b256 100644 --- a/docs/pages/ciphernode-operators/running.mdx +++ b/docs/pages/ciphernode-operators/running.mdx @@ -64,8 +64,8 @@ enclave config-set \ --eth-address 0xYourAddress ``` -This creates `~/.config/enclave/config.yaml`. You'll be prompted for a password to encrypt sensitive -data. +This creates `~/.config/enclave/enclave.config.yaml`. You'll be prompted for a password to encrypt +sensitive data. ### Set Up Credentials @@ -84,7 +84,7 @@ enclave wallet set --private-key 0xYourPrivateKey ### Configure Your Node -Edit `~/.config/enclave/config.yaml`: +Edit `~/.config/enclave/enclave.config.yaml`: ```yaml node: @@ -100,12 +100,14 @@ chains: rpc_url: 'wss://ethereum-sepolia-rpc.publicnode.com' contracts: enclave: - address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' - deploy_block: 9615399 + address: '0x01E657C16192854E8d7D7055228C7D6532E345Be' + deploy_block: 9761354 ciphernode_registry: - address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + address: '0x754490FF874f24fe36124006f9fE0bBaCADDd746' + deploy_block: 9761351 bonding_registry: - address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' + address: '0xA8E7583955797F4C3827eC7bf20872C687bD6313' + deploy_block: 9761313 ``` ### Start Your Node From a88bd14a7f471c0201a59389dc3bbc488db1a10d Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Thu, 11 Dec 2025 00:27:16 +0500 Subject: [PATCH 11/19] chore: update docs --- docs/pages/ciphernode-operators/registration.mdx | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/pages/ciphernode-operators/registration.mdx b/docs/pages/ciphernode-operators/registration.mdx index 080e2ef5f4..7db315c51e 100644 --- a/docs/pages/ciphernode-operators/registration.mdx +++ b/docs/pages/ciphernode-operators/registration.mdx @@ -18,9 +18,6 @@ Before registering, ensure your wallet has: | **USDC** (or fee token) | ≥ 10 USDC per ticket (minimum 1 ticket) | Ticket balance for sortition | | **ETH** | Sufficient for gas | Transaction fees | -> On Sepolia testnet, use MockUSDC at `0xB58B762748c64f1a36B34012d1C52503617f4De0` and ENCL at -> `0xc93f71D10874F09F7F514a3d160E5be21fD624ab`. - ## Registration Steps ### Step 1: Check Current Status From 922e641b7dd38e2c1b33c5bc65e46bcdb5b518cb Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 16 Dec 2025 18:47:31 +0500 Subject: [PATCH 12/19] chore: update docs --- docs/pages/CRISP/running-e3.mdx | 32 +++++++++++-------- docs/pages/CRISP/setup.mdx | 2 +- docs/pages/best-practices.mdx | 2 +- docs/pages/building-with-enclave.mdx | 5 ++- .../tickets-and-sortition.mdx | 2 +- docs/pages/noir-circuits.mdx | 4 +-- docs/pages/project-template.mdx | 4 +-- 7 files changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/pages/CRISP/running-e3.mdx b/docs/pages/CRISP/running-e3.mdx index e724316d32..902f5a0f6e 100644 --- a/docs/pages/CRISP/running-e3.mdx +++ b/docs/pages/CRISP/running-e3.mdx @@ -54,36 +54,40 @@ Behind the scenes `scripts/dev.sh` calls `scripts/dev_services.sh`, which: Keep this terminal open; logs from every service are multiplexed with `pnpm concurrently`. -### (Optional) Build Once for Production +### Initialize a New Voting Round -If you want release binaries or a static client before running, execute: +Open a new terminal and launch the CLI from the example root: ```sh -pnpm dev:build +pnpm cli ``` -That pipeline runs `cargo build --locked`, compiles the contracts, and builds the client bundle. +You can initialize a round using the interactive menu or directly via command-line flags: -### Initialize a New Voting Round +**Interactive Menu:** -Open a new terminal and launch the CLI from the example root: +1. Select `Initialize new E3 round` +2. Enter the token contract address +3. Enter the balance threshold for the voting round -```sh -pnpm cli +**Command-Line (Direct):** + +```bash +cargo run --bin cli init --token-address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 --balance-threshold 1000 ``` In the interactive menu: -1. Select `CRISP: Voting Protocol (ETH)` -2. Choose `Initialize new E3 round` +- `--token-address`: ERC20 token address for voting eligibility +- `--balance-threshold`: Balance threshold for the voting round You should see output similar to: ```sh -[2024-10-22 11:56:11] [commands.rs:42] - Starting new CRISP round! -[2024-10-22 11:56:11] [commands.rs:46] - Enabling E3 Program... -[2024-10-22 11:56:11] [commands.rs:50] - E3 Program enabled. TxHash: 0xa391a4cd2dcc59f4bc6dd1f5ed1c78006dbba4556ea633f4b6a53e2271538682 -[2024-10-22 11:56:11] [commands.rs:74] - E3 request sent. TxHash: 0xe7998b9748e3526f6ca992c9bb498beabe4f387b02240a23d0f42a2386d3c305 +[2025-12-16 13:41:37] [commands.rs:77] - Starting new CRISP round with token address: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 and balance threshold: 1000000000000000000 +[2025-12-16 13:41:37] [commands.rs:90] - Enabling E3 Program with address: 0x67d269191c92Caf3cD7723F116c85e6E9bf55933 +[2025-12-16 13:41:37] [commands.rs:94] - E3 Program enabled. TxHash: 0xa391a4cd2dcc59f4bc6dd1f5ed1c78006dbba4556ea633f4b6a53e2271538682 +[2025-12-16 13:41:37] [commands.rs:118] - E3 request sent. TxHash: 0xe7998b9748e3526f6ca992c9bb498beabe4f387b02240a23d0f42a2386d3c305 ``` ### Set Up MetaMask diff --git a/docs/pages/CRISP/setup.mdx b/docs/pages/CRISP/setup.mdx index e3669757c5..b41fe828e3 100644 --- a/docs/pages/CRISP/setup.mdx +++ b/docs/pages/CRISP/setup.mdx @@ -183,7 +183,7 @@ program URL: ```bash # This compiles the guest program and uploads it to IPFS via Pinata - enclave program upload --pinata-jwt YOUR_PINATA_JWT + enclave program upload ``` 3. The command will output an IPFS hash like `QmXxx...`. Update your `enclave.config.yaml` with the diff --git a/docs/pages/best-practices.mdx b/docs/pages/best-practices.mdx index 546f5a108e..0589457ae0 100644 --- a/docs/pages/best-practices.mdx +++ b/docs/pages/best-practices.mdx @@ -18,7 +18,7 @@ clear guardrails for confidential compute. This guide distills the equivalent pl ## Input Validation -- **Push logic to validators**: Implement `IInputValidator.validate` so ZK proofs and policy checks +- **Push logic to validators**: Implement `IE3Program.validateInput` so ZK proofs and policy checks happen before the Secure Process. This mirrors how CoFHE tutorials offload range proofs from the heavy computation path. - **Replay protection**: Include round identifiers or nullifiers inside inputs before you hash them diff --git a/docs/pages/building-with-enclave.mdx b/docs/pages/building-with-enclave.mdx index 916727e827..56601efdad 100644 --- a/docs/pages/building-with-enclave.mdx +++ b/docs/pages/building-with-enclave.mdx @@ -93,7 +93,8 @@ function publishInput( ) external ``` -Inputs are accumulated incrementally into a Merkle tree (LeanIMT). This allows you to: +Inputs can be accumulated incrementally into a Merkle tree (LazyIMT, or ultimately chosen by the +program implementation). This allows you to: 1. Use the published Merkle root as part of your E3 Program's Secure Process to ensure all published inputs are processed by the Compute Provider. @@ -135,6 +136,8 @@ to the E3's public key. It is also recommended to bundle in proofs to validate: ### Key Events +The following events are emitted by the Program contract: + ```solidity event E3Requested(uint256 indexed e3Id, address indexed requester, address e3ProgramAddress); diff --git a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx index a70986fe41..d0c06e3f37 100644 --- a/docs/pages/ciphernode-operators/tickets-and-sortition.mdx +++ b/docs/pages/ciphernode-operators/tickets-and-sortition.mdx @@ -108,7 +108,7 @@ The same inputs always produce the same scores, so all honest nodes converge on ### 3. Ticket Submission -Operators submit their winning tickets during the submission window (10 seconds on Sepolia): +Operators submit their winning tickets during the submission window (300 seconds on Sepolia): ```bash # The CLI handles this automatically when running diff --git a/docs/pages/noir-circuits.mdx b/docs/pages/noir-circuits.mdx index 056afb3724..934c3dc011 100644 --- a/docs/pages/noir-circuits.mdx +++ b/docs/pages/noir-circuits.mdx @@ -6,8 +6,8 @@ description: 'Build and reuse Noir circuits for Enclave programs' # Noir Circuits & Libraries Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge, -polynomial utilities, GRECO hashing, etc.). Use these circuits as-is or vendor them into your own E3 -programs. +polynomial utilities, Poseidon hashing, etc.). Use these circuits as-is or vendor them into your own +E3 programs. ## Workspace layout diff --git a/docs/pages/project-template.mdx b/docs/pages/project-template.mdx index e8d1c03625..d3a199262c 100644 --- a/docs/pages/project-template.mdx +++ b/docs/pages/project-template.mdx @@ -14,10 +14,10 @@ playground for building and testing E3 programs without copying the entire monor ``` my-first-e3/ ├── contracts/ # Hardhat workspace with Enclave adapters + your E3 program contracts -├── program/ # RISC Zero guest code and runner +├── program/ # RISC Zero guest code ├── server/ # TypeScript coordination server ├── client/ # React + Vite frontend wired to @enclave-e3/sdk -├── deploy/ # Scripts + ignition configs +├── deploy/ # Deployment scripts ├── scripts/ # Helper scripts (start dev stack, ciphernodes, etc.) ├── tests/ # Integration + contract tests ├── enclave.config.yaml # Node + chain config consumed by the CLI From d13d251a39bcaa3a15b96c9605edfc331071c87b Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 16 Dec 2025 20:15:31 +0500 Subject: [PATCH 13/19] chore: update docs --- docs/pages/CRISP/running-e3.mdx | 2 +- docs/pages/building-with-enclave.mdx | 10 +++++++--- docs/pages/noir-circuits.mdx | 6 +++--- examples/CRISP/Readme.md | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/pages/CRISP/running-e3.mdx b/docs/pages/CRISP/running-e3.mdx index 902f5a0f6e..b135a238e0 100644 --- a/docs/pages/CRISP/running-e3.mdx +++ b/docs/pages/CRISP/running-e3.mdx @@ -95,7 +95,7 @@ You should see output similar to: Whether you used `pnpm dev:up` or the manual flow below, you will interact with the Hardhat chain running at `http://localhost:8545` (chain ID `31337`). Configure MetaMask once: -1. Import the Hardhat/Anvil deployer key so you have funds available: +1. Import the Hardhat deployer key so you have funds available: ``` 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ``` diff --git a/docs/pages/building-with-enclave.mdx b/docs/pages/building-with-enclave.mdx index 56601efdad..3ed67e64bc 100644 --- a/docs/pages/building-with-enclave.mdx +++ b/docs/pages/building-with-enclave.mdx @@ -136,18 +136,22 @@ to the E3's public key. It is also recommended to bundle in proofs to validate: ### Key Events -The following events are emitted by the Program contract: +**Enclave Contract Events:** ```solidity event E3Requested(uint256 indexed e3Id, address indexed requester, address e3ProgramAddress); -event InputPublished(uint256 indexed e3Id, bytes data, uint256 inputHash, uint256 index); - event CiphertextOutputPublished(uint256 indexed e3Id, bytes ciphertextOutput); event PlaintextOutputPublished(uint256 indexed e3Id, bytes plaintextOutput); ``` +**Program Contract Events:** + +```solidity +event InputPublished(uint256 indexed e3Id, bytes data, uint256 inputHash, uint256 index); +``` + ### Result Publication Flow 1. The Compute Provider submits a proof and ciphertext output. diff --git a/docs/pages/noir-circuits.mdx b/docs/pages/noir-circuits.mdx index 934c3dc011..3fb9424a49 100644 --- a/docs/pages/noir-circuits.mdx +++ b/docs/pages/noir-circuits.mdx @@ -5,8 +5,8 @@ description: 'Build and reuse Noir circuits for Enclave programs' # Noir Circuits & Libraries -Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge, -polynomial utilities, Poseidon hashing, etc.). Use these circuits as-is or vendor them into your own +Enclave ships a dedicated Noir workspace under `circuits/` plus reusable libraries (SAFE sponge API, +polynomial utilities, Greco BFV proofs, etc.). Use these circuits as-is or vendor them into your own E3 programs. ## Workspace layout @@ -17,7 +17,7 @@ circuits/ ├── crates/ │ └── libs/ │ ├── safe/ # SAFE sponge implementation -│ ├── greco/ # Poseidon & Merkle helpers +│ ├── greco/ # ZK circuit for BFV ciphertext correctness proofs │ └── polynomial/ # polynomial commitments utils └── target/ # build artifacts (created by nargo) ``` diff --git a/examples/CRISP/Readme.md b/examples/CRISP/Readme.md index 900c89ec67..44e0f6c3ae 100644 --- a/examples/CRISP/Readme.md +++ b/examples/CRISP/Readme.md @@ -232,7 +232,7 @@ program: > - A Pinata JWT for uploading programs to IPFS (get one at [pinata.cloud](https://pinata.cloud)) > - Pre-uploaded program URL to avoid uploading the ~40MB program at runtime -**Uploading Your Program to IPFS** +### Uploading Your Program to IPFS When you make changes to the guest program in `program/`, you need to upload it to IPFS: From eb290fed8c2e48409987635d3b28d220d6b08846 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <36852564+hmzakhalid@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:42:07 +0500 Subject: [PATCH 14/19] chore: update docs/pages/CRISP/introduction.mdx Co-authored-by: Cedoor --- docs/pages/CRISP/introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index 698e937c1e..12368e7fc1 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -31,7 +31,7 @@ CRISP follows a modern Hardhat-based structure with clear separation of concerns ``` CRISP/ -├── client/ # React frontend application (Vite + @enclave-e3/sdk) +├── client/ # React frontend application (Vite + @crisp-e3/sdk) ├── server/ # Rust coordination server & CLI ├── program/ # RISC Zero guest + prover control plane ├── packages/ From deabb26085a099dfffe35049408c8571ffaf1136 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <36852564+hmzakhalid@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:42:26 +0500 Subject: [PATCH 15/19] chore: update docs/pages/CRISP/introduction.mdx Co-authored-by: Cedoor --- docs/pages/CRISP/introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index 12368e7fc1..c26d5ad849 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -49,7 +49,7 @@ CRISP/ ### **Client Application** (`/client`) The client is a React application built with TypeScript that provides a voting interface and reuses -the shared [Enclave SDK](/sdk): +the shared [CRISP SDK](/sdk): - Wallet connection with MetaMask and other wallets - Vote encryption using WebAssembly-based FHE encryption before submission From a96e32550630a96f66ad992c585781b94bb89803 Mon Sep 17 00:00:00 2001 From: Hamza Khalid <36852564+hmzakhalid@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:42:40 +0500 Subject: [PATCH 16/19] chore: update docs/pages/CRISP/introduction.mdx Co-authored-by: Cedoor --- docs/pages/CRISP/introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index c26d5ad849..feca1a78df 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -36,7 +36,7 @@ CRISP/ ├── program/ # RISC Zero guest + prover control plane ├── packages/ │ ├── crisp-contracts/ # Hardhat deployment + helpers -│ └── sdk/ # CRISP-specific TypeScript helpers +│ └── crisp-sdk/ # CRISP-specific TypeScript helpers to generate a ZK proof ├── crates/ # Rust libraries for the CLI + services ├── circuits/ # Noir circuits + verifiers (see [Noir Circuits](/noir-circuits)) ├── scripts/ # dev.sh, setup.sh, compile_circuits.sh, etc. From 7cb815064ddaa5cd9b47e054ac00951a2c4cb876 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 17 Dec 2025 15:02:24 +0500 Subject: [PATCH 17/19] chore: update docs --- docs/pages/CRISP/introduction.mdx | 2 +- docs/pages/CRISP/running-e3.mdx | 4 +--- docs/pages/ciphernode-operators/running.mdx | 10 ++++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/pages/CRISP/introduction.mdx b/docs/pages/CRISP/introduction.mdx index feca1a78df..3523c12720 100644 --- a/docs/pages/CRISP/introduction.mdx +++ b/docs/pages/CRISP/introduction.mdx @@ -36,7 +36,7 @@ CRISP/ ├── program/ # RISC Zero guest + prover control plane ├── packages/ │ ├── crisp-contracts/ # Hardhat deployment + helpers -│ └── crisp-sdk/ # CRISP-specific TypeScript helpers to generate a ZK proof +│ └── crisp-sdk/ # CRISP-specific TypeScript helpers to generate a ZK proof ├── crates/ # Rust libraries for the CLI + services ├── circuits/ # Noir circuits + verifiers (see [Noir Circuits](/noir-circuits)) ├── scripts/ # dev.sh, setup.sh, compile_circuits.sh, etc. diff --git a/docs/pages/CRISP/running-e3.mdx b/docs/pages/CRISP/running-e3.mdx index b135a238e0..7b72f836a7 100644 --- a/docs/pages/CRISP/running-e3.mdx +++ b/docs/pages/CRISP/running-e3.mdx @@ -18,8 +18,6 @@ complete voting round of CRISP and do the following: Please make sure you have followed the [CRISP Setup](/CRISP/setup) guide before proceeding. -enclave nodes up -v - ### Prep Once per Checkout @@ -76,7 +74,7 @@ You can initialize a round using the interactive menu or directly via command-li cargo run --bin cli init --token-address 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 --balance-threshold 1000 ``` -In the interactive menu: +**Command-line flags:** - `--token-address`: ERC20 token address for voting eligibility - `--balance-threshold`: Balance threshold for the voting round diff --git a/docs/pages/ciphernode-operators/running.mdx b/docs/pages/ciphernode-operators/running.mdx index cbe489b256..8c828a63a5 100644 --- a/docs/pages/ciphernode-operators/running.mdx +++ b/docs/pages/ciphernode-operators/running.mdx @@ -166,12 +166,14 @@ chains: rpc_url: 'wss://ethereum-sepolia-rpc.publicnode.com' contracts: enclave: - address: '0x1E8BD97F15Cd94f250a4dd567d2fd2114303FAa6' - deploy_block: 9615399 + address: '0x01E657C16192854E8d7D7055228C7D6532E345Be' + deploy_block: 9761354 ciphernode_registry: - address: '0x11F647479bEd47cd0dd10276DDc04F2d4B20b1C7' + address: '0x754490FF874f24fe36124006f9fE0bBaCADDd746' + deploy_block: 9761351 bonding_registry: - address: '0x56368bB545Ab2D6811b4dffa8Ad4B8AF560406E3' + address: '0xA8E7583955797F4C3827eC7bf20872C687bD6313' + deploy_block: 9761313 ``` ### Run the Container From 464933da30dc1f42bcb9d2d9c7d35772abfc13bc Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 17 Dec 2025 16:01:48 +0500 Subject: [PATCH 18/19] chore: update docs --- docs/pages/sdk.mdx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/pages/sdk.mdx b/docs/pages/sdk.mdx index ffb9a5ef5b..df85d84aa2 100644 --- a/docs/pages/sdk.mdx +++ b/docs/pages/sdk.mdx @@ -112,9 +112,8 @@ export function Dashboard() { ## Configuration contract map Provide both the Enclave and CiphernodeRegistry addresses. The template exposes these via `.env` / -`enclave.config.yaml`, and CRISP scripts surface them in deployment logs. For multi-chain apps, -instantiate multiple SDKs or call `sdk.updateConfig({ contracts: { ... }, chainId })` whenever -wallets switch networks. +`enclave.config.yaml`. For multi-chain apps, instantiate multiple SDKs or call +`sdk.updateConfig({ contracts: { ... }, chainId })` whenever wallets switch networks. ## Working with the template @@ -129,6 +128,23 @@ client already wires `@enclave-e3/sdk` and `@enclave-e3/react`: When you add new contracts or E3 programs, update `client/.env` and `server/.env` with the new addresses, then restart the dev server so the SDK reconnects. +## Application-specific SDKs + +For complex E3 programs with specialized requirements, you may want to build an application-specific +SDK on top of or alongside the Enclave SDK. For example, +[CRISP](https://github.com/gnosisguild/enclave/tree/main/examples/CRISP) uses `@crisp-e3/sdk`, which +provides: + +- Zero-knowledge proof generation for votes using Noir circuits +- Merkle tree utilities for voter eligibility verification +- Vote encryption helpers using FHE +- Round management and token operations +- CRISP server interaction APIs + +If your E3 program requires specialized cryptographic operations, domain-specific logic, or +application-level abstractions beyond basic protocol interactions, consider building a dedicated SDK +that wraps or complements the core Enclave SDK. + ## Advanced usage - **Historical events**: `sdk.getHistoricalEvents(type, fromBlock, toBlock)` fetches logs without a From a0f23ec6d3960b679c456424bac06b229a93ba5d Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Wed, 17 Dec 2025 17:20:25 +0500 Subject: [PATCH 19/19] chore: update docs --- docs/pages/sdk.mdx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/pages/sdk.mdx b/docs/pages/sdk.mdx index df85d84aa2..92522ff639 100644 --- a/docs/pages/sdk.mdx +++ b/docs/pages/sdk.mdx @@ -71,16 +71,18 @@ const hash = await sdk.requestE3({ ### Event subscriptions ```ts -sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, (event) => { +const e3Handler = (event) => { console.log('New request', event.data) -}) +} + +sdk.onEnclaveEvent(EnclaveEventType.E3_REQUESTED, e3Handler) -sdk.onEnclaveEvent(RegistryEventType.CIPHERNODE_ADDED, (event) => { - console.log('Operator joined', event.data) +sdk.onEnclaveEvent(RegistryEventType.COMMITTEE_REQUESTED, (event) => { + console.log('Committee requested', event.data) }) // Later, remember to clean up -sdk.off(EnclaveEventType.E3_REQUESTED, handler) +sdk.off(EnclaveEventType.E3_REQUESTED, e3Handler) ``` ### React hook