Parallax v2.0.0 is the first release of the 2.x line. These notes cover everything since v1.2.0, including the four release candidates.
A note up front: every Go import path has changed. If you depend on Parallax as a library, your build will break until you update the paths.
What's new
P2P / networking
I've rewritten the discovery and handshake stack. The relevant pieces:
- A v2 RLPx handshake along the lines of BIP324, wired into the Server. The client runs both v4 (UDP) discovery and the new TCP-based discovery by default and prefers the TCP path; v4 stays on for backwards compatibility. UDP discv4 will be fully deprecated in a later release. The longer-term motivation for moving discovery off UDP is to open the door to native Tor integration, so node operators and tx broadcasters can run with better privacy and anonymity.
parallax-disc/1, a gossip discovery subprotocol. It uses the new address manager as its backend, with quorum and rate limiting on top. Address relay follows Bitcoin Core's ADDR gates: an exact-parity token bucket on ingest, fan-out with a daily-rotating PRF, reduced fanout for unreachable-network addresses, and a rolling known-address filter.- A new address manager (
addrman), ported from Bitcoin Core's bucketing design and audited against the pinned reference (Core v31.0): bucketed, persisted across restarts, dual-stack aware, and source-aware when picking peers. Five sources are tracked (tcp_gossip,legacy_udp,dns_seed,manual,self_advertised) and feed bothSelect()weighting and source-aware bucket eviction. Long-lived outbound sessions re-stamp their entries so healthy peers don't age out, and the node's own identity refreshes from first-hand outbound sessions. - ENR-driven dialing for v2, ip:port bootnodes, dedup of v2 peers on
(IP, port), and up to 4 concurrent inbound attempts per IP. --dnsseedfor plain-DNS seed consumption (default seed isseed.prlxdisc.org, port32110).--legacy-discovery=[auto|on|off]is the single operator knob for the v1.x compatibility surface (UDP discv4 responder + legacy RLPx accept). Default isauto;offis fully v2-only.- DNS-seed publisher under
cmd/devp2p dns-seedwithcompile,to-zonefile,to-cloudflare,to-route53subcommands. Consumes crawler JSON, filters to default-port v2.0-native entries, and reconciles A/AAAA records idempotently. Theparallax-disccrawler is a multi-hop stateful walker that always probes v2, judges seed candidates by bitcoin-seeder-style reliability windows, and evicts unreachable nodes from its state.
Peer management
Alongside the transport work, v2.0 ports Bitcoin Core's peer-management machinery:
- Bitcoin Core's inbound eviction algorithm, triggered on inbound saturation, with protection slots (including localhost peers) and deterministic tie-breaking. Per-peer quality telemetry feeds it: ping RTT, payload bytes received, and last-block / last-tx receipt timestamps.
- Outbound network-group diversity is enforced on every dial path, including v2, block-relay, and anchor dials. 6to4 and Teredo addresses group by their embedded IPv4 /16.
- Feeler and addrfetch dial loops keep the address manager tested and fresh. Feelers never join the peerset, never receive pool announcements, and can't reach snap serving.
- Block-relay-only outbound peers, with anchor persistence on by default. The (IP, listen-port) of currently-connected anchor peers is written to
<datadir>/anchors.daton clean shutdown and replayed on next startup, mirroring Bitcoin Core'sm_anchors. Disabled whenMaxBlockRelayPeers=0. Block-relay peers that send transactions are disconnected. - A persistent ban list (
<datadir>/banlist.json) backsadmin_setban/listbanned/clearbanned, surfaced asparallax-cli setban,listbanned,clearbanned, with argument semantics matching Bitcoin Core (subnet bans included). The inbound-accept path rejects banned source IPs before the handshake, outbound dials refuse banned or discouraged addresses, and misbehavior during a session adds the peer's IP to a rolling in-memory discourage filter consulted under inbound saturation. Trusted, static, and local peers are exempt from discouragement. MinLegacyPeersfloor (default 2): hard-capstcp_gossip-sourced peers atMaxPeers - 2while non-tcp_gossip alternatives are reachable, so a v2.0-specific bug can't take down 100% of peers during early v2.x. Removed at v3.0 alongside the legacy transports. Set negative to disable.
Daemon mode and commands
There's a proper headless daemon mode now, with start, stop, status.
A fair number of commands moved into parallax-cli: chaininfo, netinfo, mempool-content, getblockhash, getheader, tip, balance, nonce, code, storage, estimategas, addpeer, removepeer, addtrusted, removetrusted, mining, startmining, stopmining, setcoinbase, setextra, loglevel, trace, dbstats, decoderaw, toaddr, account, newaccount, listaccounts, lock, unlock, sign, sendtx, uptime, setban, listbanned, clearbanned. Also addnode, addrbook, and the parallax-disc crawler.
Trusted peers receive full blocks rather than just headers.
RPC
New: net_peers, admin_uptime, dbstats, admin_setban / admin_listbanned / admin_clearbanned. New addrman-backed admin RPC: admin_addnode, admin_removenode, admin_addrbookStatus, admin_addrbookResetKey (surfaced as parallax-cli addnode, removenode, addrbook status, addrbook reset-key). addnode accepts both ip:port (v2-native) and enode://nodeID@ip:port (legacy) and stores entries with source=manual so they survive restarts and outrank gossip. admin.uptime and admin.stop are registered on the console.
admin.peers: the handshake variant is exposed (v2 vs legacy+v2). Enode/ENR/ID marshal as null for v2 sessions, but the session-scoped ID is still visible. admin.nodeInfo follows the same rule in v2-only mode, and ports.discovery mirrors the TCP port when UDP is disabled. admin_addPeer/admin_removePeer branch on input format and reject enode:// inputs in v2-only mode.
Removed
- The light client (LES) is gone. All
--light.*and--ultralight.*flags, theLightSyncmode. If you ran a light node, you'll need a full or snap-syncing node now. discv5and--v5discare gone.- The deprecated
--nousb,--whitelist,--miner.gastarget,--show-deprecated-flagsare gone. - The GUI (
prlx-gui) moved to its own repository.
Testing and hardening
v2.0.0 ships with a substantially expanded test program:
- All fuzzers migrated from go-fuzz to native
testing.F, with shared corpus seeding. New fuzz targets across the tree: addrman persistence, netlist parsing, disc Hello round-trip, v4wire/ENR/enode codecs, v2 AEAD framing, hexutil JSON, transaction codecs, fork ID, keystore decrypt, calldata and selector parsing, ASERT difficulty, and the fee estimator'stxConfirmStats. - New stress tests: transaction-pool load, deep/shallow/randomized sidechain reorgs, and concurrent state-snapshot reads with reverts.
- CI now runs race, coverage, and conformance jobs plus a sharded nightly fuzz smoke, and release branches (
N.N.x,v*) get the full build / lint / unit-test lanes.
The fuzzers found real bugs, fixed in this release (see Fixes below): the supply-reporting era math, a selector-parser panic, and unbounded keystore KDF parameters.
Fixes
kernel/xhash: the reported total supply dropped the entire first era's emission once height passed 210000 and mishandled era boundaries past the first halving. Supply is now computed by exact per-era summation, with drift tests, and coinbase maturity is read from the chain config. Reported (not consensus) values change.script/abi:ParseSelectorno longer panics on a missing parenthesis, and rejects top-level array suffixes.wallet/keystore: decrypt now validates KDF params, IV and ciphertext lengths, and bounds scrypt/pbkdf2 cost parameters, so a malicious keystore file can't crash the process or blow up memory.validation/state/snapshot: stale check now happens before the bloom shortcut.validation/state/pruner: bloom-filter filename parsing guards against overlapping prefix/suffix and requires canonical hash spelling.policy/fees:estimateSmartFeefalls back toestimateFeewhen there isn't enough data. Log message in the gas-price oracle clarified.kernel/xhash: switched tohash.Sumafterx/cryptov0.45 droppedRead()on sha3.
Security
Dependency updates in this cycle close a number of published vulnerabilities:
- CVE-2025-30204:
golang-jwt/jwtcould OOM on a malformed Authorization header. This one was reachable through the Engine API auth path, so treat it as a real fix, not hygiene. Fixed by the bump to v4.5.2. - CVE-2026-46600: DoS in
x/net(dns/dnsmessage) via invalid DNS records. Fixed in v0.56.0. - CVE-2026-56852: DoS in
x/texton invalid UTF-8. Fixed in v0.39.0. Both this and thex/netCVE were caught by the new Trivy scanning of the release images. - CVE-2023-44273 and GHSA-pffg-92cg-xf5c in
gnark-crypto(ECDSA/EdDSA deserialization range checks, GT-GLV exponentiation). The vulnerable paths are only reachable from our fuzzers, but the bump to v0.18.1 clears the alerts. - Lower-severity advisories in
x/cryptoandprotobufwhose vulnerable code paths aren't reached from this codebase, bumped alongside as no-risk hygiene.
Related hardening in this release: the keystore decrypt bounds (see Fixes) close a DoS vector via malicious keystore files, and Docker images now run unprivileged on pinned bases with Trivy scans in CI.
Binaries and build
The daemon is now parallaxd, not prlx. The IPC socket is parallax.ipc and the metrics prefix is parallax..
There are three binaries:
parallaxd: the full node daemon.parallax-cli: the client/admin tool.parallax-wallet: offline wallet tooling, consolidated.
There is also a parallax wrapper. parallax node … execs parallaxd, parallax rpc … execs parallax-cli. The wrapper resolves its companion via EvalSymlinks first and $PATH second, so both go-run and symlinked installs work.
The Makefile, ci.go, Dockerfile, and release.yml know about all three binaries. There are bash and zsh completions. The dlgo bootstrap is on Go 1.26.1.
Docker is now a first-class install path: multi-arch images are published to Docker Hub on release tags, built with Go 1.26, running as an unprivileged user on pinned base images with OCI labels, and including parallax-wallet. Images are scanned with Trivy in CI.
I've removed a fair amount of legacy: AppVeyor, CircleCI, Travis, NSIS, Maven, CocoaPods, Debian build files; the mobile bindings; swarm/; the contracts/ checkpoint oracle; cmd/checkpoint-admin/. clef and parallaxkey are no longer in release artifacts.
Dependency updates: jwt/v4 v4.5.2, x/crypto v0.53.0, x/net v0.56.0, x/text v0.39.0, protobuf, gnark-crypto v0.18.1. Several of these fix CVEs; see the Security section. reexec moved to github.com/moby/sys/reexec.
Code layout
The tree has been restructured into layers: kernel/, validation/, script/, primitives/, p2p/, node/, rpc/, wallet/, policy/, support/, util/, logging/, dbstore/, crypto/.
kernel/ no longer imports anything from validation, p2p, node, or wallet, and it has no RPC code. It does this through two new interfaces, StateAccessor and ChainConfigurator. kernel/consensus/ and kernel/misc/ were folded into the kernel root.
Package names match directory names: common -> util, log -> logging, prldb -> dbstore, params -> chainparams, core -> validation, vm -> script, accounts -> wallet, prl -> protocol, prlclient -> client, prlstats -> stats.
The old consensus wrapper is gone, engine APIs are registered directly from node/fullnode/backend.go. The node/fullnode <-> node/light cross-imports were resolved before the light client was removed. The gasprice forwarding shim is gone; callers go directly to policy/fees/.
Documentation
The documentation now lives in this repo under docs/, not in the separate parallax-docs repo. It's still served at https://docs.parallaxprotocol.org via Mintlify. New in this cycle: a full XHash technical specification, a peer-management and operator RPC reference, Docker install/run guides, and links to the second edition of the whitepaper.
Upgrading
- Replace
prlxwithparallaxd, or use theparallaxwrapper. The IPC socket isparallax.ipc; metrics prefix isparallax.. - If you import Parallax as a Go module, your imports will all need updating.
- If you were running a light client, you'll need a full or snap-syncing node.
- Drop
--nousb,--whitelist,--miner.gastarget,--v5discfrom any startup scripts. - v4 (UDP) discovery is still on by default and runs alongside the new TCP-based discovery, with TCP preferred. This is a backwards-compatibility measure; v4 will be fully deprecated in a later release. Operators who want pure-TCP can flip
--legacy-discovery=off(no UDP socket, legacy RLPx refused, enode URLs become diagnostic-only).--legacy-discovery=[auto|on|off]is the single new P2P knob. - If you consume the total-supply RPC, expect corrected values (see Fixes).