structsd is the reference client for the Structs consensus network
2.7K
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 [email protected]: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.
The genesis binary plus every known upgrade binary are baked into the image:
structsd 111b branch with Ignite. Cosmovisor runs this from block 0 until the first upgrade fires.v0.16.0 — official linux/amd64 tarball from the v0.16.0 GitHub release. Switches at height 385730.v0.17.0 — v0.17.0. Height 867678.v0.18.0 — v0.18.0. Height 1173255.v0.19.0 — plan v0.19.0 ships the 0.19.1 binary from the v0.19.1 GitHub release. Height 1335904.v0.20.0 — v0.20.0. Height 1732284.v0.21.0 — v0.21.0. Height 2283000.Each upgrade tarball is verified at build time against the sha256 from the matching on-chain governance proposal (or the official release checksums.txt when that is the source). The runtime list of plan names and heights lives in scripts/upgrades.conf.sh.
At container start, scripts/start.sh syncs all binaries into $STRUCTS_PATH/cosmovisor/ (idempotent), runs scripts/reconcile-cosmovisor-current.sh to point cosmovisor/current at the right binary, then execs cosmovisor run start --home $STRUCTS_PATH.
The reconciler selects the binary from chain state, not from upgrade-info.json. It reads the height the application last committed from data/application.db (via structs-chain-height, built from tools/chain-height) and picks the plan in upgrades.conf.sh that covers the next block. It moves current forward or backward as needed, and moves aside any data/upgrade-info.json whose plan height has not been reached yet. If the height cannot be read, it leaves current unchanged rather than guess.
Upgrades happen like this: at the plan height, x/upgrade writes data/upgrade-info.json and halts the old binary with UPGRADE "vX.Y.Z" NEEDED. Cosmovisor exits, Docker restarts the container, and the reconciler selects the new binary. The service must have a restart policy (restart: unless-stopped) for this to happen without intervention. Catch-up syncs from genesis go through every upgrade this way.
The image does not use cosmovisor add-batch-upgrade. Its watcher writes the next plan into data/upgrade-info.json as soon as the previous plan passes, hundreds of thousands of blocks early, and earlier versions of the reconciler trusted that file. A restart in that window switched full nodes to the next binary early, which commits a non-canonical app hash and stalls blocksync with wrong Block.Header.AppHash. start.sh removes the batch files from existing volumes.
Run the reconciler tests with bash tests/reconcile-cosmovisor-current.test.sh (needs bash and jq).
Roll out a new image before the next on-chain upgrade height. Consider publishing a versioned tag (e.g. structs/structsd:v0.21.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:
scripts/upgrades.conf.sh:
UPGRADES=(
"v0.16.0:385730"
"v0.17.0:867678"
"v0.18.0:1173255"
"v0.19.0:1335904"
"v0.20.0:1732284"
"v0.21.0:2283000"
"v0.22.0:NEW_HEIGHT"
)
RUN in the Dockerfile, using the sha256 from the governance proposal:
# Normal case (release tag == on-chain plan name):
/root/scripts/install-upgrade-binary.sh v0.22.0 0.22.0 <sha256>
# When the plan-name binary ships under a different release tag (e.g. a hotfix),
# pass the release tag as an optional 4th arg. Here the v0.19.0 plan binary
# lives in the v0.19.1 GitHub release:
/root/scripts/install-upgrade-binary.sh v0.19.0 0.19.1 <sha256> v0.19.1
cosmovisor/upgrades/<dir>), the second is the version in the release filename, the third is the tarball sha256, and the optional fourth overrides the GitHub release tag (defaults to the plan name).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.
Every start logs the selection, for example cosmovisor/current -> upgrades/v0.20.0 (committed height: 1912301). Check that line first.
Restart loop with UPGRADE "vX.Y.Z" NEEDED at height: N: the image does not contain that plan. Add it to upgrades.conf.sh and the Dockerfile, rebuild, and redeploy. The reconciler logs chain requested upgrade ... which this image does not know in this case.
Stalled with wrong Block.Header.AppHash in blocksync: the node executed a block with the wrong binary (for example on an image older than the height-based reconciler). With the new image the reconciler repoints current and logs a warning. The last committed block is still bad and must be rolled back once, with the container stopped and the correct binary (the one current points to):
docker compose stop structsd
docker run --rm --entrypoint bash -v structsd-chaindata:/root/.structs structs/structsd:latest -c \
'/root/.structs/cosmovisor/current/bin/structsd rollback --home /root/.structs'
docker compose start structsd
On an image older than the height-based reconciler, first move data/upgrade-info.json aside and run ln -sfn upgrades/<correct plan> /root/.structs/cosmovisor/current, or the next start switches back to the wrong binary.
could not read committed chain height: the reconciler left current unchanged. The usual cause is another process holding data/application.db.
STRUCTS_UPGRADE_NAME is not used by this image. Do not add it to compose; older docs that reference it are out of date.
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.
Content type
Image
Digest
sha256:c53a04c48…
Size
2.3 GB
Last updated
about 1 month ago
docker pull structs/structsd