Release: Zakura 1.1.1

We have released Zakura 1.1.1, a security and performance release. Last week we published 1.1.0 but did not blog about it at the time; this post discusses all of the changes.

We recommend that all node operators update immediately. This release closes block-propagation attacks that could eclipse a node during sync, let a peer repeatedly gossip invalid blocks without being penalized, or leave a mining backend working from a stale chain tip. These fixes have been introduced in coordination with Zebra.

In addition, this release provides substantial speedups for indexer consumers (thanks to @maxdesalle), improves nodes behind NATs network connectivity, and substantially extends the end-of-support window. Further, RPC changes now allow operators to more easily learn about EOS halt dates and supported block heights.

Security

  • Far-ahead blocks no longer get an honest peer banned. A peer was previously banned for serving a block whose height exceeded the sync lookahead limit. The ban was assigned to the peer that answered the block request, even though the far-ahead height came from whichever peer supplied the hash in an earlier FindBlocks response—usually a different peer. An attacker could exploit that mismatch to get honest peers banned and eclipse a node during sync. Such blocks are still dropped without restarting sync. Peers that serve blocks with no valid height or that fail consensus verification are still scored, without blaming peers for invalid ancestors. The Zakura team reported this issue.
  • Peer-controlled singleton responses no longer stall near-tip sync. Zakura previously discarded a one-block FindBlocks response while protecting against a legacy zcashd quirk that can append an unrelated hash. A peer could therefore suppress the node's only unknown block, producing a zero-length sync sample that falsely made the node appear close to tip and could let /ready report success while it remained behind. The only unknown hash in a qualifying short response is now downloaded, allowing the node to keep advancing. Maakai123 reported this issue in Zebra #10603.
  • Peers that gossip invalid blocks are scored and banned. Zakura inherited security bugs that allowed a peer to keep supplying invalid blocks over the same connection. Inbound cleanup now recognizes the router's rejections and bans the responsible peer. The Zakura team reported this issue.
  • Coinbase-height malleation can no longer poison the newest block. A V5 or later coinbase scriptSig is authorizing data and is therefore excluded from the block hash. A peer could rewrite the height in an otherwise canonical block body and still answer a request for that hash. When the block built on Zakura's own chain tip but claimed a height other than one above the tip, the poisoned body was discarded as a benign old block—unattributed, unscored, and not requeued. That delayed the newest block until the next discovery round and left a mining backend issuing work on an obsolete tip. The height check now runs on both block-download paths, sync and block gossip. Each path scores the supplying peer for a ban and immediately re-requests the hash under its own bounded retry budget. This issue was reported by Sangsoo at Ottersec as part of a security audit commissioned by the Zakura team.
  • Logging is hardened against escape attacks. Zakura now handles untrusted log content more defensively across peer-message logging and operator filtering tools.
  • Dependency hygiene. The unmaintained structopt (RUSTSEC-2022-0104) and rustls-pemfile (RUSTSEC-2025-0134) dependencies and their advisory-flagged transitive trees are removed, and CI now verifies the doctl and rustup-init binaries it downloads against pinned checksums before executing them.
  • Misbehavior scores apply promptly. Batched peer misbehavior scores reach the address book every five seconds instead of every 30, so threshold bans become visible to the listener and peer set faster. We aim to make this instant with more testing.

RPC parity for pruned nodes

  • getblockchaininfo now reports pruneheight, the lowest height at and above which every block body is retained. As in zcashd, the field is only present when pruned is true. Zakura prunes raw transaction data rather than whole blocks, so blocks below this height keep their headers, transaction IDs, and consensus state, and the genesis block is never pruned.
  • The pruned flag now reports configuration, not history. A node configured with storage_mode.pruned previously reported pruned: false until it first deleted block data, which took at least 10,000 blocks on Mainnet. As in zcashd, the field now reports whether blocks are subject to pruning.
  • New getdeprecationinfo RPC. It reports Zakura's Mainnet end-of-support height and an estimated halt time with a 24-hour safety margin. When the chain tip is unavailable, the estimate starts from the latest network checkpoint.

Operators with dashboards keyed on the read-request metric label is_pruned should note it is now pruning_info, since the request also reports the prune height.

Peer connectivity

  • The default connection budget is rebalanced. The inbound connection limit rises from 100 to 300 while the outbound limit drops from 300 to 150. This is important for ensuring good connectivity of the p2p network and allowing new nodes to enter.
  • Outbound replenishment is restored to the configured peer set size. The crawler's dial budget targeted a share of the outbound connection limit, in order to not saturate all nodes inbound limits. Now that we've fixed the inbound/outbound ratio, we now target the crawler to filling 80% of the outbound budget.
  • Restarted nodes find peers faster. The peer address disk cache grows from 75 to 300 addresses, and the first cache write is retried every 20 seconds instead of waiting the full 5-minute update interval, so a cold-started node caches its peers soon after finding them.
  • Native discovery is more careful about what it shares. zakurad now shares a discovery record with other peers only after confirming that record's owner directly, and answers each peer's GetPeers requests from a bounded per-peer record set that is stable for a ten-minute window—so repeated requests, however they vary their filters, no longer walk further through the local discovery book. Records learned second-hand still serve as local dial hints, so bootstrap reach is unchanged.

Correct answers from fast-synced nodes

This release fixes RPC behavior that could mislead wallets talking to a node bootstrapped with verified-commitment-trees (VCT) fast sync:

  • z_gettreestate and z_getsubtreesbyindex no longer fabricate emptiness. For heights a fast-synced node has no data for, z_gettreestate returned a JSON null treestate and z_getsubtreesbyindex an empty list. Clients following the lightwalletd contract read an absent treestate as the empty tree, so a wallet could derive a birthday anchor asserting an empty commitment tree deep in the chain with no error raised. Both now return a typed archive-mode error, and verbose getblock/getblockheader preserve that explanation. Re-indexing the relevant data, along with a better LWD contract are planned for subsequent releases.
  • Databases from the original VCT fast sync are rejected at startup. A Mainnet database written by the original VCT fast sync (below database format version 28.0.1) is missing the historical Sprout anchors needed to verify JoinSplits that spend a historical Sprout root. The in-place repair that used to backfill them has been removed; discard the database and resync, or restore a snapshot taken with a current release.
  • The 71 MB embedded repair artifact is gone. The zakurad validate-vct-sprout-history subcommand and the embedded artifact it audited no longer apply due to EOS heights, guaranteeing every affected user has a patched upgrade.
  • New historical-treestate audit tooling. The zakurad audit-historical-treestates command opens an existing state database read-only and inventories the authenticated roots and anchor frontiers needed to reconstruct the Sapling, Orchard, and Ironwood note commitment trees omitted by VCT fast sync. --scan-block-bodies checks that the whole absent range is retained. With --walk, the command instead validates the bodies it replays, derives trees across the requested range, and checks every sampled result against the authenticated root already stored for that height; --verify-subtrees compares replayed subtree roots with stored rows above the last checkpoint. This is audit and performance-measurement tooling, not an in-place database repair.
  • Read-only tools can inspect older databases. A read-only RocksDB secondary no longer tries to open column families that an older database does not have, so audit and inspection commands can examine it without first upgrading or modifying it.

The audit command does not yet restore historical-tree RPC serving. In the range where a VCT fast-synced database has no per-height trees, the RPCs continue to return the typed archive-mode errors described above. Reconstructing trees also requires retained block bodies, so a pruned database cannot derive trees below its retention height.

Other fixes

  • Indexer gRPC subscriptions tolerate slow consumers. Tip and mempool subscriptions now apply backpressure with a 60-second send timeout instead of being dropped the moment their buffer fills, so a briefly slow consumer no longer triggers rapid re-subscribe cycles.
  • A queued-block index leak is fixed. Dequeuing one fork sibling un-indexed another block at the same height, preventing it from being pruned and leaking entries in the block queue and its known-UTXO cache.
  • Mined-block broadcasts no longer wait for disconnected peers.
  • The P2P user agent is consistent. Every transport mode now advertises the zakurad release version without an internal networking crate version.
  • Higher ZIP 317 block-production weight cap. The cap rises from 4 to 10, allowing high-fee transactions to receive up to ten times the conventional weight during block-template transaction selection. This changes miners' transaction ranking, not transaction or block consensus validity.

Building from source

Zakura now builds with GCC 15/16 without the CXXFLAGS="-include cstdint" workaround, via RocksDB 10.4.2 (rocksdb 0.24). The bundled librocksdb-sys now always runs bindgen, so libclang is required at build time (in addition to protoc and a C++ compiler) even when linking a system RocksDB. Install libclang-dev (Debian/Ubuntu), clang (Arch), or the equivalent for your platform.

End-of-support halt

The end-of-support window is extended from 18 to 40 days after the estimated release height. Mainnet nodes running this release halt at height 3,484,507 (~2026-09-15) instead of ~2026-08-24. Upgrade warnings keep their three-day lead and begin ~2026-09-12.

Next EOS update will be in our v1.2.0 release, expected later this week.

Updating

You can update using our signed release binaries or by upgrading the zakura crate to 1.1.1 via Cargo. See the download page for installation and verification instructions.