Public testnet
The public testnet carries mainnet's consensus rules under its own chain id, so what it measures is mainnet's behaviour and not its own. Its coins are worth nothing and are meant to be.
What it is#
zcd genesis --testnet
network zycord-testnet
chain id 2
params hash 0xc4a670f04575ac3aa6e670888e1a42ec877779fda8e5519e2637f4df93815b57
launch commit 0x83aeb709b14b43a0296666f006d99378049064f3e30d8191e074e09d485e2ff7
genesis id 0x81094507a4a083d01e24af21bddbf4d7eb496472a69c4b5dfb0d7a27c6b03b55
state root 0x4f45e604e1fd7ccf066e20e5fd41105373a0ba0d28aea8fc825b8795e880384f
genesis time 1791158400
cells written 6
allocations 0
Run that command before you trust this page. A build that prints a different
genesis id is a build on a different chain, and it will not connect to this one — the
handshake refuses before a block is evaluated. allocations 0 is the premine claim,
checkable rather than promised.
Genesis was 2026-10-05T00:00:00Z (unix 1791158400), two days before
mainnet's: the testnet rehearsed the launch with the same binary and the same procedure. It is now
where Era 1 runs first — the cEVM, sequencers, intents and fills, the
directory and the forced path have been active here since height 2,880, its first day, while
mainnet reaches the same gate at height 80,640. You can watch the chain at
testnet.zycord.com.
It differs from mainnet in ten values and nowhere else#
name, chain_id, genesis_target, max_target,
genesis_time, randomx_key_interval, h1_bond,
h1_vm, coinbase_maturity and launch_commit. The activation
heights are lower here on purpose: the testnet reached them on its first day, so the machine is
exercised for weeks before mainnet arrives at the same gate. h1_bond moves with
h1_vm and opens nothing on either network: bonding is not part of Era 1. The launch commitment is the
testnet's own, so its block 1 rehearses mainnet's launch without revealing mainnet's. Everything
else — undo_depth, target_block_seconds, the subsidy split, and
the whole gas schedule — is mainnet's on purpose. The gas schedule
especially, because it is what makes the base-fee behaviour measured here mainnet's rather than
this network's own. A testnet on its own gas schedule measures a different chain.
| Parameter | Public testnet | Mainnet |
|---|---|---|
name | zycord-testnet | zycord |
chain_id | 2 | 1 |
genesis_time | 1791158400 — 2026-10-05T00:00:00Z | 1791331200 — 2026-10-07T00:00:00Z |
randomx_key_interval | 512 blocks | 2048 blocks |
h1_bond, h1_vm | 2,880 — about day 1 | 80,640 — about day 28 |
coinbase_maturity | 100 blocks | 240 blocks |
target_block_seconds | 30 — identical | |
epoch_length | 2880 blocks, about a day — identical | |
ttl_max | 240 blocks, about two hours — identical | |
emission_ramp_blocks | 86,400, the 30-day reward ramp — identical | |
founder_share, treasury_share_bps | 94% miner, 3% founder until 3,153,600, 3% treasury — identical | |
A testnet may be reset from genesis. When it is, its coins, its history and its peer lists are gone, the network takes a fresh chain id, and a data directory holding the old chain is refused at startup rather than silently mixed. The two networks also disconnect at the handshake, so nothing carries over quietly.
Joining#
make build-randomx # the testnet is randomx-v2; see below
# -> bin/zcd-randomx, bin/zycordd-randomx
./bin/zycordd-randomx --testnet --dir ./testnet
make build-randomx, not make build. The testnet's
pow_engine is randomx-v2, the same work function as mainnet. A binary
built without the tag refuses to start against it rather than falling back to the development
engine, which would accept a single BLAKE3 pass as proof of work for every header it ever saw.
The tagged binaries carry the tag in their names, so that building both leaves
both on disk and the file name says which engine is inside it. Elsewhere on these pages the
commands are written zcd and zycordd for brevity; on this network those
are the -randomx pair.
Bootstrap#
The binary carries the testnet's seeds: seed1.zycord.com to
seed4.zycord.com on port 19421. Mainnet's seeds are the same hosts on
9421, and the two networks refuse each other at the handshake, so nothing mixes. An
older binary that names testnet.zycord.com as its seed should be replaced rather than
worked around. To supply other peers instead, or as well:
zycordd --testnet --dir ./testnet --peers-file peers.txt
zycordd --testnet --dir ./testnet --peers host:19421,otherhost:19421
zycordd --testnet --dir ./testnet --no-seeds --peers-file peers.txt
Be dialable if you can#
Zycord does not do NAT traversal. A node with --listen on a reachable port is
somewhere others can bootstrap from, and the share of such nodes is the falsifiable
condition the whole no-traversal decision rests on — it is measured, not assumed.
zycordd --testnet --dir ./testnet \
--listen 0.0.0.0:9421 --advertise <public-address>:9421
If you cannot forward a port, leave --listen off and be periphery. That is a
perfectly good way to participate. Check which you are with curl -s
localhost:9420/network — listening: true with inbound: 0
after a few minutes means the port is not actually reachable.
Getting coins#
Two routes, and the second is the one this network was designed around.
The faucet#
The testnet explorer runs one. It pays a small amount to any address you give it, so that a send, a refund and a sweep can be rehearsed without allocating two gibibytes to RandomX first. What it is and why it is built that way is a page of its own.
It exists on this network and on no other. The faucet is a feature of the
explorer that is off by default, and enabling it requires naming a network — a name checked
against the chain that explorer is actually indexing, with mainnet refused outright.
Mainnet has no faucet and no premine, and that is a check in the binary rather than a policy
somebody has to remember.
Nothing is minted for it. The faucet holds an ordinary key, signs an ordinary transfer through
the same wallet/session the command line uses, and pays one claim per block because a
certificate carries the state it read and two built against one reading of its cell would race.
Its balance comes from mining, so an empty faucet stays empty until somebody refills it.
Self-mining#
The route with no queue and no operator, and the same distribution mainnet gets:
zcd wallet new --out miner.json
zycordd --testnet --dir ./testnet \
--mine --payout $(zcd wallet address --key miner.json | awk '/^persistent/ {print $3}')
The payout must be a persistent (0x02) address — the
persistent line of zcd wallet address, which prints the next one-shot
address too — and zycordd refuses anything else rather than warning. Why.
coinbase_maturity is 100, so for roughly the first hundred blocks after your first
reward only miners can transact. That ramp is mainnet's and is part of what this network is
rehearsing — and it is the reason the faucet exists here and cannot exist there: the faucet
shortens the ramp for someone who wants to exercise a wallet, on the one network where shortening
it costs nothing.
Mining allocates the RandomX dataset — about 2 GiB, plus ~256 MiB per key epoch held. A machine that can verify comfortably cannot necessarily mine; the budgets are under Mining.
The testnet coins are worth nothing#
By design, and permanently. The network can be reset from genesis, which is what a testnet is for. Anyone offering to buy or sell them is running a scam that does not even need a story.
What this network is measuring#
It is not a demo. Four things it exists to produce numbers for:
- The key-change pause. At 512 blocks the RandomX re-key lands roughly every four hours instead of mainnet's seventeen, so the dataset rebuild is rehearsed often enough to measure rather than theorise about.
- Base-fee behaviour under the mainnet gas schedule, which is why the schedule is not adjusted here.
- The share of dialable nodes, which is the first reopen condition on the no-NAT-traversal decision.
- Era 1 under real load: sequencers, fills and the forced path on a live network, weeks before mainnet reaches its gate.
When something looks wrong#
Running a node has the diagnosis path for a node that will not sync, and the repair command for a data directory it refuses to start against. Findings and reproductions belong in the issue tracker; the project would rather have the report than the benefit of the doubt.