Use this page to size a machine before you run one. A validator is cheap. Proving is not: a proof’s memory grows steeply with its tier, and it is the one number that decides whether a machine can do the job. Every figure here is a measurement from the testnet or the fullnode’s records. Figures that are not final are marked.
What each role does
| role | what it does | runs | proves? |
|---|---|---|---|
| validator | orders transactions, verifies every proof in every block, votes in HotStuff | rand-node run --validator | no |
| observer | syncs, re-verifies every proof, serves JSON-RPC; no vote | rand-node run | no |
| prover (a wallet) | proves its own bundles and calls locally, then submits them | rand send, rand call, rand program deploy | yes, every transaction |
| delegated prover | makes the bundle proof for a wallet paired with it; since chain 20 it is sent that wallet’s viewing key, never the spend key | rand-prover run, or rand-node run --prover | yes, bundle proofs only |
| aggregator | proves one recursive proof over a window of bundle proofs, for a sealing block | rand-node aggregate --watch | yes, the largest proofs |
| build host | compiles rand-node and rand and hands the binaries to small nodes | cargo build --release | no |
Validators and observers never prove. A shielded transfer or a call is proved by the wallet that sends it, or, for the bundle proof alone, by a prover that wallet is paired with (Running a node). The fleet’s validators do not prove anything today.
Block aggregation is built but not active. It needs an aggregation section in the genesis. Chain 21 has none: aggregation is off, as on chains 9 to 20, and the build refuses to start on a genesis that carries the section.
Sizing at a glance
| role | RAM | CPU | disk |
|---|---|---|---|
| validator or observer | 2 GB (the original fleet); a validator also needs a synchronised clock (clock) | 1 vCPU (most of the original fleet) | with --prune-history 24h, about a day of blocks: block tables of 3.3–4.4 GB measured on chain 14; keep more than 4 GB free (disk) |
| archive (full history) | as a validator | as a validator | grows with the chain: about 3.6 GB a day measured for chain 14’s 18-signature QCs at 1.4 s blocks, more on chains 18 to 20, whose QCs carry up to 26 signatures, which has not been re-measured; the testnet’s two archives sit on 250 GiB volumes |
| build host | 8 GB (node E) | 4 vCPU (node E) | the source tree, target/, and at least 20 GB free |
| prover, shielded transfer (tier 14) | 6.1 GB peak for a transfer on chain 18, 6.1 to 6.6 GB for a call with its paying bundle (2026-09-30) | one core; on chain 18 two proofs, the tier-14 bundle proof in 102 to 134 s and the tier-10 authorisation proof in 7 to 23 s (Apple Silicon laptop, 2026-09-30); about 100 s for the 4-in-4-out hidden-asset bundle alone on chain 14; 92.2–96.0 s measured on a laptop for chain 13’s 2-in-2-out bundle (production, 2026-09-19) | small |
| delegated prover | 5.74 GB for each proof it runs at once, plus 1 GiB of headroom; it refuses to start with less available | one core per proof | small |
| prover, tier-18 call (the ERC-20; refused on chain since v0.5.6, see Proving memory) | 85.0 GB (translated transfer) / 85.5 GB (interpreted), measured on m-16vcpu-128gb | one core | small |
| prover, tier-20 call (SPL Token; refused on chain since v0.5.6) | not yet proven; extrapolated at about 330 GB, more than DigitalOcean’s largest memory droplet (m-32vcpu-256gb, 256 GB) | one core | small |
| aggregator, N = 1 | at least 64 GB was the bound before the 2026-09-28/29 runs; see Aggregators | CPU today | as a validator |
| aggregator, N = 2 / N = 3 | 133 GB / 221 GB measured under constraint set 7 (2026-09-28/29) | a GPU node for production N ≥ 2 | as a validator |
The prover is single-threaded today. A 16-vCPU droplet ran at 99% of one core. More cores do not make one proof faster; more RAM decides whether it finishes.
Validators and observers
Memory and CPU
The original eighteen validators run on 2 GB droplets. Verifying a proof is cheap:
| operation | cost |
|---|---|
| verify a bundle proof, warm verifier key | about 16 ms |
| the first verify at a new shape | about 230 ms |
| build a deployed program’s verifier key (once, in the background) | about 7 s on a 2-vCPU server |
| verify one aggregate proof (when aggregation is active) | about 0.8 s cold, about 16 ms warm (design figures) |
The memory a validator needs to verify a tier-18 or tier-20 call proof is now partly measured, on a 48 GB Apple-silicon laptop, independently of the DigitalOcean droplet that produced each proof: verifying the tier-18 transfer proof took 50.2 s at 3.66 GB peak RSS (translated) or 49.6 s (interpreter, RSS not separately recorded); verifying the tier-16 approve proof took 12.2 s (RSS not separately recorded). Tier 20 is not measured — no tier-20 proof exists yet to verify. Since v0.5.6 a validator never builds a key that large: a call proof’s header is checked before any verifier key is built, and a call above tier 14 (or with a keccak table above 2^12, or a sha256 table above 2^13) is refused, at admission and as a block-validity rule. The worst admissible call header measured 4.7 s and 312 MB to verify.
A 1-vCPU, 2 GB droplet cannot build the binaries. Build on a larger machine and copy them (see setup).
Disk
| figure | value | source |
|---|---|---|
| an idle chain-14 block, before v0.5.5 | about 60 KB in blocks plus about 49 KB in qcs: the 18-signature Dilithium2 QC stored twice, about 6.6 GB a day at 1.4 s blocks | the 2026-09-24 disk incident, AGENTS.md |
| the same block since v0.5.5 | about 60 KB: a committed block’s QC is stored once, in its child’s justify; about 3.6 GB a day at 1.4 s blocks | docs/deploy.md, roll note for v0.5.5 |
| RocksDB write-ahead log | capped at 256 MB since the 2026-09-24 fix; before it, 13 GB of unpurged log per validator | AGENTS.md |
a chain-14 validator after --prune-history 24h drained (2026-09-25) | block tables 3.3–4.4 GB, from 19 GB; disks 18–37% used | AGENTS.md, v0.5.7 |
| node A’s data directory, chain 12 at height 62,276 | about 10 GB | deploy/README.md, the v0.3 rollout |
| a chain that runs full blocks | 4 MiB every 2 s, about 170 GB a day (the block cap of chains up to 12; chain 20’s was 20 MiB, chain 21’s is 19 MiB) | docs/block-space.md |
| free space the fleet keeps for builds | at least 20 GB | docs/block-space.md |
| a 30 GB disk holding three chains’ data directories | full; RocksDB No space left on device, crash loop | mkc1 and mem1, deploy/README.md |
On chain 21, as on chains 19 and 20, 24 of the 26 validators run --prune-history 24h and keep about a day of blocks; the ledger itself (notes, nullifiers, anchors, the register) is never pruned. The archives, obs1 and rand-archive-2 (both also validators), run without the flag. A mainnet node never passes it. The node refuses to start with less than --min-free-disk-mb (1,024 MB by default) free on its data directory’s filesystem, and rand_getHealth answers disk_low under four times that; a roll that waits on ok stops at a node that is filling up. See History pruning for what a pruned node still answers.
Delete a retired chain’s data directory after a cut-over. Data directories are keyed on the genesis hash (data-<name>-<hash8>: -ca76c276 for chain 21, -6210cf07 for chain 20; the six guardian hosts use /var/lib/randnode/data-21), so old ones stay until you remove them. At the chain-20 cut one regional validator (syd1) came up disk_low with 3.9 GB free and held the start at 25 of 26, because chains 14 to 17’s directories were still on it; deleting them freed 22 GB. Keep the previous chain’s directory for a day as the rollback target, then remove it. At full blocks each raw bundle proof is about 1.42 MB since chain 14 (about 1.3 MB up to chain 13). Since chain 17 every bundle also carries an authorisation proof, so a transfer is about 2.85 MB of proofs: about 1.49 MB for the bundle proof and 1.36 MB for the authorisation proof (production profile, measured 2026-09-29). Aggregation, once active, prunes a sealed bundle’s proof to about 3 KB, unless the node runs with --keep-raw-proofs. It does not cover the authorisation proof, which stays at full size.
Network
Open TCP 30303 inbound on a public node. Nodes behind NAT dial out with --bootstrap. At full 4 MiB blocks a validator link carries about 2 MB/s.
Clock
A validator needs NTP. Chain 14 is the first chain on which wall-clock time is part of consensus (bridge hardening B2):
| rule | bound | kind |
|---|---|---|
| a block’s timestamp may not be more than this far past its parent’s | 60 s (MAX_TIMESTAMP_STEP_MS) | validity rule; the block is invalid (BlockError::TimestampLeap) |
| a validator does not vote for a block whose timestamp is more than this far ahead of its own clock | 15 s (MAX_CLOCK_DRIFT_MS) | vote rule |
A validator whose clock is 20 s slow silently stops voting: it sees every honest block as ahead of its clock and withholds its vote, and nothing fails. On chain 21, as on chain 20, eighteen of twenty-six must vote to commit anything. Check every validator, and install chrony where the clock is not synchronised:
timedatectl # want "System clock synchronized: yes" and "NTP service: active"
chronyc tracking 2>/dev/null || timedatectl show-timesync --all 2>/dev/null
apt-get install -y chrony && systemctl enable --now chrony
The same 15 s bound applies to a genesis. Set timestamp_ms close to the launch time and never ahead of it: a genesis more than 15 s in the future commits no block 1 until wall time reaches it, and one far in the past leaves block time behind wall clock, catching up at no more than 60 s per block (docs/deploy.md). An observer does not vote, so the vote rule does not bind it.
DigitalOcean sizes the testnet runs on
| size | RAM, vCPU, disk | nodes | notes |
|---|---|---|---|
s-1vcpu-2gb | 2 GB, 1 | most regional validators (ams3, nyc1, nyc2, sfo2 among them) | cannot build; binaries are copied in |
s-1vcpu-2gb-amd | 2 GB, 1 | atl1 | as above |
s-2vcpu-2gb-intel | 2 GB, 2 | D (ric1) | |
s5-1vcpu-2gb-30gb | 2 GB, 1, 30 GB | mkc1, mem1 (the only small size there) | disks were full (29 GB) at the chain-13 cut-over; 7 GB free after the dead chain-11 data dirs were deleted; need a resize |
| 4 vCPU, 8 GB | 8 GB, 4 | E (sgp1) | validator, build host and explorer |
This table covers the original eighteen validators. Since 2026-09-27 validator A runs on a droplet too (sgp1), not a laptop. Eight more validators were bonded on chain 15 (2026-09-27): the two archives, obs1 and rand-archive-2 (fra1), and the six guardian hosts. Their droplet sizes are not recorded here, and neither is whether mkc1 and mem1 were resized. All 26 are genesis validators on chain 21, as on chains 19 and 20, at 1,000 RAND each, and as of 2026-09-30 all 26 keys are held by one operator.
Proving memory
The wallet proves every transaction it sends, so the caller of a program needs the memory for that program’s tier. These are the measured bounds. The tier-18 runs have finished, proved and verified on DigitalOcean; tier-20 has not. Since v0.5.6 the chain refuses a call proof above tier 14 (MAX_CALL_TIER), so the tier-16, 18 and 20 rows below are measurements, not calls chain 21 admits (a perp state proof and the private-multisig auth proof, both tier 18, are chain-21 exceptions: neither is a call); every call committed on chain 14 was tier 10.
| workload | tier | cycles | what was measured | needs |
|---|---|---|---|---|
shielded transfer (the bundle guest) | 14 | about 9,160 on chain 13 (the 2-in-2-out guest) | 92.2–96.0 s on an Apple Silicon laptop (production, chain 13, 2026-09-19); peak memory not recorded. Chain 14’s 4-in-4-out hidden-asset guest is pinned to the same tier: about 100 s and a proof of about 1.42 MB. Since chain 17 a transfer is two proofs (split authorisation): the tier-14 bundle proof, 102 to 134 s and about 1.49 MB, and a tier-10 authorisation proof, 7 to 23 s and about 1.36 MB. Peak memory 6.1 to 6.6 GB for a whole transaction (Apple Silicon laptop, chain 18, 2026-09-30) | runs on the development laptop |
ERC-20 approve (production, on chain 13, 2026-09-19) | 16 | 48,119 | call proof 388.7 s, 3,412,405 bytes; the whole rand call 622.8 s at 22.9 GB peak RSS on a 48 GB M-series laptop | a 48 GB laptop |
| ERC-20 calls | 18 | about 66k to 162k | the stage-one transfer (79,203 cycles, before the code guard) was SIGKILLed on a 48 GB laptop at 24.7 GB after 1,016 s; a 64 GB droplet run was above 47 GB at 25 minutes | 85.0 GB (translated) / 85.5 GB (interpreted) peak RSS, 3,230.5 s / 3,143.3 s prove time, 811,600 / 805,108-byte proofs. Measured on m-16vcpu-128gb, 2026-09-19 |
| SPL Token vectors | 20 | about 700k to 770k | the translated Transfer (692,854 cycles, before the ELF guard) was stopped on a 48 GB laptop at 30.77 GB after 225 s, still proving; a tier-20 run was OOM-killed on a 64 GB droplet at 65.1 GB after 10 m 41 s | not yet proven; extrapolated at about 330 GB and about 3.6 h (measured tier-16/18 scaling: memory about ×3.9, time about ×4.1 per +2 tiers) — more than DigitalOcean’s largest memory droplet (m-32vcpu-256gb, 256 GB) |
| rVM tier-21 production exit (one bundle proof verified inside the recursion VM) | 21 | 1,968,619 rows | derived requirement 48.6 GB before it was run; under constraint set 7 it needed more than a 256 GB droplet had (2026-09-28/29) | more than 256 GB; not re-measured under constraint set 8 |
The ERC-20 calls land at tiers 16 and 18 and SPL Token at tier 20 (Ethereum, Solana). No proof at tier 18 or 20 has been made on a 48 GB machine.
Aggregators
An aggregator watches the chain, takes the bundle proofs of a window of finalised blocks, proves one recursive aggregate over them, and submits it. The block that includes it is a sealing block. The aggregator is paid the covered bundles’ proving share plus a block subsidy in new RAND, to its registered payout address. Aggregation is permissionless: any operator with a bond can register.
It only exists on a chain whose genesis has an aggregation section. Chain 21 has none, and its build refuses to start on a genesis that has one.
Hardware
| aggregate | host RAM | backend |
|---|---|---|
| N = 1 bundle | at least 64 GB | CPU; the test profile proved one in about 26 minutes on a loaded laptop (327,035 bytes) |
| N = 2 | 133 GB measured; the earlier bound was at least 128 GB | the GPU backend for production |
| N = 3 | 221 GB measured; the earlier bound was at least 160 GB | the GPU backend for production |
| the fleet GPU node | at least 160 GB host, an 80 GB device (H100 or A100-80G) | Linux, R580+ driver, CUDA 13, LLVM 21, sm_80+; none exists yet |
The N = 2 and N = 3 figures were measured on a 256 GB DigitalOcean droplet on 2026-09-28/29, under constraint set 7, and the production exit proof needed more than that machine’s 256 GB. None has been re-measured under constraint set 8, which chains 18 to 20 run, so treat the N = 1 row as a lower bound. The CUDA backend first ran on real hardware on 2026-09-28, on an NVIDIA H100: its kernels build to PTX for sm_80 and sm_90 and match the CPU reference. The production measurement on a fleet GPU node is still to do. Every node also pays a one-time startup key-build for the aggregate program: 13.0 to 13.4 s at the test profile (2¹⁹), and an expected 30 to 70 s at production (2²¹).
Commands
# print a signed registration; the bond burns out of a wallet bundle as the register bundle's burn
rand-node aggregator register --key agg.key.json --bond <RAND> --payout rand1… --rpc http://127.0.0.1:8545
# the daemon: poll rand_getUnsealed, fetch the raw bundles, prove, seal the payment note, submit
rand-node aggregate --key agg.key.json --rpc http://127.0.0.1:8545 --watch
# leave, then withdraw the released bond into a note at the payout address
rand-node aggregator unbond --key agg.key.json --rpc http://127.0.0.1:8545
rand-node aggregator withdraw --key agg.key.json --rpc http://127.0.0.1:8545
aggregate flag | default | meaning |
|---|---|---|
--key | required | the aggregator key the register knows; signs every aggregate |
--rpc | http://127.0.0.1:8545 | the node to poll and submit to |
--watch | off | keep polling instead of submitting once |
--interval-secs | 15 | poll interval with --watch |
--no-wait | off | return once the node accepts the aggregate |
rand status shows an aggregation section on such a chain: registered aggregators, unsealed blocks and the subsidy schedule index. rand_getUnsealed is the work list.
Setup
These steps follow the scripts the testnet uses (deploy/vps-setup.sh, deploy/update-droplet.sh). They make a Linux validator or observer.
1. Build on a build host
The build needs build-essential clang cmake pkg-config libssl-dev, Rust 1.98.1 (pinned by rust-toolchain.toml), and a circuits checkout beside the fullnode checkout. The first build takes 10 to 20 minutes.
git clone https://github.com/randprotocol/fullnode
git clone https://github.com/randprotocol/zkp-circuits circuits
cd fullnode
git checkout v0.8.0 # c0878c3f, the build chain 21 runs
git -C ../circuits checkout "$(sed -n 's/^circuits: //p' crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md)" # d217252 for v0.8.0
git show origin/main:deploy/genesis-chain20.json > deploy/genesis-chain20.json # committed after the tag
cargo build --release -p randprotocol-node -p randprotocol-client
sha256sum target/release/rand-node # compare on every node you copy it to
Chain 21 needs v0.8.0 on every node before init. It runs constraint set 9, under which every verifier key and every proof’s encoding changed, so the build refuses chains 18 to 20 and no earlier build runs chain 21; its genesis also carries sections no earlier build reads (fees, perps, multisig, hc_auth_multisig). An authorisation proof still rides beside every bundle proof (hc_auth), and the private-multisig guest’s pinned verifier key, msauth-vk-production.bin from the release (SHA-256 68facb06…cd30), must sit beside rand-node on every node, or run and verify refuse to start. Run the one build the fleet runs. The genesis file is on the fullnode’s main (commit 246cb5f9), not in the v0.8.0 tag, hence the third git line. The circuits checkout must be at the commit the release was vendored from, which the second git line above reads out of the fullnode tree. Add -p randprotocol-prover to build rand-prover as well.
2. Install the binaries on the node
scp target/release/rand-node target/release/rand deploy/genesis-chain20.json root@<node>:/root/
ssh root@<node> 'install -m 755 /root/rand-node /root/rand /usr/local/bin/'
3. Key, genesis, firewall
On the node:
install -d -m 700 /root/keys
test -e /root/keys/node.key.json || rand-node keygen --out /root/keys/node.key.json # prints the address; keep the seed secret
rand-node init --datadir /root/data-6210cf07 --genesis /root/genesis-chain20.json
timedatectl # "System clock synchronized: yes" (see Clock)
ufw allow 22/tcp && ufw allow 30303/tcp && ufw enable
Generate the key on the node, as above, and keep it out of any checkout. No key is tracked in the fullnode repository any more (audit v3, OPS-1). The deploy/node-*.key.json files committed for chains 8 to 13 are published seeds; chain 21’s validator keys (the eighteen generated for chain 14 and the eight bonded on chain 15, carried through every cut since) were generated off-repo, and the fleet keeps each droplet’s key in /root/keys/node-<name>.key.json, outside the source tree. The location matters on a node provisioned by the fleet’s scripts: deploy/rebuild-vps.sh and deploy/push-to-vps.sh rsync /root/fullnode with --delete, so a key kept inside that tree is deleted by the next rebuild and the unit then fails to restart. Since v0.6.8 keygen refuses to overwrite an existing file (v0.6.7 overwrote it without asking); the test -e keeps the line safe to re-run either way. Back the key up off the host before bonding it.
init prints the genesis hash. It must read ca76c2766ed6090ac6ba5dad86b724dd5d2b80c0edfaed287cd8b129e663ca9a (chain 21). The genesis file is genesis-chain21.json in the fullnode repository’s deploy/ on main. Name the data directory after the first eight characters of the hash, as the fleet does (data-<name>-ca76c276), so it never collides with chain 20’s (-6210cf07) or a later chain’s. The genesis sets these limits. The proof cap was 8 MiB on chains 13 to 16, 4 MiB on chains 17 to 20, where a transaction began to carry up to three proofs, and is 6 MiB on chain 21 for the tier-18 multisig auth proof; the block cap came down from 20 MiB to 19 MiB with it:
| limit | chain 21 |
|---|---|
max_program_words | 65,535 |
max_proof_bytes | 6,291,456 (6 MiB; 4 MiB on chains 17 to 20) |
max_block_bytes | 19,922,944 (19 MiB; 20 MiB on chain 20) |
max_call_envelope_bytes | 65,536 |
max_program_public_words | 32,768 |
envelope_bytes | 1,860 (every note envelope, with its encrypted memo field) |
proof_window_blocks | 1,024 (as on chain 20; 256 on chain 19) |
program_state | cell fee 0.01 RAND (10,000,000 units); at most 8 reads, 8 writes and 4 payouts per invoke |
fees | burn_base and burn_floor: every bundle’s settled floor is burned, the proposer keeps the tip |
perps | one market, BTC-PERP on zUSD (asset 1): state proofs at tier 18 over at most 64 blocks, at most 24 perp inputs a block, 1 zUSD minimum deposit |
multisig | create_fee 1 RAND, at most 10 signers and 4 payouts; one genesis account, the treasury (2 of 3, 100,000 RAND) |
hc_auth_multisig | 9705f8e2…8247, the private-multisig auth guest (tier 18); its verifier key must sit beside every node’s binary |
aggregation section | none (aggregation off) |
Chain 21’s genesis also carries consensus_domain: 1, binding_domain: 1, testnet: true, a staking section with admission by vote, a gas section with price ceilings and a 9,961,472-byte target, the bridge’s rotation and fees groups, hardening_v6 and the guest pins hc_bundle and hc_auth; Running a node lists what they set.
4. A systemd unit
This is the unit deploy/vps-setup.sh writes, with the paths above:
[Unit]
Description=RAND full node
After=network-online.target
[Service]
Environment=RUST_LOG=info,libp2p=warn,libp2p_mdns=off
ExecStart=/usr/local/bin/rand-node run --datadir /root/data-6210cf07 --key /root/keys/node.key.json --validator --listen /ip4/0.0.0.0/tcp/30303 --rpc 127.0.0.1:8545 --no-mdns --prune-history 24h --bootstrap <multiaddr> --bootstrap <multiaddr>
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Drop --validator for an observer. --prune-history 24h is what the testnet’s validators run, except the archives; drop it for a node that keeps full history, and never pass it on mainnet. The bootstrap multiaddrs for chain 21 are nodes C (fra1), D (ric1) and E (sgp1), unchanged since chain 19. Chain 21 runs on the validator keys generated for chain 14, and a p2p identity is derived from the validator key, so these peer ids are the ones chain 14 used. A new node syncing from genesis also needs a full-history peer, so add one of the two archives (obs1, then rand-archive-2):
/ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe
/ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw
/ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ
/ip4/168.144.46.203/tcp/30303/p2p/12D3KooWS5usdMPvsbaWSaT2xtKndHvDYurwmueoNvaRRarb2wRf
/ip4/206.81.29.236/tcp/30303/p2p/12D3KooWPocyZGcNB9Vp68VSfgVvNXhSzBBoJa4h9R1yMkp71XHh
Keep the RPC on 127.0.0.1 unless a firewall protects it. A node that should serve the public opens the public listener (since v0.6.8) beside it (--public-rpc <ADDR>) and puts a proxy in front of that, never in front of --rpc (JSON-RPC). A unit carried over from v0.6.7 must not pass --prover-accept-spend-key, which v0.6.8 refuses at startup.
systemctl daemon-reload && systemctl enable --now rand-node
journalctl -u rand-node -f
rand status # height climbing, peer_count rising
5. Join the validator set
A new key is not in any epoch’s set. On chain 21, as on chain 20, it must first be voted in: the genesis sets staking.admission_by_vote, so validators holding more than two thirds of the voting weight each sign it with rand-node admit sign --candidate <key or registration> --key <validator key> --genesis-hash <chain 21's hash>, and one submits the votes with rand-node admit submit; rand_getAdmitted then lists it. Then bond at least 1,000 RAND to it: print a registration with rand-node register --key /root/keys/node.key.json --payout rand1… --v2 (chains 20 and 21 refuse a v1 registration), then bond from a wallet with rand bond <address> 1000 --registration <hex>. The bond waits for its activation epoch, three 1,000-block boundaries after it commits at the earliest, and at most 2,500 bps of the active weight becomes new weight per boundary (chain 19 capped it at a fixed 10,000 RAND). Staking walks through it.
6. Updating
This applies to a build that runs the same chain. Moving from an earlier chain to chain 21 is not an update: it needs the new binary, the new genesis and a fresh data directory, and the old chain’s data directory can be deleted afterwards (deploy/retire-chain-dirs.sh; the fleet keeps it a day for rollback). To roll a new build without a chain cut, build once, compare the sha256 of both rand-node and rand, stop the service, install, and restart, one node at a time. Some releases are rolled all-stop, all-start instead (v0.5.6’s call-tier rule, v0.5.7’s Status wire change, v0.6’s stricter proof verification); each release’s notes say which. v0.6.7 rolled onto chain 18 one node at a time; v0.6.8 came with chain 20, all-stop, all-start, because its CON-4 and CH-1 consensus changes must never roll node by node; v0.7.0 and v0.7.1 rolled onto chain 20 one node at a time; v0.8.0 came with chain 21, all-stop, because constraint set 9 cannot run chain 20. Wait for each node to rejoin before the next, so the quorum is never short by more than one. deploy/update-droplet.sh <ip> [build-host] does exactly this over SSH, and deploy/roll-all.sh rolls the whole fleet from a signed release, installing the msauth verifier key beside the binary. A build that changes the gossip wire, as v0.8.0’s compact blocks did, is rolled observers and archives first and then every validator at once: a mixed validator set can stop committing. Since v0.8.0 a restart of the same clean build skips the startup chain walk (the startup checkpoint); --verify-chain replay forces it.
The releases up to v0.6.8 were built by hand on one host and are unsigned. From v0.7.0 (2026-10-01) every release is built by the release workflow from the tag, CI-gated and --locked, and its SHA256SUMS is signed by the release key (SHA256SUMS.sig); deploy/update-droplet.sh and deploy/roll-all.sh verify the signature before installing and refuse an unsigned release unless ALLOW_UNSIGNED=1 is set. The v0.8.0 release carries rand-node, rand, rand-prover, msauth-vk-production.bin, SHA256SUMS and SHA256SUMS.sig; the checksums are listed on Running a node.
Chains 15, 16, 17 and 18 went live within 2.7 days (2026-09-26 to 2026-09-29), each an all-stop of the fleet. Chain 19 followed on 2026-10-01 at 03:43 UTC, a re-genesis of chain 18 on the same build, and chain 20 the same day at 06:17 UTC, cut from a snapshot of chain 19 at the v0.6.8 hard fork; every node stopped at chain-19 height 7,700. Chain 21 followed on 2026-10-12 at 10:31 UTC on v0.8.0, cut from chain 20’s bridge state at height 814,702 and a balances scan of the operator’s wallets, carrying the 26 validators, the bridge and 100.001999 zUSD (equal to the custody locked on the four backings), 3,938.879078887 RAND of operator balances and, as new issuance, the 100,000 RAND treasury, and dropping about 36,025 RAND of chain 20’s pool held by wallets the operator does not hold, the eleven other tokens registered on chain 20 and every program’s state. A written cut policy (2026-09-30) applies from chain 20 on; both chain 20’s and chain 21’s cut records waived the second operator’s rebuild, because one operator holds every key. A cut needs a reason a rolling update cannot meet, a published list of what it carries and what it drops, a client rebuild checklist done beforehand, a second operator who rebuilds the genesis to the same hash, a rollback plan, and a chain id never used before.