Bounded peer replies, steadier connections, and faster mempool cleanup. We recommend upgrading.
Supported on Mainnet until block 3,643,309, around December 3, 2026. Upgrade warnings start about three days earlier.
Before you upgrade
network.unconditional_peersnow dials peers. Listed single addresses are now dialed and reconnected automatically, with extra connection slots reserved for them. Review existing entries, since previously passive entries now cause outbound connection attempts (#2389).- Monitoring labels and refresh intervals.
zakura.net.in.errors'serrorandmempool.failed.verify.tasks.total'sreasonnow use error kinds; update matching alerts.zakura.state.rocksdb.*gauges andsize_on_disknow refresh every 5 minutes, not every 30 seconds (#2439, #2475). - Custom-network consensus and mempool policy. Custom NU7 chains using the previous payout rule need coordinated deployment and a reset or explicit migration. Sprout JoinSplits are now rejected by mempool policy even on custom pre-NU7 networks (#1591, #2471).
- Peer service flags in
getnetworkinfo. Experimental: pruned nodes advertiseNODE_PRUNED.NODE_NETWORKadvertising is restored, andgetnetworkinforeports actuallocalservices; update consumers that assume fixed service flags (#2382).
Highlights
- Security: a peer's
getblocksreply now keeps at most 500 block hashes, preventing one peer from making the syncer process up to 50,000 hashes per response (#2437). - Startup makes up to 50 peer connection attempts at once, uses cached peers when all seed DNS lookups fail, and prioritizes peers that responded in the last 3 hours (#2396, #2399, #2404).
- Lower CPU use at the chain tip and while serving blocks comes from cheaper peer-address metrics, less copying of shielded bundles, and reuse of large-block checksums (#2409, #2421, #2424).
- With faster legacy checksum hashing on a Mainnet node without SHA instructions, serving old blocks uses 32% less CPU per MB, and one connection delivers blocks about 50% faster (#2450).
- Mempool cleanup avoids full-pool scans for conflicts and expiry, batches removals, and reduces ordering work; pending transaction gossip cleanup removes changed IDs directly (#2467, #2468, #2469, #2470, #2473).
- Set
network.zakura.trace_dirto record legacy block announcements, requests, and sends inlegacy_gossip.jsonl, without peer addresses;ZAKURA_TRACE_PEER_NAMESlabels selected peers (#2446).
Library users
Source builds verifying pre-NU7 blocks above the last checkpoint need --features sprout, including Testnet sync from genesis with current checkpoints. The consensus crate restores its Halo2 error type and conversion for stable compatibility (#2413, #2466).
Full changelog
Added
network.zakura.trace_dir set, legacy peer connections write
legacy_gossip.jsonl: each block announcement sent to a peer, the peer's
request for that block, and the block being sent to it or found missing.
They also write the announcements each peer sends, up to 16 a minute for
each connection. Requests for blocks this node did not announce to that
peer are not written, so what a peer sends cannot make the file grow
without bound. Rows never hold a peer's address. The ZAKURA_TRACE_PEER_NAMES
environment variable (name=ip pairs separated by commas) names the peers an
operator wants to tell apart
(#2446).
Changed
network.unconditional_peers now also keeps its peers connected. Zakura
dials every entry that names one address, and dials it again whenever no
connection to that peer is open in either direction. An entry can give the
port to dial, such as "192.0.2.1:8233". An entry without a port is dialed
on the network's default port, and a CIDR range is only dialed when it covers
a single address. Each dialed address adds one outbound and one inbound
connection slot on top of the connection limits. The inbound slots are a pool
that only listed peers can use, so a node whose other inbound slots are full
still accepts a listed peer that dials it. One IP holds at most
max_connections_per_ip of these slots. Zakura's other outbound dials leave
a listed address's IP the room the listed peer needs. Zakura also
lets these peers reconnect inbound without its usual wait between connections
from one IP. IP addresses that an existing config
already lists start being dialed after the upgrade, and a listed peer that
accepts no connections costs one failed dial every ten minutes once its delay
has grown
(#2389).
next one as soon as an attempt completes, instead of spacing attempts 100 ms
apart. The total startup peer target and per-IP limits still apply
(#2396).
which was the largest single CPU cost of an idle node at the chain tip
(#2409).
or Sapling bundles, and when serving blocks to peers, by no longer copying
each bundle before writing it
(#2421).
reducing repeated hashing when several peers request the same block.
Concurrent sends can still each calculate a checksum before it is remembered
(#2424).
error label of zakura.net.in.errors and the reason label of
mempool.failed.verify.tasks.total now name the error kind, such as io,
parse, invalid or download_failed, instead of the full error message.
Peers could otherwise create an unbounded number of metric series. Update
dashboards and alerts that match full error messages on these labels
(#2439).
process_trace_id is now the moment the
row's ts counts from, so adding the two gives the row's wall-clock time.
Before, the two were read at different moments and could be seconds apart
(#2446).
[network.zakura] trace_dir set, zakurad now moves to the file at a
trace table's path within about a second when its own file was renamed,
deleted or replaced, so trace files can be rotated by renaming them without
losing rows
(#2449).
reads before switching files, truncating it, or rotating again, preserving rows
in large backlogs even while the node is delayed before opening a replacement.
ring's SHA-256, which
uses the vector instructions of CPUs that lack SHA instructions. On such a
mainnet node, serving old blocks to syncing peers used 32% less CPU per MB
and one connection delivered blocks about 50% faster. Checksum values are
unchanged
(#2450).
IDs for versions one through four with ring, preserving the existing hash
values (#2457).
sprout
Cargo feature. Builds using post-NU7 snapshots do not need it; verifying
pre-NU7 blocks above the last checkpoint, including Testnet sync from genesis
with the current checkpoints, requires --features sprout
(#2466).
through spend-owner indexes instead of scanning the entire pool
(#2467).
instead of scanning transactions that are not due to expire
(#2468).
dependency-order updates and metric reports while retaining unmined children
of confirmed transactions
(#2469).
removing changed IDs directly instead of scanning the advertisement backlog
(#2470).
JoinSplits are now rejected by mempool policy even on custom pre-NU7 networks;
historical block verification remains available with the sprout feature
(#2471).
caching ordering scores and refreshing only surviving transactions whose
priorities change
(#2473).
seconds to every 5 minutes. The zakura.state.rocksdb.* gauges and the
size_on_disk RPC estimate now refresh at that interval
(#2475).
performance, tracing, and build changes. Builds that verify pre-NU7 blocks
above the last checkpoint still require the documented sprout feature
(#2466,
#2479).
Fixed
calculate the same subsidy. Existing custom NU7 chains need coordinated deployment
and a reset or explicit migration if they used the previous payout rule
(#1591).
NODE_NETWORK advertising for pruned nodes so peers can discover,
reconnect to, and download recent blocks from them. Pruned nodes additionally
advertise an experimental NODE_PRUNED flag. While an updated node is still
syncing, it downloads blocks from peers without the flag and waits for one of
them when they are all busy. It asks a pruned peer only when it is connected
to no such peer, or when those peers leave block requests unanswered. It
sends getblocks to peers without the flag too, because pruned peers leave
a getblocks for deleted blocks unanswered. Near
the network tip it treats pruned peers like any other peer. getnetworkinfo
now reports the node's actual
localservices, including these flags
(#2382).
timeout releases the stream and connection reservation immediately
(#2396).
DNS lookup fails, instead of retrying DNS forever without connecting
(#2399).
the last 3 hours, not addresses learned from gossip, so a restart spends its
first connection attempts on peers that recently accepted a connection
(#2404).
preserving compatibility with its current stable release
(#2413).
network.zakura.trace_peer_names instead
of an environment variable that could prevent the node from starting. The
fleet installer writes the mapping and removes the obsolete environment
override after verifying the configuration
(#2474).
Security
getblocks reply to a FindBlocks request now keeps at
most 500 block hashes, the most zakurad and zcashd serve, so one peer can
no longer make the syncer process up to 50,000 hashes per response
(#2437).
Also in CHANGELOG.md.