Bootstrap image and tools for running Amaru on custom Cardano testnets.
Amaru cannot currently synchronise from genesis on arbitrary custom
testnets. It must start from prepared ledger and chain stores, plus the
testnet runtime parameters that tell amaru run how to interpret slots,
epochs, and Praos constants.
This repository builds the ghcr.io/lambdasistemi/amaru-bootstrap-producer
image used by the Antithesis Amaru testnets. The image carries two
entrypoints:
amaru-relay-bootstrap: the Antithesis relay entrypoint. It runs as the long-livedamaru-relay-Ncontainer, writes the Antithesis startup marker, bootstraps from its pairedcardano-node, thenexecsamaru run.bootstrap-producer: the lower-level one-shot bundle producer used by the relay entrypoint and by local verification. It reads a cardano-node ChainDB, derives snapshot targets from the chain itself, runsamaru create-snapshotsandamaru bootstrap, then exits with a classed status code.
The image default Docker entrypoint remains bootstrap-producer for
standalone compatibility. Antithesis Compose stacks must override it to
amaru-relay-bootstrap.
flowchart LR
node["paired cardano-node\nChainDB + config"] --> producer["bootstrap-producer\n(one-shot)"]
relay["amaru-relay-bootstrap\n(long-lived container)"] --> producer
producer --> extractor["header-extractor\ntip-info / list-blocks"]
producer --> snaps["amaru create-snapshots\n(db-analyser engine)"]
producer --> boot["amaru bootstrap"]
boot --> bundle["bundle\nledger.net.db + chain.net.db\nsnapshots + era-history.json"]
bundle --> run["exec amaru run"]
relay --> run
runtime["/amaru-runtime\nera-history.json\nglobal-parameters.json"] --> run
The production path does not use db-synthesizer. It reads a live
cardano-node ChainDB and runs:
header-extractor tip-info/list-blocks- poll the immutable DB until the chain is era-ready, then pick the last block of each of the three most recent completed epochs as snapshot targets.amaru create-snapshots- materialize per-epoch snapshot directories (with packaged bootstrap headers) directly from the local chain DB, using--targets-fileand--cardano-db-dirto bypass Koios and Mithril. Internally this drives thedb-analyserengine, which is whydb-analyseris bundled in the image.- era-history sidecars - the producer writes
history.<slot>.<hash>.jsonnext to each snapshot and anera-history.jsonat the bundle root, both built from the mounted Shelley genesisepochLength. amaru bootstrap- populateledger.<network>.dbandchain.<network>.dbfrom the snapshots, deriving nonces and importing the packaged headers.- atomic commit -
mv -Tof the staging directory into<bundle-dir>/<network>.
db-synthesizer remains in this repository only for fixtures and checks.
It fabricates ChainDB inputs for CI; it is not in the Antithesis runtime
path. ledger-state-emitter (the in-repo node-10.7.1 ledger projection
tool) is still built, shipped, and exposed as a flake app, but it is no
longer invoked by the producer pipeline since the migration to upstream
create-snapshots + bootstrap.
The supported runtime artifact is the published Docker image:
ghcr.io/lambdasistemi/amaru-bootstrap-producer:<full-commit-sha>
After CI succeeds on main, GitHub Actions publishes a tag named by the
full commit SHA. After CI succeeds on a same-repository pull request, it
also publishes:
ghcr.io/lambdasistemi/amaru-bootstrap-producer:<full-pr-head-sha>
ghcr.io/lambdasistemi/amaru-bootstrap-producer:pr-<pr-number>-<full-pr-head-sha>
Downstream Compose files should pin a full commit-SHA tag. The project
does not publish moving runtime tags such as latest.
Local image build (x86_64-linux only):
nix build .#packages.x86_64-linux.bootstrap-producer-image \
-o result-bootstrap-producer-image
docker load -i result-bootstrap-producer-imageThe matching CI artifact is named bootstrap-producer-image-<github-sha>
and contains amaru-bootstrap-producer-<github-sha>.tar.gz.
Produce a bundle from an existing cardano-node ChainDB without Docker:
nix run .#bootstrap-producer -- \
/path/to/cardano-node/db \
/path/to/cardano-node/config \
/tmp/amaru-bundle \
testnet_42That command waits for the chain to become era-ready, writes
/tmp/amaru-bundle/testnet_42, and exits. For the full Compose relay
shape, follow the tutorial.
All tools are exposed as flake apps:
| App | Purpose |
|---|---|
nix run .#bootstrap-producer |
One-shot bundle producer (<chain-db> <config-dir> <bundle-dir> <network>) |
nix run .#smoke-test |
Phase 0 format-compatibility smoke test (<bundle> <out-dir>) |
nix run .#header-extractor |
Immutable chain-DB queries: tip-info, list-blocks, get-header |
nix run .#ledger-state-emitter |
Standalone node-10.7.1 ledger-state projection (not in the producer pipeline) |
nix run .#amaru |
The pinned Amaru binary |
nix run .#db-synthesizer / .#db-analyser / .#snapshot-converter |
Pinned upstream consensus tools |
In the downstream
cardano-foundation/cardano-node-antithesis
Amaru testnets, each amaru-relay-N container is an instance of this
image with:
entrypoint: amaru-relay-bootstrap
environment:
RELAY_NAME: amaru-relay-1
AMARU_PEER: p1.example:3001
AMARU_NETWORK: testnet_42
AMARU_BOOTSTRAP_RETRY_SECONDS: "5"
volumes:
- p1-state:/live:ro
- p1-configs:/cardano/config:ro
- ./amaru-runtime:/amaru-runtime:ro
- amaru-startup:/startup
- a1-state:/srv/amaruThe relay entrypoint writes /startup/$RELAY_NAME.started immediately so
the Antithesis sidecar can emit setup-complete inside the setup window.
Bootstrap then continues during the test phase. The relay loops over
bootstrap-producer, promotes a complete bundle into /srv/amaru, and
finally runs:
amaru run \
--network "$AMARU_NETWORK" \
--ledger-dir /srv/amaru/ledger.$AMARU_NETWORK.db \
--chain-dir /srv/amaru/chain.$AMARU_NETWORK.db \
--era-history-file /amaru-runtime/era-history.json \
--global-parameters-file /amaru-runtime/global-parameters.json \
--peer-address "$AMARU_PEER"
The amaru-runtime/ directory is part of the deployment contract. It
must contain:
era-history.json: the custom testnet era history passed to--era-history-file.global-parameters.json: the custom testnet consensus parameters passed to--global-parameters-file.
This repository currently targets cardano-node 10.7.1. That is
deliberate: Cardano ledger-state CBOR changes across node releases, so
compiling against a random ledger package set is not enough. Retargeting
the producer means updating cabal.project, flake.lock, and the
documented projection in
specs/003-amaru-bootstrap-producer/research.md#r-011.
The MkDocs site is published at
https://lambdasistemi.github.io/amaru-bootstrap/ and starts at
docs/index.md. The current operator path is
docs/tutorial.md, and the Antithesis-specific
contract is in docs/antithesis.md.
For AI agents, start at AGENTS.md.
just cijust ci mirrors the GitHub workflow: it runs the Build Gate, runs the
Phase 0 smoke verdict, and runs the Docker-level live bootstrap verifier.
Producer-specific checks include:
nix build .#checks.x86_64-linux.bootstrap-producer-synthesized
nix build .#checks.x86_64-linux.amaru-run-bootstrap
nix build .#checks.x86_64-linux.antithesis-short-epoch-samples
nix build .#checks.x86_64-linux.antithesis-short-epoch-golden
nix build .#checks.x86_64-linux.bootstrap-producer-bats
nix build .#checks.x86_64-linux.bootstrap-producer-image
just live-bootstrap-producerThese checks prove bundle production, Amaru import, and Amaru startup alignment for the pinned release boundary. They are not exhaustive mainnet ledger-content coverage.
Apache-2.0. See LICENSE.