Upgrade a Node
Upgrade native or Docker nodes safely with manual and agentic procedures, rollback, and validator identity gates.
Upgrade a ROKO node
The current reviewed node release is v1.0.21, built from source revision `8db4c6d7a98057a66b4e67321d561943fd2456d8`. Use the immutable `https://downloads.roko.network/releases/v1.0.21/` path or an architecture-specific GHCR digest. Do not deploy a moving `latest` tag directly to a validator.
Upgrade validators one at a time. Full, archive, sentry, and observer nodes may be upgraded in parallel only while independent RPC, boot, and time-mesh capacity remains online.
This procedure replaces software only. It must not replace the chain spec, base path, node identity, session keys, temporal key, or service credentials.
Preflight
Record the following before stopping anything:
- release tag, source revision, and artifact SHA-256 or image digest;
- installed unit and current executable or image digest;
- genesis hash, finalized head, peer count, sync state, and node role;
- authority index and PTP² mesh state for a validator; and
- the expected stash and all seven public session keys from the approved
enrollment manifest for a validator.
A healthy unit, correct genesis, peers, and `isSyncing: false` prove that a host is a synchronized peer. They do not prove that it owns an active authority slot. Confirm finality is advancing and the remaining authorities can retain quorum. Stop if the network is already degraded.
The examples use `roko-node.service`, `/usr/local/bin/roko-node`, and loopback RPC on port 9944. Discover the real values from the installed unit instead of guessing them.
ROKO_RELEASE=v1.0.21
ROKO_SERVICE=roko-node.service
ROKO_RPC=http://127.0.0.1:9944
systemctl show "$ROKO_SERVICE" -p FragmentPath -p ExecStart -p ActiveState
chronyc tracking
chronyc sources -v
curl --fail --silent --show-error "$ROKO_RPC" \
-H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"system_health","params":[]}'
curl --fail --silent --show-error "$ROKO_RPC" \
-H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"chain_getFinalizedHead","params":[]}'
curl --fail --silent --show-error "$ROKO_RPC" \
-H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"temporal_getMeshState","params":[]}'
Manual native-binary upgrade
Download the architecture-matched bundle and checksum manifest into a new private staging directory:
ROKO_RELEASE_BASE="https://downloads.roko.network/releases/${ROKO_RELEASE}"
case "$(uname -m)" in
x86_64) ROKO_ARCH=amd64 ;;
aarch64|arm64) ROKO_ARCH=arm64 ;;
*) echo "Unsupported architecture" >&2; exit 1 ;;
esac
ROKO_BUNDLE="roko-node-testnet-linux-${ROKO_ARCH}.tar.gz"
mkdir -m 0700 "roko-upgrade-${ROKO_RELEASE}"
cd "roko-upgrade-${ROKO_RELEASE}"
curl --fail --location --remote-name "${ROKO_RELEASE_BASE}/${ROKO_BUNDLE}"
curl --fail --location --remote-name "${ROKO_RELEASE_BASE}/SHA256SUMS"
curl --fail --location --remote-name "${ROKO_RELEASE_BASE}/BUILD-METADATA.json"
sha256sum --check --ignore-missing SHA256SUMS
jq -e --arg release "$ROKO_RELEASE" \
'.release_id == $release and .source_revision == "8db4c6d7a98057a66b4e67321d561943fd2456d8"' \
BUILD-METADATA.json
tar -xzf "$ROKO_BUNDLE"
./roko-node --version
Require an `OK` checksum and the expected revision before touching the service. Stage the binary on the same filesystem and preserve the previous executable:
sudo install -o root -g root -m 0755 roko-node \
/usr/local/bin/roko-node.new
sudo systemctl stop "$ROKO_SERVICE"
sudo cp --preserve=mode,ownership,timestamps \
/usr/local/bin/roko-node \
"/usr/local/bin/roko-node.before-${ROKO_RELEASE}"
sudo mv /usr/local/bin/roko-node.new /usr/local/bin/roko-node
sudo systemctl start "$ROKO_SERVICE"
Do not delete the previous binary until the observation window passes.
Manual Docker upgrade
Use an architecture-specific immutable tag only to discover the image, then pin the resolved digest in the service environment:
ROKO_RELEASE="${ROKO_RELEASE:-v1.0.21}"
case "$(uname -m)" in
x86_64) ROKO_ARCH=amd64 ;;
aarch64|arm64) ROKO_ARCH=arm64 ;;
*) echo "Unsupported architecture" >&2; exit 1 ;;
esac
ROKO_CANDIDATE="ghcr.io/roko-network/roko-node:testnet-${ROKO_RELEASE}-${ROKO_ARCH}"
docker pull "$ROKO_CANDIDATE"
ROKO_IMAGE_DIGEST="$(docker image inspect "$ROKO_CANDIDATE" \
--format '{{index .RepoDigests 0}}')"
ROKO_IMAGE_REVISION="$(docker image inspect "$ROKO_CANDIDATE" \
--format '{{index .Config.Labels "org.opencontainers.image.revision"}}')"
case "$ROKO_IMAGE_DIGEST" in
*@sha256:*) ;;
*) echo "Image did not resolve to a registry digest" >&2; exit 1 ;;
esac
test "$ROKO_IMAGE_REVISION" = \
"8db4c6d7a98057a66b4e67321d561943fd2456d8"
printf 'digest=%s\
revision=%s\
' \
"$ROKO_IMAGE_DIGEST" "$ROKO_IMAGE_REVISION"
docker run --rm "$ROKO_IMAGE_DIGEST" --version
Record the digest, preserve the previous environment file, set `ROKO_IMAGE` to the digest rather than the tag, and restart only the node unit:
sudo cp -a /etc/roko/node-image.env \
"/etc/roko/node-image.env.before-${ROKO_RELEASE}"
printf 'ROKO_IMAGE=%s\
' "$ROKO_IMAGE_DIGEST" |
sudo tee /etc/roko/node-image.env >/dev/null
sudo systemctl restart "$ROKO_SERVICE"
Post-upgrade acceptance
Inspect the unit and recent logs, then repeat the preflight RPC checks:
sudo systemctl status "$ROKO_SERVICE" --no-pager
sudo journalctl -u "$ROKO_SERVICE" --since '-10 minutes' --no-pager
Require all of the following before moving to another validator:
- expected version and revision are running;
- genesis is unchanged and `isSyncing` becomes false;
- best and finalized heads advance across multiple observations;
- peers return to the expected range;
- Chrony is healthy and `temporal_getMeshState` returns `Converged` after
warm-up;
- the expected authority role, authorship, and non-null time quality are
present for a validator; and
- there are no repeated BABE, GRANDPA, database, time-source, OOM, or restart
errors.
Validator acceptance is an identity join. At the same finalized head, prove:
1. host keystore public filenames match the approved seven-key manifest; 2. `session.nextKeys(expected_stash)` matches that manifest byte for byte; 3. the expected stash is in `session.validators`, not only `staking.invulnerables`, `staking.validators`, or `session.queuedKeys`; 4. active BABE, GRANDPA, and temporal keys map to that host; and 5. the host authors blocks and has the correct non-null producer authority index and `temporal_getValidatorTimeQuality` result.
Record configured, queued, and active membership separately. Session changes are protocol-timed; do not declare success while only the configured or queued set matches.
Rollback
Restore only the saved executable or prior image digest. Do not roll back chain data after an upgraded node writes to it unless release notes explicitly state that the database format is backward compatible. Repeat every acceptance check after rollback and record the reason.
Agentic upgrade contract
An automation agent may perform this upgrade only after the operator supplies or approves the target hosts, release tag, immutable artifact, and rollout order. Give the agent this bounded contract:
Upgrade my ROKO node to v1.0.21 using the public ROKO upgrade guide.
Discover the actual unit, executable or image, chain spec, base path, node
identity, role, and loopback RPC before changing anything. Capture preflight
evidence without printing secrets. Verify the immutable checksum or image
digest and embedded source revision. Preserve the chain spec, data, node
identity, keystore, temporal key, credentials, and a tested rollback target.
For validators, upgrade one host at a time. Stop if finality, peers, clock,
storage, memory, or another validator is unhealthy. After restart, wait for
sync, advancing finality, correct active authority identity, authorship, and
PTP² convergence before continuing. Compare the complete intended set with
session.validators and session.queuedKeys; validator count or
staking.invulnerables alone is insufficient. A synced host absent from the
active session is an observer, not a healthy validator.
Stop on the first failed gate. Do not rotate keys, change chain spec, delete
data, move a release tag, submit governance, or widen network exposure. Produce
a value-free receipt with host, old and new revisions, artifact digest,
timestamps, health results, and rollback disposition.
The agent must ask before any action outside that contract.