diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 15c9255e..2a1a5338 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -175,7 +175,6 @@ jobs: name: Runtime Upgrade (on-chain) runs-on: ubuntu-latest needs: [metadata, build] - environment: ${{ needs.metadata.outputs.environment }} # Deshabilitado hasta tener nodo testnet estable — activar con workflow_dispatch if: github.event.inputs.deploy_runtime == 'true' steps: @@ -215,7 +214,6 @@ jobs: name: Rolling Node Binary Update runs-on: ubuntu-latest needs: [metadata, build, deploy-runtime] - environment: ${{ needs.metadata.outputs.environment }} # Solo si explícitamente solicitado — los upgrades de runtime no lo necesitan if: github.event.inputs.rolling_update == 'true' steps: diff --git a/docker/testnet/.env.example b/docker/testnet/.env.example new file mode 100644 index 00000000..bf7e9280 --- /dev/null +++ b/docker/testnet/.env.example @@ -0,0 +1 @@ +VALIDATOR_NODE_KEY= diff --git a/docker/testnet/README.md b/docker/testnet/README.md index df9e2ea0..1eb88db1 100644 --- a/docker/testnet/README.md +++ b/docker/testnet/README.md @@ -1,20 +1,68 @@ # Running a Validator on Orbinum Testnet -This guide walks through everything needed to join the Orbinum testnet as a validator: server setup, key generation, node startup, and requesting approval to produce blocks. +This guide covers everything needed to join the Orbinum testnet as a validator: server setup, key generation, node startup, on-chain registration, and keeping your node up to date. -**Flow at a glance:** +--- + +## Table of Contents + +- [Running a Validator on Orbinum Testnet](#running-a-validator-on-orbinum-testnet) + - [Table of Contents](#table-of-contents) + - [Overview](#overview) + - [Part 1 — Server Setup](#part-1--server-setup) + - [1. Hardware Requirements](#1-hardware-requirements) + - [2. Firewall Ports](#2-firewall-ports) + - [Part 2 — Run the Node](#part-2--run-the-node) + - [Option A: Docker (recommended)](#option-a-docker-recommended) + - [A.1 Install Docker](#a1-install-docker) + - [A.2 Authenticate with GHCR](#a2-authenticate-with-ghcr) + - [A.3 Configure the node key](#a3-configure-the-node-key) + - [A.4 Start the node](#a4-start-the-node) + - [A.5 Automatic updates (Watchtower)](#a5-automatic-updates-watchtower) + - [Option B: systemd (binary)](#option-b-systemd-binary) + - [B.1 Install the binary](#b1-install-the-binary) + - [B.2 Configure the node key](#b2-configure-the-node-key) + - [B.3 Create the systemd service](#b3-create-the-systemd-service) + - [Part 3 — Key Setup](#part-3--key-setup) + - [3. Generate Session Keys](#3-generate-session-keys) + - [Option A — Automated (recommended)](#option-a--automated-recommended) + - [Option B — Manual](#option-b--manual) + - [What to record](#what-to-record) + - [4. Insert Keys into Keystore](#4-insert-keys-into-keystore) + - [5. Get Your EVM Relay Address](#5-get-your-evm-relay-address) + - [Part 4 — On-Chain Registration](#part-4--on-chain-registration) + - [6. Register Session Keys On-Chain](#6-register-session-keys-on-chain) + - [7. Submit Validator Registration](#7-submit-validator-registration) + - [8. Request Approval](#8-request-approval) + - [9. Wait for the Next Session](#9-wait-for-the-next-session) + - [Part 5 — Operations](#part-5--operations) + - [Keeping the Node Updated](#keeping-the-node-updated) + - [Docker — automatic (Watchtower)](#docker--automatic-watchtower) + - [systemd — manual update](#systemd--manual-update) + - [systemd — automatic updates with cron](#systemd--automatic-updates-with-cron) + - [Bond and Deregistration](#bond-and-deregistration) + - [Useful Commands](#useful-commands) + - [Docker](#docker) + - [systemd](#systemd) + - [Troubleshooting](#troubleshooting) + +--- + +## Overview + +**Registration flow at a glance:** ``` -1. Prepare server and install Docker -2. Generate your two session keys (one mnemonic) -3. Start the node — sync with the network -4. Insert the session keys into the running node's keystore (local RPC) -5. Restart the node — it will derive and log your EVM relay address automatically -6. Share the logged EVM address with the Orbinum team — they register it via sudo +1. Prepare server +2. Run the node and sync with the network +3. Generate session keys (Aura + GRANDPA) +4. Insert session keys into the local keystore +5. Restart node → EVM relay address is derived and logged automatically +6. Share EVM address with Orbinum team → they register it via sudo 7. Register session keys on-chain → session.setKeys 8. Submit validator registration (locks 1 000 ORB bond) → validatorSet.registerValidator -9. Contact the Orbinum team — governance approves your registration -10. Wait for the next session (~1 h) — you are now an active validator +9. Contact the Orbinum team → governance approves your registration +10. Wait for the next session (~1 h) → you are now an active validator ``` > **Steps 7–8 must be completed in order.** `registerValidator` will be rejected @@ -23,7 +71,9 @@ This guide walks through everything needed to join the Orbinum testnet as a vali --- -## 1. Hardware Requirements +## Part 1 — Server Setup + +### 1. Hardware Requirements | Resource | Minimum | | --------- | ----------------------------- | @@ -35,122 +85,265 @@ This guide walks through everything needed to join the Orbinum testnet as a vali > Recommended provider: **Hetzner CCX13** (~$18/mo). Shared-CPU VPS instances are not recommended — validators run ZK proof verification which is CPU-intensive. +### 2. Firewall Ports + +```bash +sudo ufw allow 30333/tcp # P2P — must be publicly reachable +sudo ufw allow 9615/tcp # Prometheus metrics (optional) +sudo ufw enable +``` + +> Do **not** open port `9944` (RPC) on a validator. The RPC port is only used locally during key insertion. + +--- + +## Part 2 — Run the Node + +Choose one of the two options below. Docker is recommended for most validators. + --- -## 2. Install Docker +### Option A: Docker (recommended) + +The `docker-compose.yml` includes the node and **Watchtower**, which automatically updates your container whenever a new testnet release is published. + +#### A.1 Install Docker ```bash curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER -newgrp docker # apply group without logging out +newgrp docker sudo apt-get install -y docker-compose-plugin -docker compose version # should print v2.x +docker compose version # should print v2.x ``` ---- +#### A.2 Authenticate with GHCR -## 3. Open Firewall Ports +The Orbinum node image is hosted on GitHub Container Registry (private). You need to authenticate once: ```bash -sudo ufw allow 30333/tcp # P2P — must be publicly reachable -sudo ufw allow 9615/tcp # Prometheus metrics (optional) -sudo ufw enable +# Create a GitHub Personal Access Token with read:packages scope at: +# https://github.com/settings/tokens/new?scopes=read:packages + +export GITHUB_TOKEN= +echo $GITHUB_TOKEN | docker login ghcr.io -u --password-stdin ``` -Do **not** open port `9944` (RPC) on a validator. The RPC port is only used locally during key insertion. +> Credentials are saved to `~/.docker/config.json`. Watchtower uses them automatically for future pulls. ---- +#### A.3 Configure the node key -## 4. Get the Node +Each validator needs a stable **node key** — a 32-byte Ed25519 private key that determines the node's Peer ID on the libp2p network. Without it, the Peer ID changes on every restart and other nodes cannot reliably locate you. ```bash -git clone https://github.com/orbinum/node.git -cd node/docker/testnet -docker compose build # compiles the node from source (~10-20 min first time) +# Generate a random node key +openssl rand -hex 32 +# Example output: 847eff06b1f1b8a10b1a8b3b03a0dc90fe4e4a7c86f5e6063a88382f545f7704 ``` ---- +Save it in a `.env` file in the same directory as `docker-compose.yml`: -## 5. Generate Your Session Keys +```bash +# node/docker/testnet/.env +VALIDATOR_NODE_KEY= +``` -Each validator has **two session keys**, both derived from a single mnemonic: +> **Security:** `.env` is in `.gitignore` — never commit it. Store the key in a password manager as a backup. Whoever holds this key can impersonate your node on the network. -| Key | Scheme | Key type | Role | -| ----------- | ------- | -------- | ------------------------------------------ | -| **Aura** | Sr25519 | `aura` | Block production (your validator identity) | -| **GRANDPA** | Ed25519 | `gran` | Block finalization | +Docker Compose reads `.env` automatically. The key is passed to the node via `--node-key ${VALIDATOR_NODE_KEY}`. -> **EVM relay key:** The node derives your EVM relay address automatically from the Aura key at startup — you do not need to generate or insert a separate EVM key. +Your **Peer ID** is derived from this key and printed in the logs on startup: -### Option A — Automated (recommended) +``` +Local node identity is: 12D3KooWxxxxx... +``` + +#### A.4 Start the node ```bash -cd scripts/validator-keys -./generate-validator-keys.sh +git clone https://github.com/orbinum/node.git +cd node/docker/testnet + +# Generate and save your node key (see A.3 above) +openssl rand -hex 32 # copy the output +echo "VALIDATOR_NODE_KEY=" > .env + +docker compose pull # download pre-built image (~1-2 min) +docker compose up -d # start validator + watchtower +docker compose logs -f validator-1 ``` -Output is saved to `keys/validator-1/`: -- `aura.json` — Sr25519 key -- `grandpa.json` — Ed25519 key -- `summary.txt` — human-readable summary of all values +Wait until you see `Idle` in the logs before proceeding: -### Option B — Manual +``` +2026-06-02 12:00:00 Idle (3 peers), best: #1234 ... +``` + +Get your **Peer ID** — you will need it when requesting approval: ```bash -# Step 1: generate Aura key — this produces your mnemonic -docker run --rm orbinum-node:latest key generate --scheme Sr25519 +docker compose logs validator-1 | grep "Local node identity" +# -> Local node identity is: 12D3KooWxxxxx... ``` -Save the **Secret phrase**. You will use it for both keys. +#### A.5 Automatic updates (Watchtower) + +Watchtower monitors GHCR and restarts your container automatically when a new `testnet-latest` image is published — no manual action required. + +``` +Orbinum team publishes v0.1.1-rc.1 + ↓ +ghcr.io/orbinum/node:testnet-latest is updated + ↓ +Watchtower detects change (checks every 5 min) + ↓ +docker pull + restart validator-1 (~5s downtime) +``` + +Watchtower starts automatically with `docker compose up -d`. To check update history: ```bash -# Step 2: derive GRANDPA from the same mnemonic -docker run --rm orbinum-node:latest key inspect --scheme Ed25519 "" +docker compose logs watchtower ``` -### What to record +--- -| Value | Where to find it | Example | -| ---------------------- | -------------------------- | ---------------------- | -| **Mnemonic** | `key generate` output | `abandon ... about` | -| **Aura public key** | `aura.json → publicKey` | `0x72d4f4...` (64 hex) | -| **GRANDPA public key** | `grandpa.json → publicKey` | `0x96749e...` (64 hex) | +### Option B: systemd (binary) -> **Security:** Store the mnemonic in a password manager (Bitwarden, 1Password). Never commit it to the repository. The `keys/` directory is in `.gitignore`. +Use this if you prefer to run the binary directly without Docker. ---- +#### B.1 Install the binary + +```bash +# Replace with the current release version +VERSION=v0.1.0-rc.1 +curl -L "https://github.com/orbinum/node/releases/download/${VERSION}/orbinum-node-linux-x86_64-${VERSION}" \ + -o /usr/local/bin/orbinum-node +chmod +x /usr/local/bin/orbinum-node + +# Create system user and data directory +useradd -m -u 1001 -U -s /bin/sh orbinum +mkdir -p /var/lib/orbinum /etc/orbinum +chown orbinum:orbinum /var/lib/orbinum + +# Copy the chain spec +cp /path/to/node/docker/testnet/testnet-spec.json /etc/orbinum/testnet-spec.json +``` -## 6. Start the Node +#### B.2 Configure the node key + +Same reasoning as Docker (see [A.3](#a3-configure-the-node-key)). Generate a key and store it in a file readable only by the `orbinum` system user: ```bash -cd docker/testnet -docker compose up -d -docker compose logs -f validator-1 +# Generate the key and save it +openssl rand -hex 32 | sudo tee /etc/orbinum/node-key > /dev/null +sudo chmod 600 /etc/orbinum/node-key +sudo chown orbinum:orbinum /etc/orbinum/node-key ``` -The node will start syncing. Wait until you see `Idle` in the logs before proceeding: +> **Security:** Back up `/etc/orbinum/node-key` in a password manager. Never commit it or share it. If you lose it, your Peer ID changes and you must update the chain spec bootNodes entry. + +#### B.3 Create the systemd service + +Create `/etc/systemd/system/orbinum-node.service`: + +```ini +[Unit] +Description=Orbinum Node +After=network.target +Wants=network.target + +[Service] +User=orbinum +Group=orbinum +ExecStart=/usr/local/bin/orbinum-node \ + --chain /etc/orbinum/testnet-spec.json \ + --name "Orbinum-Validator-1" \ + --base-path /var/lib/orbinum \ + --port 30333 \ + --validator \ + --node-key-file /etc/orbinum/node-key \ + --no-mdns \ + --no-private-ipv4 \ + --prometheus-external \ + --prometheus-port 9615 \ + --log info +Restart=always +RestartSec=10 +KillSignal=SIGINT +TimeoutStopSec=300 + +[Install] +WantedBy=multi-user.target +``` +```bash +systemctl daemon-reload +systemctl enable orbinum-node +systemctl start orbinum-node +journalctl -u orbinum-node -f ``` -2026-06-02 12:00:00 Idle (3 peers), best: #1234 ... + +Wait until you see `Idle` in the logs before proceeding. + +--- + +## Part 3 — Key Setup + +### 3. Generate Session Keys + +Each validator needs **two session keys**, both derived from a single mnemonic: + +| Key | Scheme | Key type | Role | +| ----------- | ------- | -------- | ------------------ | +| **Aura** | Sr25519 | `aura` | Block production | +| **GRANDPA** | Ed25519 | `gran` | Block finalization | + +> **EVM relay key:** The node derives your EVM relay address automatically from the Aura key — you do not generate or insert a separate EVM key. + +#### Option A — Automated (recommended) + +```bash +cd scripts/validator-keys +./generate-validator-keys.sh ``` -Get your **Peer ID** — you will need it when requesting approval: +Output is saved to `keys/validator-1/`: +- `aura.json` — Sr25519 key +- `grandpa.json` — Ed25519 key +- `summary.txt` — human-readable summary + +#### Option B — Manual ```bash -docker compose logs validator-1 | grep "Local node identity" -# -> Local node identity is: 12D3KooWxxxxx... +# Generate Aura key — save the Secret phrase shown in the output +docker run --rm ghcr.io/orbinum/node:testnet-latest key generate --scheme Sr25519 + +# Derive GRANDPA from the same mnemonic +docker run --rm ghcr.io/orbinum/node:testnet-latest key inspect --scheme Ed25519 "" ``` +#### What to record + +| Value | Where to find it | +| ---------------------- | -------------------------- | +| **Mnemonic** | `key generate` output | +| **Aura public key** | `aura.json → publicKey` | +| **GRANDPA public key** | `grandpa.json → publicKey` | + +> **Security:** Store the mnemonic in a password manager (Bitwarden, 1Password). Never commit it to the repository. The `keys/` directory is in `.gitignore`. + --- -## 7. Insert Session Keys into Keystore +### 4. Insert Keys into Keystore This writes the keys into the **node's local keystore** via RPC. These are local calls — not blockchain transactions — and require no balance. +The node must be running before you proceed. + ```bash -# Replace , , -# with the values recorded in Step 5. +# Replace , , with your values # Aura (Sr25519) curl -s -H "Content-Type: application/json" \ @@ -163,26 +356,28 @@ curl -s -H "Content-Type: application/json" \ http://localhost:9944 ``` -Or use the script: +Each call returns `{"result":null}` on success. Or use the script: ```bash cd scripts/validator-keys ./insert-session-keys.sh --validator 1 --rpc http://localhost:9944 ``` -Each call returns `{"result":null}` on success. - --- -## 8. Restart the Node — EVM Address Is Derived Automatically +### 5. Get Your EVM Relay Address After inserting the Aura key, restart the node: ```bash +# Docker docker compose restart validator-1 + +# systemd +systemctl restart orbinum-node ``` -At block #1 the node reads the Aura key from the keystore, derives the corresponding EVM relay address, and prints a log box if not yet registered: +The node reads the Aura key from the keystore, derives the EVM relay address, and prints it in the logs: ``` ╔══════════════════════════════════════════════════╗ @@ -195,15 +390,15 @@ At block #1 the node reads the Aura key from the keystore, derives the correspon ╚══════════════════════════════════════════════════╝ ``` -**Copy both values from the log** and include them in your approval request (Step 9). The Orbinum team will register the EVM address on your behalf via sudo — you do not call any extrinsic for this step. +**Copy both values** — you will need them for the approval request in Step 8. -> After this step, continue with the **on-chain** steps (9 → 10 → 11) in order. +The Orbinum team registers the EVM address on your behalf via sudo — you do not call any extrinsic for this step. --- -## 9. Register Session Keys On-Chain +## Part 4 — On-Chain Registration -This is an on-chain transaction — **not** the same as inserting keys into the keystore in Step 7. +### 6. Register Session Keys On-Chain First, get the combined session key from the node: @@ -214,9 +409,7 @@ curl -s -H "Content-Type: application/json" \ # Returns: {"result":"0x"} ``` -Or if you used the script, it was saved automatically to `keys/validator-1/session_key.txt`. - -Now submit the on-chain transaction via [Polkadot.js Apps](https://polkadot.js.org/apps/): +Then submit the on-chain transaction via [Polkadot.js Apps](https://polkadot.js.org/apps/): ``` Developer → Extrinsics @@ -231,11 +424,11 @@ This links your node's session keys to your account on-chain. --- -## 10. Submit Validator Registration +### 7. Submit Validator Registration -This locks **1 000 ORB** as a bond and places your account in the **pending** queue. Your account must have > 1 001 ORB free balance (1 000 for the bond + fees buffer). +This locks **1 000 ORB** as a bond and places your account in the **pending** queue. Your account must have > 1 001 ORB free balance. -> **Prerequisites enforced on-chain:** If session keys (Step 8) or EVM relay address (Step 9) are not registered, this call will fail with `NoSessionKeys` or `NoRelayer`. +> **Prerequisites enforced on-chain:** If session keys (Step 6) or EVM relay address (Step 5) are not registered, this call will fail with `NoSessionKeys` or `NoRelayer`. Via [Polkadot.js Apps](https://polkadot.js.org/apps/): @@ -250,16 +443,12 @@ On success, a `ValidatorRegistrationRequested` event is emitted and your bond is --- -## 11. Request Approval - -Validators are permissioned on Orbinum Testnet. Governance (sudo) must: -1. Register your EVM relay address (`relayer → registerRelayer`) -2. Approve your validator registration (`validatorSet → approveValidator`) +### 8. Request Approval -Contact the Orbinum team on **Discord** with: +Validators are permissioned on Orbinum Testnet. Contact the Orbinum team on **Discord** with: -- Your **Substrate AccountId** (from the log box in Step 8) -- Your **EVM relay address** (from the log box in Step 8, `0x...` 40 hex chars) +- Your **Substrate AccountId** (from the log box in Step 5) +- Your **EVM relay address** (from the log box in Step 5, `0x...` 40 hex chars) - Your **server's public IP** and **Peer ID** (`12D3KooW...`) - Confirmation that `registerValidator()` was called and `ValidatorRegistrationRequested` was emitted @@ -269,9 +458,7 @@ The team will execute on-chain: 2. validatorSet → approveValidator(who) ← moves you to the active set ``` -This emits `ValidatorApproved`. Your bond remains locked as long as you are an active validator. - -You can verify your status at any time: +You can verify your status at any time via Polkadot.js Apps: ``` Developer → Chain state → validatorSet → approvedValidators() @@ -280,7 +467,7 @@ Developer → Chain state → validatorSet → pendingValidators() --- -## 12. Wait for the Next Session +### 9. Wait for the Next Session Validator set changes take effect at the **next session boundary**. Sessions on Orbinum Testnet are **600 blocks** — approximately 1 hour at 6 seconds per block. @@ -293,7 +480,69 @@ Idle (5 peers), best: #1802 ... --- -## Bond and Deregistration +## Part 5 — Operations + +### Keeping the Node Updated + +The Orbinum team publishes new testnet releases periodically. Your node needs to stay on the latest version. + +#### Docker — automatic (Watchtower) + +If you are running with Docker, **no action is required**. Watchtower checks GHCR every 5 minutes and restarts the container automatically when `testnet-latest` is updated. + +To force an immediate update without waiting: + +```bash +docker compose pull && docker compose up -d +``` + +#### systemd — manual update + +```bash +VERSION=v0.1.1-rc.1 # replace with the new version +systemctl stop orbinum-node +curl -L "https://github.com/orbinum/node/releases/download/${VERSION}/orbinum-node-linux-x86_64-${VERSION}" \ + -o /usr/local/bin/orbinum-node +chmod +x /usr/local/bin/orbinum-node +systemctl start orbinum-node +journalctl -u orbinum-node -f +``` + +Downtime is ~5-10 seconds. If you operate multiple validators, update **one at a time** — never take down more than 1/3 of the active set simultaneously. + +#### systemd — automatic updates with cron + +Save the following script as `/usr/local/bin/orbinum-update.sh`: + +```bash +#!/usr/bin/env bash +# Checks for new testnet releases and updates the node automatically +LATEST=$(curl -s https://api.github.com/repos/orbinum/node/releases \ + | grep '"tag_name"' | head -1 | cut -d'"' -f4) +CURRENT=$(/usr/local/bin/orbinum-node --version 2>&1 | grep -oP '\d+\.\d+\.\d+.*' | head -1) + +if [[ -n "$LATEST" && "$LATEST" != *"$CURRENT"* ]]; then + echo "$(date): Updating to $LATEST..." + systemctl stop orbinum-node + curl -L "https://github.com/orbinum/node/releases/download/${LATEST}/orbinum-node-linux-x86_64-${LATEST}" \ + -o /usr/local/bin/orbinum-node + chmod +x /usr/local/bin/orbinum-node + systemctl start orbinum-node + echo "$(date): Updated to $LATEST" +fi +``` + +```bash +chmod +x /usr/local/bin/orbinum-update.sh + +# Check every 10 minutes +echo "*/10 * * * * root /usr/local/bin/orbinum-update.sh >> /var/log/orbinum-update.log 2>&1" \ + > /etc/cron.d/orbinum-update +``` + +--- + +### Bond and Deregistration Your **1 000 ORB bond** remains locked while you are in the pending queue or active validator set. @@ -312,28 +561,53 @@ If you are still in the **pending** queue (not yet approved), you can also call --- -## Useful Commands +### Useful Commands + +#### Docker ```bash -# View logs +# View validator logs docker compose logs -f validator-1 -# Stop the node +# View Watchtower logs (check when updates were applied) +docker compose logs -f watchtower + +# Stop everything docker compose down -# Restart +# Restart validator only docker compose restart validator-1 -# Full reset — deletes all chain data (use only for a fresh start) +# Force update now (without waiting for Watchtower) +docker compose pull && docker compose up -d + +# Full reset — deletes all chain data docker compose down -v # Resource usage docker stats orbinum-validator-1 ``` +#### systemd + +```bash +# View logs +journalctl -u orbinum-node -f + +# Restart +systemctl restart orbinum-node + +# Stop / Start +systemctl stop orbinum-node +systemctl start orbinum-node + +# Check update log +tail -f /var/log/orbinum-update.log +``` + --- -## Troubleshooting +### Troubleshooting **Node has 0 peers after several minutes** - Confirm port `30333` is open and publicly reachable: `nc -zv 30333` @@ -344,26 +618,18 @@ docker stats orbinum-validator-1 - Port `9944` is not exposed publicly; call from the same machine: `http://localhost:9944` **Node is not producing blocks after approval** -- Verify all three keys are inserted: restart and check logs for `Loaded session key` -- The validator set update takes effect at the next session boundary (~30 min after approval) +- Verify all keys are inserted: restart and check logs for `Loaded session key` +- The validator set update takes effect at the next session boundary (~1 h after approval) - Confirm your AccountId is in `validatorSet → approvedValidators()` **`registerValidator` fails with `NoRelayer`** - Your EVM relay address has not been registered yet by the Orbinum team -- Share the values from the log box (Step 8) with the team and wait for confirmation +- Share the values from the log box (Step 5) with the team and wait for confirmation **`registerValidator` fails with `NoSessionKeys`** -- Verify that `session.setKeys` was called on-chain (Step 9) +- Verify that `session.setKeys` was called on-chain (Step 6) - Confirm the combined key returned by `author_rotateKeys` was used correctly ---- - -## File Reference - -| File | Purpose | -| ------------------------ | ---------------------------------------------- | -| `Dockerfile` | Multi-stage build — shared by all node types | -| `docker-compose.yml` | Validator node configuration | -| `docker-compose.rpc.yml` | Public RPC node configuration | -| `testnet-spec.json` | Raw chain spec used by all nodes | -| `rpc-node.md` | Guide for running a public RPC node with Nginx | +**Watchtower is not updating the container** +- Confirm GHCR login is still valid: `docker login ghcr.io` +- Check Watchtower logs: `docker compose logs watchtower` diff --git a/docker/testnet/docker-compose.yml b/docker/testnet/docker-compose.yml index c1825819..8e77f828 100644 --- a/docker/testnet/docker-compose.yml +++ b/docker/testnet/docker-compose.yml @@ -1,6 +1,7 @@ services: validator-1: image: ${ORBINUM_IMAGE:-ghcr.io/orbinum/node:testnet-latest} + platform: linux/amd64 container_name: orbinum-validator-1 command: > --chain /chain-specs/testnet-spec.json @@ -8,19 +9,43 @@ services: --base-path /data --port 30333 --validator + --node-key ${VALIDATOR_NODE_KEY} --no-mdns --no-private-ipv4 --prometheus-external --prometheus-port 9615 --log info + volumes: + - ./testnet-spec.json:/chain-specs/testnet-spec.json:ro + - validator-1-data:/data ports: - "30333:30333" # P2P — must be publicly reachable restart: unless-stopped + labels: + com.centurylinklabs.watchtower.enable: "true" logging: driver: "json-file" options: max-size: "100m" max-file: "3" + watchtower: + image: containrrr/watchtower + container_name: orbinum-watchtower + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + environment: + # Check GHCR every 5 minutes + WATCHTOWER_POLL_INTERVAL: "300" + # Only update containers managed by this compose (via label) + WATCHTOWER_LABEL_ENABLE: "true" + # Wait for the new container to be healthy before removing the old one + WATCHTOWER_ROLLING_RESTART: "true" + # Log level + WATCHTOWER_LOG_LEVEL: "info" + labels: + com.centurylinklabs.watchtower.enable: "false" # watchtower does not update itself + volumes: validator-1-data: diff --git a/docker/testnet/testnet-spec.json b/docker/testnet/testnet-spec.json index 53a8dd29..9a3f2eeb 100644 --- a/docker/testnet/testnet-spec.json +++ b/docker/testnet/testnet-spec.json @@ -2,7 +2,11 @@ "name": "Orbinum Testnet", "id": "orbinum_testnet", "chainType": "Live", - "bootNodes": [], + "bootNodes": [ + "/dns/testnet-bootnode-1.orbinum.io/tcp/30333/p2p/12D3KooWBzqb1AFLQJd4NooU7q6dSsYBFL85A8RPsJDLesfxHvbW", + "/dns/testnet-bootnode-2.orbinum.io/tcp/30333/p2p/12D3KooWKiLEh2Z8XZYGejL5ZMR6rwEdZHPTpVDW3nsXfSW8paLt", + "/dns/testnet-bootnode-3.orbinum.io/tcp/30333/p2p/12D3KooWDyUCkm5GoxeZ2pz582tUgQXv1QUcLL7KDzqYcgf4QezU" + ], "telemetryEndpoints": [ [ "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F", diff --git a/docs/release-signing.md b/docs/release-signing.md index c6d658d9..6996432c 100644 --- a/docs/release-signing.md +++ b/docs/release-signing.md @@ -9,7 +9,7 @@ All Orbinum Node releases are signed with GPG using an Ed25519 key. This guarant ``` Maintainer signs tag locally (GPG Ed25519) ↓ -git push origin vX.Y.Z +git push origin vX.Y.Z[-rc.N] ↓ GitHub Actions: Verify GPG signature ↓ (fails → pipeline blocked) @@ -17,6 +17,8 @@ Build binary + WASM ↓ Publish Docker image (ghcr.io/orbinum/node) GitHub Release (binary + WASM + checksums) + ↓ +Runtime upgrade on-chain ← manual via workflow_dispatch ``` The CI pipeline **refuses to build or publish anything** if the tag signature is missing or invalid. @@ -48,6 +50,8 @@ The **public key** is stored as a GitHub Actions secret (`RELEASE_GPG_PUBLIC_KEY Stable releases update `latest`. Pre-releases (suffix `-rc`, `-alpha`, `-beta`, `-pre`) only update `testnet-latest`. +> **Current strategy**: Orbinum is in testnet phase. All releases use pre-release tags (`-rc.N`). Stable tags (`v1.0.0`) are reserved for mainnet launch. + --- ## Creating a release (maintainers) @@ -68,30 +72,42 @@ echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf ``` -### Publishing a release +### Publishing a testnet release (pre-release) ```bash # 1. Ensure main is clean and up to date git checkout main && git pull -# 2. Create signed tag -git tag -s v1.0.0 -m "Release v1.0.0" +# 2. Create signed pre-release tag +git tag -s v1.0.0-rc.1 -m "Testnet release candidate 1" # 3. Verify the signature locally before pushing -git verify-tag v1.0.0 +git verify-tag v1.0.0-rc.1 -# 4. Push — this triggers the full CI/CD pipeline -git push origin v1.0.0 +# 4. Push — triggers CI: build + Docker testnet-latest + GitHub Release +git push origin v1.0.0-rc.1 ``` -### Publishing a pre-release (testnet) +### Publishing a mainnet release (stable — reserved for mainnet launch) ```bash -git tag -s v1.0.0-rc.1 -m "Testnet release candidate 1" -git verify-tag v1.0.0-rc.1 -git push origin v1.0.0-rc.1 +git tag -s v1.0.0 -m "Mainnet launch" +git verify-tag v1.0.0 +git push origin v1.0.0 +# → publishes ghcr.io/orbinum/node:latest +``` + +### Triggering a runtime upgrade on-chain (manual) + +After a release is published, the on-chain runtime upgrade must be triggered manually: + +``` +GitHub → Actions → Release → Run workflow + deploy_runtime: true ``` +This requires `TESTNET_RPC_WS` and `TESTNET_SUDO_SEED` secrets to be configured. + ### Recreating a tag (if needed) ```bash @@ -108,13 +124,9 @@ git push origin v1.0.0 Anyone can verify that a tag was signed by the Orbinum release key: ```bash -# 1. Import the Orbinum release public key +# 1. Import the Orbinum release public key from the keyserver gpg --keyserver keys.openpgp.org --recv-keys B82CFAF08B9338D5 -# Or import manually from the repo -curl -s https://raw.githubusercontent.com/orbinum/node/main/docs/release-signing.md \ - | grep -A 1 "Public key" # (see below) - # 2. Verify the tag git fetch --tags git verify-tag v1.0.0