Running an Earth node
Everything you need to sync a node on earth-1.
If you can't get a node syncing from this page alone, that's a bug in this page — please open an issue.
Not launched yet. Two values below are marked
TBDand will be filled in with the launch release: the seed address and the genesis hash. Until then the network is a single validator and there is nothing to join.
1. Get the binary
Download from the latest release:
VERSION=v0.1.7 # use the launch tag
ARCH=amd64 # or arm64
curl -LO https://github.com/zenopie/earth-network-chain/releases/download/$VERSION/earthd_${VERSION}_linux_${ARCH}.tar.gz
curl -LO https://github.com/zenopie/earth-network-chain/releases/download/$VERSION/checksums.txt
sha256sum -c checksums.txt --ignore-missing # must say OK
tar xzf earthd_${VERSION}_linux_${ARCH}.tar.gz
sudo install -m755 earthd_${VERSION}_linux_${ARCH}/bin/earthd /usr/local/bin/
sudo install -m644 earthd_${VERSION}_linux_${ARCH}/lib/* /usr/local/lib/
Both lines matter. earthd links libwasmvm — the CosmWasm engine — as a shared
library, and the two are version-locked: a node must never pair one release's
earthd with another release's libwasmvm. The tarball ships the matching copy
in lib/, along with the C++ runtime the proof verifier needs.
The binary looks for them at ../lib relative to itself, which is why installing
to /usr/local/bin and /usr/local/lib works with no ldconfig and no
LD_LIBRARY_PATH. Keep the pair together if you install somewhere else.
Check it:
earthd version --long
The version and commit it prints are how you answer "am I running what
everyone else is running" — the only question that matters during an upgrade.
Building instead of downloading? You need cgo and the proof verifier:
sudo apt-get install -y clang python3 binutils libc++-dev libc++abi-dev
cd third_party/barretenberg-go && ./scripts/build-wrapper.sh --platform linux_amd64
cd ../.. && make install
There is also a container image at ghcr.io/zenopie/earth-network-chain, pinned
by digest. See docker/README.md.
2. Initialise
earthd init "<your-moniker>" --chain-id earth-1
3. Install genesis — and check it
This is the step that decides whether you join earth-1 or start your own chain
alone. A node whose genesis differs by one byte computes a different app hash and
will never agree with anyone.
curl -L -o ~/.earth/config/genesis.json \
https://github.com/zenopie/earth-network-chain/releases/download/$VERSION/genesis.json
sha256sum ~/.earth/config/genesis.json
It must print:
TBD — published with the launch release
If it doesn't, stop. Don't work around it.
earthd genesis validate-genesis
4. Configure
Seeds and reachability — in ~/.earth/config/config.toml:
# The address other nodes should dial to reach you. Set it if this node is
# behind NAT, a container, or a cloud provider that maps ports — otherwise
# CometBFT advertises the address it sees on itself, hands that to every peer
# it meets, and nobody can dial you back.
external_address = "your.host.or.ip:26656"
Port 26656 has to be reachable from outside for peers to connect to you. A node can sync without that — it dials out — but it will never be dialled, which means it contributes nothing to the network's connectivity and cannot serve state sync to anyone.
Running from the Docker image, these are SEEDS, PERSISTENT_PEERS and
EXTERNAL_ADDRESS environment variables; the entrypoint writes them into
config.toml on every start, so a restart is enough to change one.
Minimum gas price — in ~/.earth/config/app.toml. Required. The node will
not start without it, and the error doesn't say which file to edit:
set min gas price in app.toml or flag or env variable
Below this value your node won't relay a transaction. This is a per-node setting, not a chain rule — there is no fee module, so the network's real floor is whatever most validators pick:
minimum-gas-prices = "0.005uerth"
Pruning — pick by what the node is for, in app.toml:
| role | setting |
|---|---|
| validator | pruning = "default" |
| public RPC | pruning = "custom", pruning-keep-recent = "362880", pruning-interval = "100" |
| archive | pruning = "nothing" — grows without limit |
Snapshots — on by default, and worth leaving on:
snapshot-interval = 1000 # ~80 minutes at 5s blocks
snapshot-keep-recent = 5
This is what lets other people state-sync from you. 0 disables it. If
everyone disables it, nobody can join without replaying the whole chain.
If you change pruning, check the states a snapshot needs are still kept —
pruning = "default" keeps far more than the snapshot interval, so the two do
not collide.
Don't enable enabled-unsafe-cors on a validator. It lets any website read
your node and broadcast through it. If you're serving a browser app, run a
separate read-only node for that.
4b. State sync (optional, but much faster)
Instead of replaying every block, fetch state at a recent height from a peer.
This chain benefits more than most. Replaying a block re-executes its transactions, and every passport registration verifies a zero-knowledge proof. A chain that mostly moves tokens replays quickly; this one re-runs a proof per registration, so replay cost grows with adoption.
Get a trust height and hash a little behind the tip:
RPC=https://rpc.erth.network
LATEST=$(curl -s $RPC/block | jq -r .result.block.header.height)
TRUST_HEIGHT=$(( LATEST - 2000 ))
TRUST_HASH=$(curl -s "$RPC/block?height=$TRUST_HEIGHT" | jq -r .result.block_id.hash)
echo "$TRUST_HEIGHT $TRUST_HASH"
Put them in ~/.earth/config/config.toml under [statesync]:
enable = true
rpc_servers = "https://rpc.erth.network:443,https://rpc.erth.network:443"
trust_height = <TRUST_HEIGHT>
trust_hash = "<TRUST_HASH>"
trust_period = "168h0m0s"
rpc_servers needs at least two entries — the same address twice is
accepted, though two independent ones are better.
Then start with an empty data directory:
earthd tendermint unsafe-reset-all --home ~/.earth --keep-addr-book
earthd start
The log shows Discovering snapshots, then Fetching snapshot chunks. If it
sits on Discovering snapshots with no progress, no peer is offering one —
check snapshot-interval is non-zero on the node you are syncing from.
5. Start
earthd start
Watch it catch up:
curl -s localhost:26657/status | jq .result.sync_info
catching_up: false means you're synced.
Hardware
| validator | public RPC | archive | |
|---|---|---|---|
| CPU | 4 cores | 4 cores | 8 cores |
| RAM | 16 GB | 16 GB | 32 GB |
| Disk | 500 GB SSD | 1 TB SSD | 2 TB+ SSD |
SSD, not spinning disk — the node fsyncs every block.
One thing specific to this chain: every passport registration verifies a zero-knowledge proof on-chain, which is CPU-heavy and cannot be skipped. Budget more CPU than a chain of this size would normally need.
Becoming a validator
Sync first. A node that isn't caught up can't validate.
Write validator.json:
{
"pubkey": PASTE_OUTPUT_OF_show-validator,
"amount": "1000000uerth",
"moniker": "<your-moniker>",
"commission-rate": "0.1",
"commission-max-rate": "0.2",
"commission-max-change-rate": "0.01",
"min-self-delegation": "1"
}
pubkey is the whole JSON object from earthd comet show-validator, pasted in
unquoted — not a string.
earthd tx staking create-validator validator.json \
--chain-id earth-1 --from <your-key> --gas auto --gas-adjustment 1.5
Your consensus key should not live on the node. Use a remote signer — see deploy/akash/REMOTE_SIGNER.md. It fails closed: with a signer configured and none answering, your node signs nothing rather than signing with a key it shouldn't have.
Double-signing gets you slashed and tombstoned permanently. Never run two nodes with the same consensus key — not during a migration, not for a few seconds.
Upgrades
Upgrades halt the chain at an agreed height. Your node stops on its own and waits.
Use cosmovisor so the new binary is staged in advance and swaps automatically, instead of you doing it by hand at whatever hour the height lands.
Each upgrade's release notes give the name, the height, and the binary.
If something goes wrong
"expected chain id earth-1" — wrong genesis. Redo step 3.
Wrong app hash at a height — your genesis differs from everyone else's, or you're on the wrong binary. Check both hashes.
"set min gas price in app.toml" — the node won't start until
minimum-gas-prices is set in app.toml. See step 4.
No peers — your seeds are wrong, or port 26656 isn't reachable. Peers have to be able to dial you.
Stuck at a height with peers connected — usually an upgrade you haven't applied. Check the releases page.
State sync stuck on "Discovering snapshots" — no peer is offering one. The
node you are syncing from needs a non-zero snapshot-interval, and a snapshot
cannot be produced for a height already passed.