From cb79b7442b27461e167f83816bb321a5ba2e8267 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Mon, 1 Dec 2025 20:33:40 +0500 Subject: [PATCH 1/3] feat: add a dappnode package --- dappnode/.gitignore | 33 +++++ dappnode/Dockerfile | 43 ++++++ dappnode/README.md | 240 +++++++++++++++++++++++++++++++++ dappnode/avatar-default.png | Bin 0 -> 13306 bytes dappnode/config.template.yaml | 25 ++++ dappnode/dappnode_package.json | 37 +++++ dappnode/docker-compose.yml | 46 +++++++ dappnode/entrypoint.sh | 79 +++++++++++ dappnode/releases.json | 8 ++ dappnode/setup-wizard.yml | 194 ++++++++++++++++++++++++++ 10 files changed, 705 insertions(+) create mode 100644 dappnode/.gitignore create mode 100644 dappnode/Dockerfile create mode 100644 dappnode/README.md create mode 100644 dappnode/avatar-default.png create mode 100644 dappnode/config.template.yaml create mode 100644 dappnode/dappnode_package.json create mode 100644 dappnode/docker-compose.yml create mode 100644 dappnode/entrypoint.sh create mode 100644 dappnode/releases.json create mode 100644 dappnode/setup-wizard.yml diff --git a/dappnode/.gitignore b/dappnode/.gitignore new file mode 100644 index 0000000000..537867f288 --- /dev/null +++ b/dappnode/.gitignore @@ -0,0 +1,33 @@ +# DAppNode Package - Git Ignore + +# Environment files with secrets +.env +*.env.local + +# Local test data +data/ + +# Build artifacts +build_*/ +*.tar.xz +*.txz + +# DAppNode SDK output +releases/ + +# Node modules (if any) +node_modules/ + +# OS files +.DS_Store +Thumbs.db + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# Logs +*.log +logs/ diff --git a/dappnode/Dockerfile b/dappnode/Dockerfile new file mode 100644 index 0000000000..f8274fe262 --- /dev/null +++ b/dappnode/Dockerfile @@ -0,0 +1,43 @@ +# DAppNode Enclave Ciphernode Dockerfile +# Uses official upstream image from GitHub Container Registry +# For local testing: use Dockerfile.local instead + +FROM hmzakhalid/enclave-ciphernode:0.1.0 AS upstream + +# Runtime image +FROM debian:stable-slim + +# Install runtime dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + procps \ + gettext-base \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user +RUN useradd -m -u 1000 -s /bin/bash ciphernode + +# Create data directory +RUN mkdir -p /data && chown ciphernode:ciphernode /data + +# Copy binary from upstream +COPY --from=upstream /usr/local/bin/enclave /usr/local/bin/enclave +RUN chmod +x /usr/local/bin/enclave + +# Copy entrypoint and config template +COPY --chmod=755 entrypoint.sh /usr/local/bin/entrypoint.sh +COPY --chmod=644 config.template.yaml /opt/config.template.yaml + +# Labels +LABEL maintainer="Gnosis Guild " +LABEL org.opencontainers.image.source="https://github.com/gnosisguild/enclave" +LABEL org.opencontainers.image.description="Enclave Ciphernode for DAppNode" + +USER ciphernode +WORKDIR /data + +HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ + CMD pgrep -f enclave || exit 1 + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/dappnode/README.md b/dappnode/README.md new file mode 100644 index 0000000000..370ba5c532 --- /dev/null +++ b/dappnode/README.md @@ -0,0 +1,240 @@ +# Enclave Ciphernode – DAppNode Package + +Run an Enclave ciphernode on DAppNode. + +This package wraps the `enclave` CLI in a DAppNode service so users can run a ciphernode with a +simple UI form (setup wizard) instead of hand-crafting configs and Docker commands. + +## Networks + +This is a **single-configuration** package: the same package can be pointed at different networks by +changing the config in the DAppNode UI. + +You choose: + +- `NETWORK` (e.g. `sepolia`, `mainnet`, `localhost`) +- The RPC URL [remote procedure call endpoint] +- Contract addresses and deploy blocks + +All of these are set in the setup wizard or in the package config after installation. + +## Files + +Package layout (from the `dappnode/` directory): + +```text +dappnode/ +├── Dockerfile # Builds the DAppNode image from the upstream ciphernode image +├── docker-compose.yml # DAppNode service definition (single variant) +├── dappnode_package.json # Package metadata (name, version, links, backup, etc.) +├── setup-wizard.yml # DAppNode UI form -> environment variables +├── entrypoint.sh # Startup script (validates env, renders config, runs enclave) +├── config.template.yaml # Enclave config template (filled via envsubst) +├── releases.json # Release metadata used by DAppNode +└── avatar-default.png # Icon shown in the DAppNode UI +``` + +All configuration is done via **environment variables**, wired through `docker-compose.yml` and +`setup-wizard.yml`. + +## Quick Start + +### For DAppNode Users + +Once this package is published to the DAppStore: + +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` – e.g. `sepolia`, `mainnet`, `localhost` + - Contract addresses + deploy blocks + - Node role (`ciphernode` or `aggregator`) + - Optional keys and peers + +4. Confirm and finish the installation. +5. Go to **Packages → enclave-ciphernode.public.dappnode.eth → Logs** to verify the node started + correctly. + +Until it’s in the public store, you can install it by IPFS hash: + +- Build it with the SDK (see “For Developers”). +- Paste the resulting `/ipfs/...` hash into the DAppNode installer UI (“Install from IPFS hash”). + +--- + +### For Developers + +You’ll typically: + +- Build the package with the DAppNode SDK. +- Install it on a DAppNode box (device or VM) from the resulting IPFS hash. +- Iterate on the entrypoint, config template, and setup wizard. + +#### 1. Build the package + +From the `dappnode/` directory: + +```bash +cd dappnode +npx @dappnode/dappnodesdk@latest build -p remote +``` + +This will: + +- Validate `docker-compose.yml`, `setup-wizard.yml`, and `dappnode_package.json` +- Build a multi-arch Docker image for `ciphernode.enclave-ciphernode.public.dappnode.eth` +- Upload the release to the DAppNode IPFS node +- Print an `/ipfs/` you can use to install the package + +#### 2. Install on your DAppNode instance + +In your browser (connected to your DAppNode): + +- Open the installer URL that the SDK prints, **or** +- Go to the DAppNode UI → Installer → “Install from IPFS hash” and paste the `/ipfs/`. + +Fill in the wizard fields, then install. + +#### 3. Debugging and iteration + +- Use the package **Logs** tab to inspect `entrypoint.sh` and `enclave` output. + +- If something is wrong in the generated config, `docker exec` into the container and inspect: + + ```bash + docker exec -it cat /data/config.yaml + ``` + +- Edit `entrypoint.sh`, `config.template.yaml`, or `setup-wizard.yml` locally, then rebuild with: + + ```bash + npx @dappnode/dappnodesdk@latest build -p remote + ``` + +- Reinstall with the new IPFS hash. + +## Configuration + +All runtime configuration is done via environment variables. They are: + +### Core + +- **`RPC_URL`** (required) WebSocket RPC endpoint for the chain (e.g. + `wss://ethereum-sepolia-rpc.publicnode.com`). + +- **`NETWORK`** Logical network name written into the Enclave config (e.g. `sepolia`, `mainnet`, + `localhost`). + +- **`NODE_ROLE`** + - `ciphernode` – participate in threshold decryption. + - `aggregator` – coordinate operations, requires a wallet key. + +- **`ETH_ADDRESS`** Optional Ethereum address to bind the node to. Leave empty to let Enclave handle + it. + +- **`QUIC_PORT`** Internal UDP port used for QUIC [Quick UDP Internet Connections] P2P networking. + Default in this package: `37173`. + +- **`LOG_LEVEL`** One of `info`, `debug`, `trace`. Mapped internally to `-v`, `-vv`, or `-vvv` when + calling `enclave start`. + +- **`EXTRA_OPTS`** Extra flags appended to the `enclave start` CLI. + +### Contracts + +Used to populate the `chains[0].contracts` section in `config.yaml`: + +- `ENCLAVE_CONTRACT` +- `CIPHERNODE_REGISTRY_CONTRACT` +- `BONDING_REGISTRY_CONTRACT` +- `ENCLAVE_DEPLOY_BLOCK` +- `CIPHERNODE_REGISTRY_DEPLOY_BLOCK` +- `BONDING_REGISTRY_DEPLOY_BLOCK` + +These are all required in the setup wizard so that the node can index chain events from the correct +block heights. + +### Secrets and keys + +- **`ENCRYPTION_PASSWORD`** Optional local encryption password. If set, `entrypoint.sh` calls: + - `enclave password set --config /data/config.yaml` + +- **`NETWORK_PRIVATE_KEY`** Optional libp2p network key. If set, `entrypoint.sh` calls: + - `enclave net set-key --config /data/config.yaml --net-keypair "$NETWORK_PRIVATE_KEY"` + +- **`PRIVATE_KEY`** Optional Ethereum private key (hex). Only needed for aggregator mode. If set, + `entrypoint.sh` calls: + - `enclave wallet set --config /data/config.yaml --private-key "$PRIVATE_KEY"` + +### Peers + +- **`PEERS`** Comma-separated list of peer multiaddresses, for example: + + ```text + /dns4/cn1/udp/37173/quic-v1,/dns4/cn2/udp/37173/quic-v1 + ``` + + The entrypoint splits this on commas, trims spaces, and turns each into a `--peer` flag: + + ```bash + enclave start ... --peer /dns4/cn1/udp/37173/quic-v1 --peer /dns4/cn2/udp/37173/quic-v1 + ``` + +If a variable is not set in the wizard, it still appears (with its default) in the package config +screen after installation, as per DAppNode’s env behavior. + +## How It Works Internally + +At container startup, `entrypoint.sh`: + +1. Validates `RPC_URL` is non-empty and starts with `ws://` or `wss://`. +2. Applies sensible defaults for `NETWORK`, `QUIC_PORT`, `NODE_ROLE`, and `LOG_LEVEL`. +3. Uses `envsubst` to render `config.template.yaml` into `/data/config.yaml`, substituting: + - node address, role, ports + - network name and RPC URL + - contract addresses and deploy blocks + +4. Optionally programs password, network key, and wallet key via the `enclave` CLI. +5. Builds CLI args, including verbosity and `--peer` flags from `PEERS`. +6. Executes: + + ```bash + enclave start --config /data/config.yaml ... + ``` + +The state and databases live under `/data` inside the container, which is backed by the +`ciphernode_data` Docker volume and listed as a backup target in `dappnode_package.json`. + +## Data & Ports + +- **Data volume**: `ciphernode_data` → `/data` This is where Enclave stores its databases and state. + +- **Ports**: + - **UDP 37173** – QUIC P2P networking (host and container). + +If you change `QUIC_PORT` in the config, you must also adjust the `ports:` mapping in +`docker-compose.yml` in a derived package. + +## Publishing + +To publish this package to the public DAppStore so others can install it: + +```bash +npx @dappnode/dappnodesdk@latest publish \ + --type= \ + --eth-provider= \ + --content-provider= \ + --developer-address= +``` + +The SDK will guide you through signing and broadcasting the on-chain transaction that registers the +new package version. + +## Links + +- [Enclave Docs](https://docs.enclave.gg) +- [DAppNode Package Development – Single Configuration](https://docs.dappnode.io/docs/dev/package-development/single-configuration/) +- [DAppNode Docker Compose Reference](https://docs.dappnode.io/docs/dev/references/docker-compose/) +- [DAppNode Setup Wizard Reference](https://docs.dappnode.io/docs/dev/references/setup-wizard/) +- [Enclave GitHub Repository](https://github.com/gnosisguild/enclave) diff --git a/dappnode/avatar-default.png b/dappnode/avatar-default.png new file mode 100644 index 0000000000000000000000000000000000000000..2365b0e440bd3daa7e0013114a6dd5838156740a GIT binary patch literal 13306 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 literal 0 HcmV?d00001 diff --git a/dappnode/config.template.yaml b/dappnode/config.template.yaml new file mode 100644 index 0000000000..a5f5703542 --- /dev/null +++ b/dappnode/config.template.yaml @@ -0,0 +1,25 @@ +# Enclave Ciphernode Configuration +# Generated by DAppNode entrypoint + +node: + address: '${NODE_ADDRESS}' + quic_port: ${QUIC_PORT} + role: + type: ${NODE_ROLE} + autonetkey: true + autopassword: true + autowallet: true + +chains: + - name: '${NETWORK}' + rpc_url: '${RPC_URL}' + contracts: + enclave: + address: '${ENCLAVE_CONTRACT}' + deploy_block: ${ENCLAVE_DEPLOY_BLOCK} + ciphernode_registry: + address: '${CIPHERNODE_REGISTRY_CONTRACT}' + deploy_block: ${CIPHERNODE_REGISTRY_DEPLOY_BLOCK} + bonding_registry: + address: '${BONDING_REGISTRY_CONTRACT}' + deploy_block: ${BONDING_REGISTRY_DEPLOY_BLOCK} diff --git a/dappnode/dappnode_package.json b/dappnode/dappnode_package.json new file mode 100644 index 0000000000..fad4e15863 --- /dev/null +++ b/dappnode/dappnode_package.json @@ -0,0 +1,37 @@ +{ + "name": "enclave-ciphernode.public.dappnode.eth", + "version": "0.1.0", + "upstreamVersion": "0.1.5", + "upstreamRepo": "gnosisguild/enclave", + "shortDescription": "Enclave Ciphernode - Run a node for confidential computing", + "description": "Run an Enclave ciphernode to participate in the E3 (Encrypted Execution Environments) network.", + "type": "service", + "mainService": "ciphernode", + "author": "Gnosis Guild ", + "categories": ["Blockchain", "Developer tools"], + "keywords": ["enclave", "fhe", "mpc", "ciphernode", "threshold", "encryption"], + "links": { + "homepage": "https://enclave.gg", + "docs": "https://docs.enclave.gg", + "repository": "https://github.com/gnosisguild/enclave" + }, + "repository": { + "type": "git", + "url": "https://github.com/gnosisguild/enclave.git", + "directory": "dappnode" + }, + "bugs": { + "url": "https://github.com/gnosisguild/enclave/issues" + }, + "license": "LGPL-3.0-only", + "requirements": { + "minimumDappnodeVersion": "0.2.50" + }, + "backup": [ + { + "name": "ciphernode-data", + "path": "/data", + "service": "ciphernode" + } + ] +} diff --git a/dappnode/docker-compose.yml b/dappnode/docker-compose.yml new file mode 100644 index 0000000000..50bae2a0f9 --- /dev/null +++ b/dappnode/docker-compose.yml @@ -0,0 +1,46 @@ +version: '3.5' +services: + ciphernode: + build: + context: . + args: + UPSTREAM_VERSION: 0.1.5 + image: 'ciphernode.enclave-ciphernode.public.dappnode.eth:0.1.0' + restart: unless-stopped + volumes: + - 'ciphernode_data:/data' + ports: + - 37173:37173/udp + environment: + # Required + RPC_URL: '' + # Network & node config + NETWORK: 'sepolia' + NODE_ROLE: 'ciphernode' + NODE_ADDRESS: '' + QUIC_PORT: '37173' + PEERS: '' + LOG_LEVEL: 'info' + EXTRA_OPTS: '' + # Secrets + ENCRYPTION_PASSWORD: '' + NETWORK_PRIVATE_KEY: '' + PRIVATE_KEY: '' + # Contracts (variants override these) + ENCLAVE_CONTRACT: '' + CIPHERNODE_REGISTRY_CONTRACT: '' + BONDING_REGISTRY_CONTRACT: '' + ENCLAVE_DEPLOY_BLOCK: '0' + CIPHERNODE_REGISTRY_DEPLOY_BLOCK: '0' + BONDING_REGISTRY_DEPLOY_BLOCK: '0' + security_opt: + - no-new-privileges:true + healthcheck: + test: ['CMD', 'pgrep', '-f', 'enclave'] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + +volumes: + ciphernode_data: {} diff --git a/dappnode/entrypoint.sh b/dappnode/entrypoint.sh new file mode 100644 index 0000000000..e3ecdb7568 --- /dev/null +++ b/dappnode/entrypoint.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# DAppNode Enclave Ciphernode Entrypoint +set -e + +CONFIG_DIR="/data" +CONFIG_FILE="$CONFIG_DIR/config.yaml" +TEMPLATE_FILE="/opt/config.template.yaml" + +log() { echo "[$(date '+%H:%M:%S')] $1"; } + +echo "==========================================" +echo " Enclave Ciphernode - ${NETWORK:-sepolia}" +echo "==========================================" + +# Validate RPC URL (required) +if [ -z "$RPC_URL" ]; then + log "ERROR: RPC_URL is required!" + log "Set it in the DAppNode package configuration." + exit 1 +fi + +if [[ ! "$RPC_URL" =~ ^wss?:// ]]; then + log "ERROR: RPC_URL must be a WebSocket URL (ws:// or wss://)" + exit 1 +fi + +# Set defaults +export NETWORK="${NETWORK:-sepolia}" +export QUIC_PORT="${QUIC_PORT:-37173}" +export NODE_ROLE="${NODE_ROLE:-ciphernode}" +export NODE_ADDRESS="${NODE_ADDRESS:-}" +export LOG_LEVEL="${LOG_LEVEL:-info}" + +# Contract addresses are set by package variants or environment variables +# No need for default placeholders here as variants handle network-specific values + +# Generate config from template +log "Generating configuration..." +envsubst < "$TEMPLATE_FILE" > "$CONFIG_FILE" + +# Setup secrets if provided +if [ -n "$ENCRYPTION_PASSWORD" ]; then + log "Setting encryption password..." + echo "$ENCRYPTION_PASSWORD" | enclave password set --config "$CONFIG_FILE" 2>/dev/null || true +fi + +if [ -n "$NETWORK_PRIVATE_KEY" ]; then + log "Setting network key..." + enclave net set-key --config "$CONFIG_FILE" --net-keypair "$NETWORK_PRIVATE_KEY" 2>/dev/null || true +fi + +if [ -n "$PRIVATE_KEY" ]; then + log "Setting wallet key..." + enclave wallet set --config "$CONFIG_FILE" --private-key "$PRIVATE_KEY" 2>/dev/null || true +fi + +# Build CLI args +CLI_ARGS="--config $CONFIG_FILE" + +case "$LOG_LEVEL" in + trace) CLI_ARGS="-vvv $CLI_ARGS" ;; + debug) CLI_ARGS="-vv $CLI_ARGS" ;; + info) CLI_ARGS="-v $CLI_ARGS" ;; +esac + +# Add peers if provided +if [ -n "$PEERS" ]; then + IFS=',' read -ra PEER_ARRAY <<< "$PEERS" + for peer in "${PEER_ARRAY[@]}"; do + peer=$(echo "$peer" | xargs) + [ -n "$peer" ] && CLI_ARGS="$CLI_ARGS --peer $peer" + done +fi + +[ -n "$EXTRA_OPTS" ] && CLI_ARGS="$CLI_ARGS $EXTRA_OPTS" + +# Start +log "Starting: enclave start $CLI_ARGS" +exec enclave start $CLI_ARGS \ No newline at end of file diff --git a/dappnode/releases.json b/dappnode/releases.json new file mode 100644 index 0000000000..1b6a59c96f --- /dev/null +++ b/dappnode/releases.json @@ -0,0 +1,8 @@ +{ + "0.1.0": { + "hash": "/ipfs/QmeX7jxDFcwbW7kAbs8Tgn5T4vonYxe4WmemUQsaca8xDQ", + "uploadedTo": { + "remote": "Mon, 01 Dec 2025 15:29:59 GMT" + } + } +} diff --git a/dappnode/setup-wizard.yml b/dappnode/setup-wizard.yml new file mode 100644 index 0000000000..183fb8b259 --- /dev/null +++ b/dappnode/setup-wizard.yml @@ -0,0 +1,194 @@ +# DAppNode Setup Wizard - Enclave Ciphernode +version: '2' +fields: + - id: NETWORK + target: + type: environment + name: NETWORK + service: ciphernode + title: 'Network' + description: 'Select the network to connect to.' + enum: + - sepolia + - mainnet + - localhost + required: true + + - id: RPC_URL + target: + type: environment + name: RPC_URL + service: ciphernode + title: 'RPC URL' + description: | + WebSocket RPC endpoint for the blockchain. + + Examples: + - Sepolia: wss://ethereum-sepolia-rpc.publicnode.com + - Mainnet: wss://ethereum.publicnode.com + - Localhost: ws://localhost:8545 + required: true + pattern: '^wss?://.*' + patternErrorMessage: 'Must be a WebSocket URL (wss:// or ws://)' + + - id: NODE_ADDRESS + target: + type: environment + name: NODE_ADDRESS + service: ciphernode + title: 'Node Address' + description: 'Public address for this node (must match the private key below if set).' + required: true + pattern: '^0x[a-fA-F0-9]{40}$' + patternErrorMessage: 'Must be a valid 20-byte hex address (0x...)' + + - id: PRIVATE_KEY + target: + type: environment + name: PRIVATE_KEY + service: ciphernode + title: 'Private Key' + description: 'Private key for this node. Must correspond to the Node Address above.' + secret: true + required: false + pattern: '^(0x[a-fA-F0-9]{64})?$' + + # Node settings + - id: NODE_ROLE + target: + type: environment + name: NODE_ROLE + service: ciphernode + title: 'Node Role' + default: 'ciphernode' + description: | + - **ciphernode**: Participate in threshold decryption + - **aggregator**: Coordinate operations + enum: + - ciphernode + - aggregator + required: false + + # Contracts + - id: ENCLAVE_CONTRACT + target: + type: environment + name: ENCLAVE_CONTRACT + service: ciphernode + title: 'Enclave Contract Address' + description: 'Address of the Enclave contract on the selected network.' + required: true + pattern: '^0x[a-fA-F0-9]{40}$' + patternErrorMessage: 'Must be a valid Ethereum address (0x...)' + + - id: CIPHERNODE_REGISTRY_CONTRACT + target: + type: environment + name: CIPHERNODE_REGISTRY_CONTRACT + service: ciphernode + title: 'Ciphernode Registry Contract' + description: 'Address of the CiphernodeRegistry contract.' + required: true + pattern: '^0x[a-fA-F0-9]{40}$' + patternErrorMessage: 'Must be a valid Ethereum address (0x...)' + + - id: BONDING_REGISTRY_CONTRACT + target: + type: environment + name: BONDING_REGISTRY_CONTRACT + service: ciphernode + title: 'Bonding Registry Contract' + description: 'Address of the BondingRegistry contract.' + required: true + pattern: '^0x[a-fA-F0-9]{40}$' + patternErrorMessage: 'Must be a valid Ethereum address (0x...)' + + - id: ENCLAVE_DEPLOY_BLOCK + target: + type: environment + name: ENCLAVE_DEPLOY_BLOCK + service: ciphernode + title: 'Enclave Deploy Block' + description: 'Block number where the Enclave contract was deployed.' + required: true + pattern: '^[0-9]+$' + patternErrorMessage: 'Must be a block number (integer).' + + - id: CIPHERNODE_REGISTRY_DEPLOY_BLOCK + target: + type: environment + name: CIPHERNODE_REGISTRY_DEPLOY_BLOCK + service: ciphernode + title: 'Ciphernode Registry Deploy Block' + description: 'Block number where the CiphernodeRegistry contract was deployed.' + required: true + pattern: '^[0-9]+$' + patternErrorMessage: 'Must be a block number (integer).' + + - id: BONDING_REGISTRY_DEPLOY_BLOCK + target: + type: environment + name: BONDING_REGISTRY_DEPLOY_BLOCK + service: ciphernode + title: 'Bonding Registry Deploy Block' + description: 'Block number where the BondingRegistry contract was deployed.' + required: true + pattern: '^[0-9]+$' + patternErrorMessage: 'Must be a block number (integer).' + + - id: PEERS + target: + type: environment + name: PEERS + service: ciphernode + title: 'Bootstrap Peers' + description: | + Comma-separated peer addresses, e.g.: + /dns4/cn1/udp/9091/quic-v1, /dns4/cn2/udp/9092/quic-v1 + Leave empty for auto-discovery. + required: false + + # Secrets + - id: ENCRYPTION_PASSWORD + target: + type: environment + name: ENCRYPTION_PASSWORD + service: ciphernode + title: 'Encryption Password' + description: 'Password for local encryption. Leave empty to auto-generate.' + secret: true + required: false + + - id: NETWORK_PRIVATE_KEY + target: + type: environment + name: NETWORK_PRIVATE_KEY + service: ciphernode + title: 'Network Private Key' + description: 'libp2p network key for consistent peer ID across restarts. Leave empty to auto-generate.' + secret: true + required: false + pattern: '^(0x[a-fA-F0-9]{64})?$' + + # Advanced + - id: LOG_LEVEL + target: + type: environment + name: LOG_LEVEL + service: ciphernode + title: 'Log Level' + description: 'Log level for the ciphernode.' + enum: + - info + - debug + - trace + required: false + + - id: EXTRA_OPTS + target: + type: environment + name: EXTRA_OPTS + service: ciphernode + title: 'Extra Options' + description: 'Additional CLI arguments passed to `enclave start`.' + required: false From 4e60ef00df50b337a2314b243a58131d1fc5c6eb Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 2 Dec 2025 01:50:19 +0500 Subject: [PATCH 2/3] feat: add release tags to ciphernode --- .github/workflows/ci.yml | 76 ++++++++++++++++------- .github/workflows/ec2-deployment.yml | 86 -------------------------- .github/workflows/releases.yml | 80 ++++++++++++++++++++++++- dappnode/Dockerfile | 4 +- dappnode/dappnode_package.json | 1 + docs/public/site.webmanifest | 34 +++++------ templates/default/client/index.html | 90 +++++++++++++++------------- 7 files changed, 203 insertions(+), 168 deletions(-) delete mode 100644 .github/workflows/ec2-deployment.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9328d3f9f..e7233d3b90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,10 @@ on: - main - dev env: - DOCKERFILE_PATH: crates/support/Dockerfile - IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/e3-support + SUPPORT_DOCKERFILE_PATH: crates/support/Dockerfile + CIPHERNODE_DOCKERFILE_PATH: crates/Dockerfile + SUPPORT_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/e3-support + CIPHERNODE_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/ciphernode HARDHAT_VAR_MNEMONIC: 'test test test test test test test test test test test junk' HARDHAT_VAR_INFURA_API_KEY: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' PRIVATE_KEY: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' @@ -143,44 +145,78 @@ jobs: image_tag: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v4 - - name: Generate version tag - id: version - run: | - echo "version=$(git rev-parse --short=9 HEAD)" >> $GITHUB_OUTPUT - name: Generate tags id: tags run: | - VERSION=$(git rev-parse --short=9 HEAD) - TAGS="${{ env.IMAGE_NAME }}:$VERSION" - if [ "${{ github.ref }}" = "refs/heads/main" ]; then - TAGS="$TAGS,${{ env.IMAGE_NAME }}:latest" + SHORT_SHA=$(git rev-parse --short=9 HEAD) + TAGS="${SUPPORT_IMAGE_NAME}:${SHORT_SHA}" + + if [ "${GITHUB_REF}" = "refs/heads/main" ]; then + TAGS="$TAGS,${SUPPORT_IMAGE_NAME}:main" fi + echo "tags=$TAGS" >> $GITHUB_OUTPUT - name: Set up BuildKit uses: docker/setup-buildx-action@v3 + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Build image uses: docker/build-push-action@v5 with: context: ./crates/support - file: ${{ env.DOCKERFILE_PATH }} - push: true + file: ${{ env.SUPPORT_DOCKERFILE_PATH }} + push: ${{ github.ref == 'refs/heads/main' }} tags: ${{ steps.tags.outputs.tags }} cache-from: | - type=gha,scope=cargo-registry - type=gha,scope=cargo-git - type=gha,scope=cargo-target - type=gha,scope=buildcache + type=gha,scope=e3-support cache-to: | - type=gha,mode=max,scope=cargo-registry - type=gha,mode=max,scope=cargo-git - type=gha,mode=max,scope=cargo-target - type=gha,mode=max,scope=buildcache + type=gha,mode=max,scope=e3-support + + build_ciphernode_image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate tags + id: tags + run: | + SHORT_SHA=$(git rev-parse --short=9 HEAD) + TAGS="${CIPHERNODE_IMAGE_NAME}:${SHORT_SHA}" + + if [ "${GITHUB_REF}" = "refs/heads/main" ]; then + TAGS="$TAGS,${CIPHERNODE_IMAGE_NAME}:main" + fi + + echo "tags=$TAGS" >> $GITHUB_OUTPUT + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + if: github.ref == 'refs/heads/main' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build ciphernode image + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ env.CIPHERNODE_DOCKERFILE_PATH }} + push: ${{ github.ref == 'refs/heads/main' }} + tags: ${{ steps.tags.outputs.tags }} + cache-from: | + type=gha,scope=ciphernode + cache-to: | + type=gha,mode=max,scope=ciphernode test_contracts: runs-on: 'ubuntu-latest' diff --git a/.github/workflows/ec2-deployment.yml b/.github/workflows/ec2-deployment.yml deleted file mode 100644 index cd2ed28d4e..0000000000 --- a/.github/workflows/ec2-deployment.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Build and Deploy Ciphernode -on: - push: - branches: - - dev - - main - paths: - - 'Cargo.*' - - 'crates/**' - - 'packages/enclave-contracts/contracts/**' - pull_request: - branches: - - dev - - main - paths: - - 'Cargo.*' - - 'crates/**' - - 'packages/enclave-contracts/contracts/**' - -env: - DOCKERFILE_PATH: crates/Dockerfile - IMAGE_NAME: ghcr.io/gnosisguild/ciphernode - -permissions: - contents: read - packages: write - -jobs: - build: - name: Build & Push Image - runs-on: ubuntu-latest - outputs: - image_tag: ${{ steps.version.outputs.version }} - steps: - - uses: actions/checkout@v3 - - - name: Generate version tag - id: version - run: echo "version=$(date +'%Y%m%d')-${GITHUB_SHA::8}" >> $GITHUB_OUTPUT - - - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build image - env: - IMAGE_TAG: ${{ steps.version.outputs.version }} - run: | - docker build -t $IMAGE_NAME:${{ steps.version.outputs.version }} -f $DOCKERFILE_PATH . - docker push $IMAGE_NAME:$IMAGE_TAG - - - name: Push to GHCR - if: github.ref == 'refs/heads/release' - env: - IMAGE_TAG: ${{ steps.version.outputs.version }} - run: | - docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:latest - docker push $IMAGE_NAME:latest - - deploy: - name: Deploy to Production - needs: build - runs-on: ubuntu-latest - environment: - name: production - if: github.ref == 'refs/heads/release' - - steps: - - name: Deploy to EC2 - uses: appleboy/ssh-action@v1.2.0 - with: - host: ${{ secrets.EC2_HOST }} - username: ${{ secrets.EC2_USERNAME }} - key: ${{ secrets.EC2_KEY }} - script: | - IMAGE_TAG="${{ needs.build.outputs.image_tag }}" - echo "Deploying version: $IMAGE_TAG" - docker pull $IMAGE_NAME:$IMAGE_TAG - - cd /home/ec2-user/enclave - git pull - - ./deploy/deploy.sh enclave $IMAGE_NAME:$IMAGE_TAG diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index 70e3230f72..2b2227cdb2 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -11,6 +11,10 @@ on: - 'v*.*.*-*' # Pre-release tags like v1.0.0-beta.1 env: + CIPHERNODE_DOCKERFILE_PATH: crates/Dockerfile + SUPPORT_DOCKERFILE_PATH: crates/support/Dockerfile + CIPHERNODE_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/ciphernode + SUPPORT_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/e3-support MNEMONIC: 'test test test test test test test test test test test junk' INFURA_API_KEY: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' ETHERSCAN_API_KEY: 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' @@ -67,6 +71,72 @@ jobs: echo "✅ All versions match: $VERSION" + build-ciphernode-image-release: + name: Build & Push ciphernode (release) + runs-on: ubuntu-latest + needs: validate-and-prepare + env: + CIPHERNODE_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/ciphernode + steps: + - uses: actions/checkout@v4 + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push ciphernode release image + uses: docker/build-push-action@v5 + with: + context: . + file: crates/Dockerfile + push: true + tags: | + ${{ env.CIPHERNODE_IMAGE_NAME }}:${{ needs.validate-and-prepare.outputs.version }} + ${{ env.CIPHERNODE_IMAGE_NAME }}:latest + cache-from: | + type=gha,scope=ciphernode + cache-to: | + type=gha,mode=max,scope=ciphernode + + build-e3-support-release: + name: Build & Push e3-support (release) + runs-on: ubuntu-latest + needs: validate-and-prepare + env: + SUPPORT_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/e3-support + steps: + - uses: actions/checkout@v4 + + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push e3-support release image + uses: docker/build-push-action@v5 + with: + context: ./crates/support + file: ${{ env.SUPPORT_DOCKERFILE_PATH }} + push: true + tags: | + ${{ env.SUPPORT_IMAGE_NAME }}:${{ needs.validate-and-prepare.outputs.version }} + ${{ env.SUPPORT_IMAGE_NAME }}:latest + cache-from: | + type=gha,scope=e3-support + cache-to: | + type=gha,mode=max,scope=e3-support + build-binaries: name: Build Binaries (${{ matrix.os_name }}-${{ matrix.arch }}) runs-on: ${{ matrix.os }} @@ -217,7 +287,15 @@ jobs: create-github-release: name: Create GitHub Release runs-on: ubuntu-latest - needs: [validate-and-prepare, build-binaries, publish-rust-crates, publish-npm-packages] + needs: + [ + validate-and-prepare, + build-ciphernode-image-release, + build-e3-support-release, + build-binaries, + publish-rust-crates, + publish-npm-packages, + ] if: always() && needs.validate-and-prepare.result == 'success' && needs.build-binaries.result == 'success' steps: - name: Checkout diff --git a/dappnode/Dockerfile b/dappnode/Dockerfile index f8274fe262..e5f3865f2f 100644 --- a/dappnode/Dockerfile +++ b/dappnode/Dockerfile @@ -1,8 +1,8 @@ # DAppNode Enclave Ciphernode Dockerfile # Uses official upstream image from GitHub Container Registry -# For local testing: use Dockerfile.local instead -FROM hmzakhalid/enclave-ciphernode:0.1.0 AS upstream +ARG UPSTREAM_VERSION +FROM ghcr.io/gnosisguild/ciphernode:${UPSTREAM_VERSION} AS upstream # Runtime image FROM debian:stable-slim diff --git a/dappnode/dappnode_package.json b/dappnode/dappnode_package.json index fad4e15863..426f623735 100644 --- a/dappnode/dappnode_package.json +++ b/dappnode/dappnode_package.json @@ -2,6 +2,7 @@ "name": "enclave-ciphernode.public.dappnode.eth", "version": "0.1.0", "upstreamVersion": "0.1.5", + "upstreamArg": "UPSTREAM_VERSION", "upstreamRepo": "gnosisguild/enclave", "shortDescription": "Enclave Ciphernode - Run a node for confidential computing", "description": "Run an Enclave ciphernode to participate in the E3 (Encrypted Execution Environments) network.", diff --git a/docs/public/site.webmanifest b/docs/public/site.webmanifest index a1553eb86b..161c642e0b 100644 --- a/docs/public/site.webmanifest +++ b/docs/public/site.webmanifest @@ -1,19 +1,19 @@ { - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-384x384.png", - "sizes": "384x384", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" } diff --git a/templates/default/client/index.html b/templates/default/client/index.html index e9dc495af7..b4ec575bc7 100644 --- a/templates/default/client/index.html +++ b/templates/default/client/index.html @@ -1,48 +1,54 @@ + + Enclave + + + + + + - - Enclave - - - - - - + + + + - - - - + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - - - - - -
- -
-
- - - - \ No newline at end of file + +
+ +
+
+ + + From 305857f2799c6ea71d59fdba1a9f44d4edd64809 Mon Sep 17 00:00:00 2001 From: Hamza Khalid Date: Tue, 2 Dec 2025 01:52:55 +0500 Subject: [PATCH 3/3] feat: add release tags to ciphernode --- .github/workflows/ci.yml | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7233d3b90..f75ae2c2d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,12 +178,12 @@ jobs: cache-to: | type=gha,mode=max,scope=e3-support - build_ciphernode_image: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + build_ciphernode_image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 - - name: Generate tags + - name: Generate tags id: tags run: | SHORT_SHA=$(git rev-parse --short=9 HEAD) @@ -195,28 +195,28 @@ jobs: echo "tags=$TAGS" >> $GITHUB_OUTPUT - - name: Set up Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to GitHub Container Registry - if: github.ref == 'refs/heads/main' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build ciphernode image - uses: docker/build-push-action@v5 - with: - context: . - file: ${{ env.CIPHERNODE_DOCKERFILE_PATH }} - push: ${{ github.ref == 'refs/heads/main' }} - tags: ${{ steps.tags.outputs.tags }} - cache-from: | - type=gha,scope=ciphernode - cache-to: | - type=gha,mode=max,scope=ciphernode + - name: Set up Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + if: github.ref == 'refs/heads/main' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build ciphernode image + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ env.CIPHERNODE_DOCKERFILE_PATH }} + push: ${{ github.ref == 'refs/heads/main' }} + tags: ${{ steps.tags.outputs.tags }} + cache-from: | + type=gha,scope=ciphernode + cache-to: | + type=gha,mode=max,scope=ciphernode test_contracts: runs-on: 'ubuntu-latest'