Start here/Run a node

Run a node

A pruned node validates everything and serves complete wallet history from the moment it first syncs. The one decision that matters is how far back you need to see.

gRPC16810loopback only
P2P listen16811no Kaspa clash
P2P dial16111where the seeders are
Node modes3pruned · +history · archival
Pruned node servescompletefrom its first sync onward

Ports, and coexisting with Kaspa

PurposeZKasKaspaNote
RPC (gRPC)1681016110bind to loopback; never expose
P2P listen / advertise1681116111the free "8" block — no clash with a Kaspa parent
P2P dial1611116111where the seeders and seed.zkas.info live

Only outbound access to a peer's P2P port is required to sync. Inbound is optional — it lets others sync from you.

kaspad --appdir=./zkas-node \
  --rpclisten=127.0.0.1:16810 \
  --listen=0.0.0.0:16811 \
  --utxoindex
Binaries ≤ v1.0.7 defaulted P2P to 16111 for both listen and dial, which collided with a Kaspa node on the same host. On those, bind P2P yourself with --listen. That changes inbound only; outbound discovery still dials 16111, so the node syncs normally.

Pruned, shielded-history, or archival

ZKas keeps two kinds of history — public block data and shielded note history — and they are pruned independently. This is the part people get wrong.

Pruned (default)+ --shielded-history=on--archival
Public block bodies below the pruning pointdiscardeddiscardedkept
Notes from before the node first syncednot fetchedfetched + keptfetched + kept
Notes from the node's first sync onwardall kept foreverall kept foreverall kept forever
Fully validates the chain and every spendyesyesyes
Serves balances complete since first syncyesyesyes
Serves balances complete back to genesisnoyesyes
Serves an explorer old public blocksnonoyes
Disklightlight + note archiveheavy

1. Pruned — the default, and what most people should run

Pruning deletes block bodies, UTXO state and acceptance data. It never touches the scan archive or the nullifier set — ZKas deliberately diverges from upstream here, and the reason is user funds. A pruned node keeps forever:

  • the shielded consensus state — note-commitment tree frontier and nullifier set, everything needed to validate every future spend;
  • the per-block scan archive — the compact note records a wallet replays to recover a balance, plus a chain index so they stay enumerable in chain order after the blocks are gone.

So a restore-from-seed against a plain pruned node returns a complete balance for everything at or after that node's first sync. Wallet recovery does not depend on an archival node existing somewhere.

The one gap: history from before the node ever synced. IBD seeds a fresh node with only the aggregate shielded state — a frontier plus a nullifier MuHash, which reveal nobody's notes — so there is no per-note archive below the initial pruning point. A wallet needing older notes reads a silently partial balance: the number looks final but is a lower bound. Clients must check missing_history and historyFromDaaScore.

2. --shielded-history=on — the wallet-backend shape

Controls whether the node fetches shielded note history below its pruning point from peers during IBD. With it on, the scan archive and chain index survive pruning, so the node serves wallets complete history while still discarding bulky public block bodies. This is the right node behind a zkas-walletd or a hosted wallet.

kaspad --appdir=./zkas-node --utxoindex --shielded-history=on --verify-shielded-history

Default: on when --archival is set, off otherwise.

3. --archival — keep everything

kaspad --appdir=./zkas-node --utxoindex --archival --rocksdb-preset=hdd
  • Archival only retains from now forward. Enabling it on an already-pruned node does not backfill what was pruned before. A complete archive means enabling it on a node syncing from genesis, or importing a full-history snapshot.
  • It is heavy on disk. On spinning disks add --rocksdb-preset=hdd.
  • Archival is not required for validation or mining. A fresh non-archival node still syncs genesis→tip to byte-identical state.

Flag reference

Every node flag13 rows
Flag (env)What it does
--appdir=<dir> (KASPAD_APPDIR)data directory
--rpclisten=<ip:port>bind the gRPC RPC. Keep on 127.0.0.1
--listen=<ip:port>P2P listen/advertise address
--connect=<ip:port>connect only to these peers (repeatable); skips the DNS seeder
--addpeer=<ip:port>add a persistent peer but still discover others (repeatable)
--utxoindex (KASPAD_UTXOINDEX)build the UTXO index; needed for some RPCs
--archival (KASPAD_ARCHIVAL)retain public block data past the pruning point
--shielded-history=on|offfetch shielded note history below the pruning point
--verify-shielded-historyverify transferred shielded history during IBD
--rocksdb-preset=default|hddstorage tuning; hdd for archival on spinning disks
--ram-scale=<f>scale in-memory caches, e.g. 2.0 on a large box
--enable-unsynced-miningbootstrap only, for a brand-new network with no peers. Never on a pool mining the live chain
--wallet-apiembed zkas-walletd with auto-provisioned TLS and a pairing QR — see self-hosting

kaspad --help lists the complete set.

Why history from a peer is trustworthy

Backfill is cryptographic, not reputational. The tree frontier is a pure function of the leaf sequence, so replaying every cmx from genesis must reproduce exactly the frontier the node already holds — a value it never learned from the serving peer. A peer that fabricates, omits, reorders or truncates cannot match it. Completeness is established by that verify pass, which sets the history_complete flag; an offline import does not set it.

Two RPC fields expose this to clients: historyFromDaaScore (oldest height this node can serve) and historyComplete (can enumerate to genesis). See Node RPC.

Recovery and common faults

Node will not start, corrupt DB
Stop it, move the appdir aside, resync from a peer. A pruned node resyncs quickly; snapshot an archival node rather than resyncing it.
Balances look low for old coins after a resync
The node is pruned and was not given --shielded-history=on, so it lacks notes from before its first sync. Coins received since are complete; older ones read as a lower bound. Re-run with shielded history enabled and let the wallet rescan.
invalid prefix zkas / invalid prefix kaspa
Address HRP does not match the node's network. A pre-rebrand node does not know zkas:; a Kaspa node never will.
Wallet stops updating after a node restart
zkas-walletd points at the local node and does not reconnect. Always restart walletd after touching the node.
Node wedges under load after a hardlink snapshot
Stop → snapshot → start under load can wedge template building. Take snapshots cleanly, then restart the node and any solo bridge.
Verified against zkas-rusty at zkas-v1.0.9. Byte layouts, endpoint shapes and parameters are read from source; figures marked measured come from the live mainnet node. If this page contradicts the code, the code is right — report it.