Skip to content

Quickstart: join the testnet

Sova is an EVM chain. Its gas coin, SOVA, is issued to people who burn ZEC on Zcash. One Sova block follows each Zcash block, and every Sova node runs beside its own Zcash node and re-derives every payout from it.

The public testnet is anchored to Zcash testnet, so you burn TAZ (testnet ZEC). Its chain ID is 82330. To look around first, browse explorer.testnet.sova.io.

This quickstart takes you from nothing to a synced Zcash testnet zebrad, a Sova node on the network, and a sova-miner burning TAZ and earning SOVA. The testnet reference has the rest: requirements, sealing, earnings, troubleshooting and every setting.

You need Linux x86_64 or an Apple Silicon Mac (a laptop or a small VPS), Docker, curl, jq, zstd, git, and about 40 GB free. Testnet coins have no value, and the chain can reset (what this testnet is).

Everything lives in ~/.sova-testnet/. The rpc helper is used throughout:

Terminal window
mkdir -p ~/.sova-testnet/bin ~/.sova-testnet/zebrad-state
export PATH="$HOME/.sova-testnet/bin:$PATH"
rpc() { curl -s -H 'Content-Type: application/json' \
--data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$2\",\"params\":${3:-[]}}" "$1"; }

Write ~/.sova-testnet/zebrad.toml:

[network]
network = "Testnet"
listen_addr = "0.0.0.0:18233"
[state]
cache_dir = "/var/lib/sova/zebrad"
[rpc]
# Inside the container. Docker publishes it on the host's 127.0.0.1 only (1c).
listen_addr = "0.0.0.0:18232"
# The Sova node can't read zebrad's auth cookie yet, so cookie auth is off.
# Keep the RPC on loopback.
enable_cookie_auth = false
[tracing]
use_color = false

A snapshot saves hours of sync. Get snapshot.sh at the release tag, then download the snapshot (11 GB; aria2c resumes and uses 8 connections):

Terminal window
git clone https://github.com/sova-chain/sova ~/.sova-testnet/src
git -C ~/.sova-testnet/src checkout v0.1.14
SNAP=~/.sova-testnet/src/box/testnet/snapshot.sh
mkdir -p ~/.sova-testnet/snapshot && cd ~/.sova-testnet/snapshot
aria2c -x 8 -s 8 -c https://dl.testnet.sova.io/zebrad-testnet/4390524/zebrad-testnet-4390524.tar.zst
curl -fLO https://dl.testnet.sova.io/zebrad-testnet/4390524/SHA256SUMS
curl -fLO https://dl.testnet.sova.io/zebrad-testnet/4390524/snapshot.json
jq -r '.height, .hash, .sha256, .zebra_version' snapshot.json

The four values printed must match these:

4390524
000007d5b1a082776d85c9bc5eabc0b093110675c33c78d9eb78c5b0449a57bb
e78e551d89b66a07b6623b3eb02ea71c5adf532addd510e59b55717adfd2c4a3
v6.3.0

Restore into the empty state directory, and keep cache_dir as in 1a:

Terminal window
bash "$SNAP" restore zebrad-testnet-4390524.tar.zst ~/.sova-testnet/zebrad-state

After 1c, check the snapshot against a source the project doesn’t run.

Terminal window
sudo chown -R 10001:10001 ~/.sova-testnet/zebrad-state # Linux only
docker run -d --name zebrad --restart unless-stopped \
-p 127.0.0.1:18232:18232 -p 18233:18233 \
-v "$HOME/.sova-testnet/zebrad.toml:/home/zebra/.config/zebrad.toml:ro" \
-v "$HOME/.sova-testnet/zebrad-state:/var/lib/sova/zebrad" \
-e RUST_LOG=info \
zfnd/zebra:6.3.0

Skipped the snapshot? The same command full-syncs from zero (about 12 hours). Stop it with docker stop -t 110 zebrad, so RocksDB flushes cleanly.

Terminal window
rpc http://127.0.0.1:18232 getblockchaininfo | jq '.result | {blocks, estimatedheight}'

Wait until blocks is within a few blocks of estimatedheight.

Terminal window
cd ~/.sova-testnet
TAG=v0.1.14
PLATFORM=linux-x86_64 # or darwin-arm64
BASE=https://github.com/sova-chain/sova/releases/download/$TAG
curl -fLO "$BASE/SHA256SUMS"
curl -fLO "$BASE/sova-box-bin-$PLATFORM.tar.gz"
grep " sova-box-bin-$PLATFORM.tar.gz" SHA256SUMS | sha256sum -c - # macOS: shasum -a 256 -c -
mkdir -p release && tar -xzf "sova-box-bin-$PLATFORM.tar.gz" -C release
(cd release && sha256sum -c SHA256SUMS) # macOS: shasum -a 256 -c SHA256SUMS
install -m 0755 release/sova release/sova-miner bin/

Other platforms: build from source.

Terminal window
cd ~/.sova-testnet
curl -fsSLO https://dl.testnet.sova.io/testnet.env
curl -fsSLO https://dl.testnet.sova.io/seeds.json

testnet.env holds the network’s settings, which every node shares, and three of your own (what’s in it).

Terminal window
cd ~/.sova-testnet
. ./testnet.env
sova genesis-hash
jq -r .genesis_hash seeds.json

Both must print 0xb7391a4a83644e1dce95c95348a005febedeaa12fa46eb30ac0dfb5f36f00b71. If not, you’d be on another chain.

A follow-only node checks and serves the chain but produces no blocks.

Terminal window
cd ~/.sova-testnet
. ./testnet.env
sova 2>&1 | tee -a node.log

On a VPS with a public IPv4, also export SOVA_NAT=extip:<your public IPv4>. What a good start looks like.

Compare a block hash with the public RPC at the same height:

Terminal window
H=$(rpc http://127.0.0.1:8545 eth_blockNumber | jq -r .result)
rpc http://127.0.0.1:8545 eth_getBlockByNumber "[\"$H\",false]" | jq -r .result.hash
rpc https://rpc.testnet.sova.io eth_getBlockByNumber "[\"$H\",false]" | jq -r .result.hash

The two hashes match: your node is verifying the testnet. It catches up only as far as your zebrad has scanned. If H is still 0x0, see No peers after 5 minutes.

Always pass --network test. The default is regtest.

Terminal window
sova-miner --network test --data-dir ~/.sova-testnet/miner init
t-addr to fund: tm...
evm address (SIP-1 credit): 0x...
keystore: .../.sova-testnet/miner/keystore.json
state: .../.sova-testnet/miner/state.json

One key holds both the TAZ at the t-addr and the SOVA at the EVM address. The keystore is plaintext behind file mode 0600: keep it that way, and back it up.

Terminal window
curl -s -X POST -d '{"address":"tm..."}' https://faucet.testnet.sova.io/drip

It sends 0.1 TAZ to a tm… address, once per address and per IP every 24 hours. The TAZ is spendable about one Zcash block later.

Terminal window
sova-miner --network test --data-dir ~/.sova-testnet/miner mine \
--rpc http://127.0.0.1:18232 \
--per-epoch-zat 10000 \
--budget-zat 5000000

It sends at most one burn per new Zcash block:

epoch 1: height=... burn=10000zat fee=...zat change=...zat txid=...

Each burn costs --per-epoch-zat plus a Zcash fee of about 20,000 zat. One drip is about 330 burns at these values.