Docker container for running the Structs Consensus Engine.
Docker Hub: https://hub.docker.com/r/structs/structsd/
In the distant future the species of the galaxy are embroiled in a race for Alpha Matter, the rare and dangerous substance that fuels galactic civilization. Players take command of Structs, a race of sentient machines, and must forge alliances, conquer enemies and expand their influence to control Alpha Matter and the fate of the galaxy.
git clone git@github.com:playstructs/docker-structsd.git
cd docker-structsd
docker build .
The following will run the latest Structs consensus server.
docker run -d --restart unless-stopped -p 26656:26656 --name=structsd structs/structsd:latest
--restart unless-stopped is recommended so the container auto-recovers if cosmovisor itself ever crashes. The chain binary swap at the upgrade height does not stop the container (see "Cosmovisor and chain upgrades" below), but a host reboot or cosmovisor crash would.
A good way to run for development and for continual monitoring is to attach to the terminal:
docker run -it --rm -p 26656:26656 --name=structsd structs/structsd:latest
This image runs structsd under cosmovisor so that on-chain x/upgrade software-upgrade plans swap the binary automatically without operator intervention and without restarting the container.
Three binaries are baked into the image:
- Genesis binary — built from the
structsd111bbranch with Ignite. Cosmovisor runs this from block 0 until the first upgrade fires. - Upgrade binary
v0.16.0— the officialstructsd-0.16.0-linux-amd64.tar.gzfrom the v0.16.0 GitHub release, verified against the sha256 from the on-chain proposal. Cosmovisor switches to this at height 385730. - Upgrade binary
v0.17.0— the officialstructsd-0.17.0-linux-amd64.tar.gzfrom the v0.17.0 GitHub release, verified against the sha256 from governance proposal 2. Cosmovisor switches to this at height 867678.
At container start, scripts/start.sh syncs all binaries into $STRUCTS_PATH/cosmovisor/ (idempotent), runs scripts/reconcile-cosmovisor-current.sh to fix any drift in the cosmovisor/current symlink, registers batch upgrades for catch-up syncs, then execs cosmovisor run start --home $STRUCTS_PATH. Because cosmovisor is PID 1 and DAEMON_RESTART_AFTER_UPGRADE=true, each upgrade swap is handled in-place: the daemon child exits, cosmovisor updates cosmovisor/current, and starts the new binary as a fresh child. The container itself stays running.
The reconciler treats data/upgrade-info.json (written by x/upgrade at the upgrade height) as the authoritative signal for which binary should be running. This closes the rare window where a Docker restart during an in-process upgrade swap would otherwise leave cosmovisor/current pointing at the old binary and trigger a permanent restart loop.
Roll out a new image before the next on-chain upgrade height. Consider publishing a versioned tag (e.g. structs/structsd:v0.17.0) alongside :latest so operators can pin the exact image containing the upgrade binary.
| Variable | Default | Notes |
|---|---|---|
DAEMON_NAME |
structsd |
Must match the binary file name under cosmovisor/*/bin/. |
DAEMON_HOME |
/root/.structs |
Same as STRUCTS_PATH; cosmovisor looks for cosmovisor/ under this path. |
DAEMON_RESTART_AFTER_UPGRADE |
true |
Required so the container does not exit after the upgrade swap. |
DAEMON_ALLOW_DOWNLOAD_BINARIES |
false |
Image is hermetic; the upgrade binary is baked in. |
UNSAFE_SKIP_BACKUP |
true |
Skips tarballing data/ before upgrade. Set to false for an extra safety net (slow on a long-lived chain). Take a manual volume snapshot before upgrade heights regardless. |
The repo has one source of truth for known upgrades — scripts/upgrades.conf.sh — and one place that downloads the binary at build time (Dockerfile). When a governance proposal lands:
- Add one line to
scripts/upgrades.conf.sh:UPGRADES=( "v0.16.0:385730" "v0.17.0:867678" "v0.18.0:NEW_HEIGHT" )
- Add one line to the upgrade
RUNin theDockerfile, using the sha256 from the governance proposal:/root/scripts/install-upgrade-binary.sh v0.18.0 0.18.0 <sha256> - Rebuild and roll before the upgrade height. Cosmovisor picks the right binary based on chain state.
scripts/start.sh and scripts/reconcile-cosmovisor-current.sh both source upgrades.conf.sh, so the batch-upgrade list, pre-flight checks, and drift correction all derive automatically. No compose changes are needed for chain upgrades — operators never touch their compose files for this.
The genesis binary stays 111b so fresh syncs from block 0 still work through all historical upgrade heights.
If a container is restart-looping with UPGRADE "vX.Y.Z" NEEDED at height: N after the chain crossed the upgrade height, cosmovisor/current is pointing at the old binary. The reconciler in this image self-heals on every start, so the permanent fix is to rebuild and redeploy with the latest image.
For an immediate fix without rebuilding (or for nodes still on a pre-reconciler image), repoint the symlink manually:
# Universal: works on any host (replace v0.17.0 with the target upgrade name).
docker exec <structsd-container> bash -c '
ln -sfn upgrades/v0.17.0 /root/.structs/cosmovisor/current &&
cp /root/.structs/data/upgrade-info.json \
/root/.structs/cosmovisor/upgrades/v0.17.0/upgrade-info.json
'
docker restart <structsd-container>Notes:
STRUCTS_UPGRADE_NAMEis not used by this image. Do not add it to compose; older docs that reference it are out of date.priv_validator_state.jsonheight only advances for validators that signed blocks. Full nodes rely ondata/upgrade-info.jsonfor upgrade detection (which is sufficient —x/upgradewrites that file at every upgrade height regardless of node role).
Copyright 2021 Slow Ninja Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.