Sign inSign up

structs/structsd

By structs

•Updated about 1 month ago

structsd is the reference client for the Structs consensus network

Image
0

2.7K

structs/structsd repository overview

⁠docker-structsd

Docker⁠ container for running the Structs Consensus Engine⁠.

Docker Hub: https://hub.docker.com/r/structs/structsd/⁠

⁠Structs

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.

⁠How to Build

git clone [email protected]:playstructs/docker-structsd.git
cd docker-structsd
docker build .

⁠How to Use this Image

⁠Quickstart

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.

⁠Interactive

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

⁠Cosmovisor and chain upgrades

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:

  • Genesis binary — built from the structsd 111b branch with Ignite. Cosmovisor runs this from block 0 until the first upgrade fires.
  • Upgrade binary v0.16.0 — official linux/amd64 tarball from the v0.16.0 GitHub release⁠. Switches at height 385730.
  • Upgrade binary v0.17.0 — v0.17.0⁠. Height 867678.
  • Upgrade binary v0.18.0 — v0.18.0⁠. Height 1173255.
  • Upgrade binary v0.19.0 — plan v0.19.0 ships the 0.19.1 binary from the v0.19.1 GitHub release⁠. Height 1335904.
  • Upgrade binary v0.20.0 — v0.20.0⁠. Height 1732284.
  • Upgrade binary 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.

⁠Cosmovisor environment knobs

VariableDefaultNotes
DAEMON_NAMEstructsdMust match the binary file name under cosmovisor/*/bin/.
DAEMON_HOME/root/.structsSame as STRUCTS_PATH; cosmovisor looks for cosmovisor/ under this path.
DAEMON_RESTART_AFTER_UPGRADEtrueRequired so the container does not exit after the upgrade swap.
DAEMON_ALLOW_DOWNLOAD_BINARIESfalseImage is hermetic; the upgrade binary is baked in.
UNSAFE_SKIP_BACKUPtrueSkips 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.

⁠Adding a future upgrade

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:

  1. Add one line to 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"
    )
    
  2. Add one line to the upgrade 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
    
    The first arg is the on-chain plan name (and the 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).
  3. Rebuild and roll before the upgrade height. The reconciler 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.

⁠Stuck after an upgrade?

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.

⁠Learn more

⁠License

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.

Tag summary

Content type

Image

Digest

sha256:c53a04c48…

Size

2.3 GB

Last updated

about 1 month ago

docker pull structs/structsd