ZIP: 218 Title: 25-second Block Target Spacing Owners: Dev Ojha Evan Forbes Status: Draft Category: Consensus Created: 2026-03-13 License: MIT Discussions-To: # Terminology The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in BCP 14 [^BCP14] when, and only when, they appear in all capitals. The terms "block chain", "consensus rule change", "consensus branch", and "network upgrade" are to be interpreted as defined in ZIP 200. [^zip-0200] The term "block target spacing" means the time interval between blocks targeted by the difficulty adjustment algorithm in a given consensus branch. It is normally measured in seconds. (This is also sometimes called the "target block time", but "block target spacing" is the term used in the Zcash Protocol Specification [^protocol-diffadjustment].) The term "TPS" refers to the maximum number of transactions per second supported by a Zcash subprotocol, assuming the target block spacing. The character § is used when referring to sections of the Zcash Protocol Specification. [^protocol] The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 'Mainnet and Testnet'. [^protocol-networks] # Abstract This proposal specifies a change in the block target spacing from 75 seconds to 25 seconds in NU7, and introduces per-pool action limits for the Sapling, Orchard, and Ironwood shielded pools. This solves three problems. - Significantly improves the UX for actors who need 1 or 2 confirmations, such as Near Intents, and for small payments. The user-visible latency goes down 3x. - Increases consensus bandwidth, which would amplify the scaling impact of any future shielded pools that do not require shielded sync. - Introduces action limits. These provide limits on the number of actions that can go into a block. There is a *block shielded action limit* across all shielded pools, as well as per-pool limits. These limits are configured to more than double Orchard-protocol TPS (2.9 → 6.6 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 37% (271 → 169 MB/day). The action limits significantly decrease the number of Sprout and Sapling pool outputs available per block, to lower the maximum shielded sync burden under attempted DoS. The emission schedule of mined ZEC will be the same in terms of ZEC/day, but this requires the emission per block to be adjusted to take account of the changed block target spacing. # Motivation The motivations for decreasing the block target spacing are: - **Reduced transaction latency.** Currently, users must wait 75 seconds on average for even a single confirmation, regardless of network utilization. This creates friction for point-of-sale payments, exchange deposits, and cross-chain bridge operations. A 25-second target spacing reduces the expected wait for a first confirmation to 25 seconds on average. - **Greater throughput.** With 3× as many blocks per day and the same 2 MB block size limit, we will have allocated higher consensus bandwidth capacity. In the short term, when paired with the action limits, we will more than double the Ironwood TPS for 2-action transactions. In the longer term, when we get a shielded pool with no shielded sync burden, we will have 3x higher throughput. The throughput goal on its own could be achieved via a block size increase. However the goal of this proposal is foremost to improve the transaction latency. This proposal is complementary to, and does not compete with, finality mechanisms such as Crosslink [^crosslink]. Faster block times improve the responsiveness of the base layer regardless of whether an additional finality gadget is also deployed. Rollback-risk analysis depends on the threat model. For models that bound an attacker by a fixed fraction of total hash power, reducing the block target spacing can reduce confirmation latency by nearly the same factor, provided that block validation and propagation times remain small relative to the target spacing. Given that is maintained here, this proposal is expected to improve confirmation latency by slightly less than 3x for users applying the same rollback-risk tolerance as today. See [#slowfastblocks]_ for analysis under several attack models. Economic rollback models give a different result. For recipients who wait until the block rewards built on top of their payment exceed the payment value, then shorter block times significantly reduce the variance of their waiting time, while the mean stays roughly the same. Recall that proof of work block times while the mean stays roughly the same. Recall that proof-of-work block times have high variance, so variance reduction is a substantial benefit. This ZIP does not argue for clients reducing confirmation counts, but it does expect many users to see a lower expected time until receipt under confirmation policies comparable to those they use today. ## Security Scaling and block time reductions in Zcash impose three security costs, one on full nodes' and miners' ability to verify blocks, a second on clients for shielded sync, and a third on the whole network for the uncle rate and fork rate. Action limits are introduced in this ZIP to limit the block processing costs, and client shielded sync costs. The proposed parameterization lowers the worst case for shielded sync and node processing times relative to today, while yielding far higher Ironwood TPS. We benchmark [block verification](#block-processing-time), and the uncle-rate post-proposal on networks more distributed than mainnet at maximum load is far lower than ETH-PoW was, leading to conclusion that it is safe. Today the worst-case DoS attack can induce 271 MB of wallet sync download to clients per day, and 4.8M trial decryptions per day [^syncsimulator]. This is achieved by fully utilizing block space with Sapling transactions that have few inputs and many outputs. The worst-case DoS for node verification time uses many Sapling inputs and a single transparent output, totaling 5,600 Sapling inputs and zero-knowledge proofs. This takes 3.2 seconds on a modern AMD laptop CPU with 4 pinned threads. Regular user flows impose far lower costs on the network than this DoS model. We propose introducing block shielded action limits and per-pool action limits as follows: - A block shielded action limit of 330 across all pools - A maximum of 330 Orchard actions per block - A maximum of 330 Ironwood actions per block - A maximum of 300 Sapling inputs + outputs. (Total inputs + outputs <= 300) - No Sprout JoinSplits (achieved by deploying this ZIP in conjunction with ZIP 2003 [^zip-2003] which disables v4 transactions). With these limits, the worst case client load becomes 169 MB bandwidth and 2.3M trial decrypts per day. This is a 37% improvement in worst case wallet sync bandwidth despite 3× more blocks. This yields a 2.3× increase in Ironwood TPS, and keeps Sapling TPS at a higher level than today's Ironwood TPS. However, every wallet does have to download every compact block header, which is 90 bytes. This leads to an extra 200kb of wallet bandwidth per day in exchange for the improved UX. The reduced Sapling and Sprout per-block limits are justified by the The reduced Sapling per-block limit and disabling of Sprout is justified by the current distribution of shielded funds across pools (other motivations for disabling Sprout are discussed in ZIP 2003). As of May 2026: | Pool | Balance | Share of shielded supply | |------|---------|--------------------------| | Orchard | 4,534,914 ZEC | 87.9% | | Sapling | 597,910 ZEC | 11.6% | | Sprout | 25,409 ZEC | 0.5% | The vast majority of shielded activity is already in Orchard, and this trend is expected to continue. The Sapling limit is set generously relative to current usage while substantially reducing the potential for DoS. Furthermore, this ZIP is proposed to activate together with disabling v4 transactions in NU7, which would prevent any Sprout transactions from being included in blocks. ## Stale block rate The stale rate is the percentage of blocks that get orphaned, which relates to mining centralization risk, block propagation delay, and block verification times. Today the stale rate is 0.4%, but this may be lower than what pure block propagation delay may imply due to hash-power centralization in mining pools. At 25-second block target spacing, the theoretical stale block rate is approximately 3.26%, derived from measured Zcash network propagation delays. A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks at 25-second target spacing measured a stale block rate of 4.86% and a fork rate of 0.37%. Both observed figures are below the 5.4% safety threshold set by Ethereum's historical proof-of-work stale rate. [^forum-proposal] The only modification required to achieve these rates was tuning TCP configuration (more details in the linked footnote). The devnet's node distribution was significantly more decentralized than today's mainnet, so these figures represent a near worst-case scenario. [^devnet-blocktime-test] ## Block processing time A prerequisite for reducing the target block spacing is that block validation and propagation must remain small relative to the target spacing. The per-pool propagation remain small relative to the target spacing. The per-pool action limits introduced by this proposal ensure that worst-case *per-block* processing time is lower than today's. The fact that there are three times as many blocks in unit time does mean that the *overall* worst-case proportion of time taken for processing, and the worst cost of sync after a given time offline for full nodes will increase. We accept this trade-off. These computational limits parallelize well. The max bandwidth requirement from the chain is 655kbps, so syncing with 10mbps bandwidth still has a 15x advantage factor over full blocks on mainnet. **Current worst case:** A full 2 MB block today can contain up to ~617 Orchard or Ironwood actions, or ~2,090 Sapling outputs, with no per-pool limits. A fully packed Orchard-protocol block requires verifying all action proofs, spend authorization, and binding signatures, and checking validity of curve point encodings, for those ~617 actions. **Proposed worst case:** With the action limits, a block contains at most 330 actions across pools. There are also separate per-pool limits: - 330 Orchard actions - 330 Ironwood actions - 300 Sapling inputs+outputs. This means the new worst case block processing time, if Orchard- or Ironwood-dominant, would be 14% of today's worst case, and Sapling's would be less than one tenth. The worst case per-block verification work is therefore substantially reduced. **Batch verification.** Ironwood transaction verification benefits from batch validation, where proof and signature verification is amortized across multiple transactions. Ironwood uses the same Action encoding and proof system as Orchard. [^zip-0229] In current node software, Orchard transactions are batch-verified in groups of up to 64 transactions (each worst case being a single action). Zebra has performed batch verification during live network syncing since version 3.0.0. With the action limits, the Orchard-protocol bundles in a worst-case block can be fully batch-verified in a small number of batches. **Measured timing.** We benchmarked worst-case block verification with Zebra on a modern AMD laptop CPU with 4 pinned threads.[^verification-benchmark] The figures report wall-clock time for verifying the zero-knowledge proofs and signatures in a single block, without any mempool pre-verification. | Case | Block composition | Mean ± stddev | |------|-------------------|---------------| | Full Orchard limit (proposed) | 330 Orchard actions | 432.11 ± 11.03 ms | | Full Sapling limit (proposed) | 300 Sapling spends, 0 outputs | 271.51 ± 5.03 ms | | Today's Orchard worst case | ~617 actions in dense multi-action txs in a 2 MB block | 769.85 ± 16.18 ms | | Today's Sapling worst case | ~5,600 spends in dense multi-spend txs in a 2 MB block | 3,174.90 ± 144.04 ms | - **Full Orchard limit (proposed)** — binding post-NU7 verification worst case. - **Full Sapling limit (proposed)** — verification worst case is all-spends; the bandwidth worst case (all-outputs) is in [Rationale](#rationale). - **Full Sapling limit (proposed)** — verification worst case is all-spends; the bandwidth worst case (all-outputs) is in [Rationale](#rationale). - **Today's Orchard worst case** — dense multi-action (single-action would understate the byte bound). - **Today's Sapling worst case** — analogous, dense multi-spend. When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has been online, block validation reduces to checking signatures and When transactions have already been pre-verified upon entering the mempool, block validation reduces to checking signatures and state updates, which is even cheaper. This is the typical case for a node that has been online under normal usage of the network, but under DoS attack it cannot be assumed, because the adversary can send blocks with transactions that were never in the mempool. # Specification The changes described in this section are to be made in the Zcash Protocol Specification [^protocol], relative to the specification as of the activation of this proposal. ## Consensus changes ### Block target spacing In § 2 'Notation', add $\mathsf{NU7ActivationHeight}$ and $\mathsf{PostNU7PoWTargetSpacing}$ to the list of integer constants. In § 5.3 'Constants', define: $$\mathsf{PostNU7PoWTargetSpacing} := 25 \textsf{ seconds}$$ On Testnet, the minimum-difficulty threshold remains 450 seconds after NU7 activation; see [Minimum difficulty blocks on Testnet](#minimum-difficulty-blocks-on-testnet). For a given network (production or test), define $\mathsf{NU7ActivationHeight}$ as the height at which this network upgrade activates on that network, as specified in a separate deployment ZIP. Define: $$\mathsf{NU7PoWTargetSpacingRatio} := \mathsf{PostBlossomPoWTargetSpacing} \;/\; \mathsf{PostNU7PoWTargetSpacing} = 3$$ Define $\mathsf{IsNU7Activated}(\mathsf{height})$ to return true if $\mathsf{height} \geq \mathsf{NU7ActivationHeight}$, otherwise false. In § 7.7.3 'Difficulty adjustment', redefine $\mathsf{PoWTargetSpacing}$ as: $$ \mathsf{PoWTargetSpacing}(\mathsf{height}) := \begin{cases} \mathsf{PreBlossomPoWTargetSpacing}, &\textsf{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\\\ \mathsf{PostBlossomPoWTargetSpacing}, &\textsf{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \textsf{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\ \mathsf{PostNU7PoWTargetSpacing} &\textsf{otherwise} \end{cases} $$ ### Averaging window [averaging-window] In § 2 'Notation', add $\mathsf{PostNU7PoWAveragingWindow}$ to the list of integer constants. In § 5.3 'Constants', define: $$\mathsf{PostNU7PoWAveragingWindow} := 102$$ In § 7.7.3 'Difficulty adjustment', redefine $\mathsf{PoWAveragingWindow}$ as a height-dependent function: $$ \mathsf{PoWAveragingWindow}(\mathsf{height}) := \begin{cases} 17, &\textsf{if not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\ \mathsf{PostNU7PoWAveragingWindow} &\textsf{otherwise} \end{cases} $$ All other references to $\mathsf{PoWAveragingWindow}$ in § 7.7.3 'Difficulty adjustment' that previously took the constant value 17 are reinterpreted as $\mathsf{PoWAveragingWindow}(\mathsf{height})$ for the height of the block under consideration. This includes the size of the averaging window used to compute the average target threshold and the average block timespan. ### Halving interval and block subsidy Define: $$\mathsf{PostNU7HalvingInterval} := \lfloor \mathsf{PostBlossomHalvingInterval} \cdot \mathsf{NU7PoWTargetSpacingRatio} \rfloor = 5{,}040{,}000$$ Redefine the $\mathsf{Halving}$ function as: $$ \mathsf{Halving}(\mathsf{height}) := \begin{cases} \left\lfloor \dfrac{\mathsf{height} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} \right\rfloor, &\textsf{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\\\[1.5ex] \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + \dfrac{\mathsf{height} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} \right\rfloor, &\textsf{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \textsf{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\[1.5ex] \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + \dfrac{\mathsf{NU7ActivationHeight} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} + \dfrac{\mathsf{height} - \mathsf{NU7ActivationHeight}}{\mathsf{PostNU7HalvingInterval}} \right\rfloor, &\textsf{otherwise} \end{cases} $$ Redefine $\mathsf{BlockSubsidy}$ to add a case for post-activation heights. The prior Blossom case in § 7.8 'Calculation of Block Subsidy and Founders' Reward', currently written as "otherwise", must be amended to "if $\mathsf{IsBlossomActivated}(\mathsf{height})$ and not $\mathsf{IsNU7Activated}(\mathsf{height})$": $$ \mathsf{BlockSubsidy}(\mathsf{height}) := \begin{cases} \ldots &\text{(prior cases, with the Blossom case amended as above)} \\\\[1ex] \mathsf{floor}\left(\dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}}\right), &\textsf{if } \mathsf{IsNU7Activated}(\mathsf{height}) \end{cases} $$ This divides the per-block subsidy by an additional factor of 3 relative to the post-Blossom subsidy, so that the total issuance per unit of wall clock time remains the same. Note: during the second halving period, the post-Blossom block subsidy is 1.5625 ZEC. At 25-second spacing it becomes $\mathsf{floor}(156250000 / 3) = 52083333$ zatoshi (0.52083333 ZEC), so three post-NU7 blocks issue one zatoshi less than one pre-NU7 block. After the third halving, the subsidy is $\mathsf{floor}(78125000 / 3) = 26041666$ zatoshi (0.26041666 ZEC). Let $A$ be the NU7 activation height, and let $H_3$ be the third-halving height under the 75-second schedule on the relevant network. If NU7 activates between the second and third halvings, the additional shortfall in scheduled issuance relative to keeping 75-second blocks is $0.4872 + (H_3 - A)/10^8$ ZEC. The first term is the combined rounding shortfall from the third and later halving periods; the second is the one-zatoshi shortfall per remaining 75-second block in the second period. The existing 75-second schedule falls short of $\mathsf{MAX\_MONEY}$ by 0.1848 ZEC, so the post-NU7 scheduled shortfall is $0.6720 + (H_3 - A)/10^8$ ZEC. These figures exclude any NSM reissuance. ### Shielded pool action limits Define the following constants in § 5.3 'Constants': $$\mathsf{GlobalShieldedBudget} := 330$$ $$\mathsf{OrchardProtocolBlockActionLimit} := 330$$ $$\mathsf{SaplingBlockIOLimit} := 300$$ $$\mathsf{SproutBlockJoinSplitLimit} := 0$$ For each block at height $\mathsf{height}$ where $\mathsf{IsNU7Activated}(\mathsf{height})$, the following limits MUST be satisfied: **Per-pool limits:** - The total number of Orchard actions across all transactions in the block MUST NOT exceed $\mathsf{OrchardProtocolBlockActionLimit}$. That is, $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nActionsOrchard}(\mathit{tx}) \leq \mathsf{OrchardProtocolBlockActionLimit}$. - The total number of Ironwood actions across all transactions in the block MUST NOT exceed $\mathsf{OrchardProtocolBlockActionLimit}$. That is, $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nActionsIronwood}(\mathit{tx}) \leq \mathsf{OrchardProtocolBlockActionLimit}$. - The total number of Sapling inputs and outputs across all transactions in the block MUST NOT exceed $\mathsf{SaplingBlockIOLimit}$. That is, $\sum_{\mathit{tx} \in \mathit{block}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \leq 300$. - The total number of Sprout JoinSplits across all transactions in the block MUST NOT exceed $\mathsf{SproutBlockJoinSplitLimit}$. That is, $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nJoinSplit}(\mathit{tx}) \leq 0$. **Block shielded budget:** In addition to the per-pool limits, the total shielded cost across all pools in a block MUST NOT exceed $\mathsf{BlockShieldedBudget}$. The shielded cost of a block is defined as: $$\sum_{\mathit{tx}} \left(\mathit{nActionsOrchard}(\mathit{tx}) + \mathit{nActionsIronwood}(\mathit{tx})\right) \;+\; \sum_{\mathit{tx}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \;+\; 2 \times \sum_{\mathit{tx}} \mathit{nJoinSplit}(\mathit{tx}) \;\leq\; \mathsf{GlobalShieldedBudget}$$ Thus, Orchard and Ironwood do not receive separate 330-unit global budgets: every action in either pool consumes one unit of the same global budget. The factor of 2 for Sprout JoinSplits reflects that each JoinSplit produces 2 shielded outputs. This global budget ensures that the worst-case shielded sync bandwidth per block is bounded regardless of which combination of pools is used. These limits do not apply to the transparent components of transactions. The overall 2 MB block size limit continues to apply as before. #### Rationale: Compact sync bandwidth per action The limits above are chosen to bound the worst-case bandwidth that lightweight wallets must download for shielded sync. The Light Wallet Protocol represents both Orchard and Ironwood actions using `CompactOrchardAction`. [^lightwallet-protocol] The per-action field payload has the following costs: **Orchard and Ironwood:** 148 bytes per action, consisting of: | Field | Size | |-------|------| | cmx (note commitment) | 32 bytes | | nullifier | 32 bytes | | ephemeral public key | 32 bytes | | truncated note plaintext | 52 bytes | | **Total** | **148 bytes** | **Sapling:** 32 bytes per spend (input) and 116 bytes per output, consisting of: | Field | Size | |-------|------| | *Per spend:* nullifier | 32 bytes | | *Per output:* cmu (note commitment) | 32 bytes | | *Per output:* ephemeral public key | 32 bytes | | *Per output:* truncated note plaintext | 52 bytes | | **Per spend total** | **32 bytes** | | **Per output total** | **116 bytes** | With these limits, the worst-case compact sync bandwidth per block is: - **Orchard or Ironwood:** $330 \times 148 = 48{,}840$ bytes - **Sapling:** at most $300 \times 116 = 34{,}800$ bytes (all-output pathological case) Due to the global shielded budget, these cannot stack: a block that uses 330 Orchard and/or Ironwood actions has zero budget remaining for Sapling. The worst-case compact sync bandwidth per block is therefore always bounded by the Orchard-protocol case at 48,840 bytes. See the [Rationale](#rationale) section for the full daily bandwidth analysis. ## Effect on difficulty adjustment As with the Blossom activation [^zip-0208], the difficulty adjustment parameter $\mathsf{PoWMedianBlockSpan}$ refers to a number of blocks and does not change at activation. The change in the effective value of $\mathsf{PoWTargetSpacing}$ will cause the block spacing to adjust to the new target at the normal rate for a difficulty adjustment. See [Difficulty averaging window](#difficulty-averaging-window) in the Rationale for analysis of the $\mathsf{PoWAveragingWindow}$ change. It is likely that the difficulty adjustment for the first few blocks after activation will be limited by $\mathsf{PoWMaxAdjustDown}$. This is not anticipated to cause any problem. ## Minimum difficulty blocks on Testnet On Testnet, the minimum-difficulty block threshold defined in ZIP 205 [^zip-0205] and modified by ZIP 208 [^zip-0208] is changed at the Testnet NU7 activation height. For a block at height $\mathsf{height} \geq 299188$, the threshold is $6 \cdot \mathsf{PoWTargetSpacing}(\mathsf{height})$ seconds before NU7 activation and $18 \cdot \mathsf{PoWTargetSpacing}(\mathsf{height})$ seconds from NU7 activation onward. The latter is $18 \times 25 = 450$ seconds. A block is a minimum-difficulty block only if its block time is *strictly greater* than this threshold after the preceding block's time. Thus, at and after Testnet NU7 activation, a gap of 450 seconds does not qualify, while a gap of 451 seconds does. In that case, the block's `nBits` field MUST be set to $\mathsf{ToCompact}(\mathsf{PoWLimit})$ as specified by ZIP 208. This change does not affect Mainnet. ## Non-consensus node behaviour ### Default expiry delta When not overridden by the `-txexpirydelta` option, node implementations that create transactions use a default expiry delta. The current default of 40 blocks (approximately 50 minutes at 75-second spacing) SHOULD change to $\mathsf{NU7PoWTargetSpacingRatio} \times 40 = 120$ blocks after activation, to maintain the approximate expiry time of 50 minutes. If the `-txexpirydelta` option is set, then the set value SHOULD be used both before and after activation. ### Block-count-based constants The following constants, measured in number of blocks, were reviewed. Implementations SHOULD scale by $\mathsf{NU7PoWTargetSpacingRatio}$ those constants that represent a time duration (marked "Scale by 3" below), and SHOULD NOT scale those whose semantics are intrinsically measured in blocks (marked "No change"): | Constant | Current | Post-activation | Notes | |---------------------------------------------|---------|-----------------|-------| | `COINBASE_MATURITY` | 100 | 100 | No change; | | `MAX_REORG_LENGTH` | 99 | 600 | Scale by 6; decoupled from `COINBASE_MATURITY` | | `TX_EXPIRING_SOON_THRESHOLD` | 3 | 3 | No change; | | `MAX_BLOCKS_IN_TRANSIT_PER_PEER` | 16 | 48 | Scale by 3 | | `BLOCK_DOWNLOAD_WINDOW` | 1024 | 3072 | Scale by 3 | | `MIN_BLOCKS_TO_KEEP` | 288 | 864 | Scale by 3; keep 6 hours worth of blocks | | `NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD` | 1728 | 1728 | No change; | This proposal is fundamentally about decreasing the target spacing, which makes the wall-clock margin shorter for any given `MAX_REORG_LENGTH`. Zebra's `MAX_REORG_LENGTH` is currently 99, set just below `COINBASE_MATURITY` (= 100) by Bitcoin-inherited convention. At Zcash's launch 150-second spacing it covered about 4.2 hours, at the current 75-second spacing about 125 minutes, and at NU7's proposed 25-second spacing only about 42 minutes. Recent incidents show consensus splits can persist beyond tens of minutes: for example, Litecoin's April 2026 MWEB incident produced a 13-block invalid chain that was later reorged out, with a ~3-hour recovery window per the postmortem [^litecoin-mweb-incident]. The optimal long-term value for `MAX_REORG_LENGTH` likely needs to change further in the future, but that is out of scope here. Raising it to 600 blocks restores the ~4.2-hour wall-clock window it provided at Zcash's launch 150-second target spacing, while `COINBASE_MATURITY` remains 100. This is more conservative than the ~125-minute window at today's 75-second spacing. Given the incident above and that the launch 150-second-spacing value predates this line of evidence, restoring the launch wall-clock margin is the safer choice. This deliberately means that a supported reorg may invalidate a mature coinbase output. That case is already a valid consequence of deep PoW reorgs in the abstract protocol model. ### Anchor selection depth ZIP 315 [^zip-0315], recommends selecting an anchor 3 blocks back from the chain tip when constructing shielded transactions. The recommended anchor depth SHOULD remain at 3 blocks after activation, reducing the average wall-clock anchor delay from ~3.75 minutes to ~1.25 minutes. This follows the same precedent set by the Blossom upgrade (ZIP 208 [^zip-0208]), which did not update the anchor depth and therefore halved delay. | Parameter | Current | Post-activation | Notes | |-----------|---------|-----------------|-------| | Recommended anchor depth | 3 blocks (~3.75 min) | 3 blocks (~1.25 min) | No change; follows Blossom precedent | The increased likelihood of forking due to block time reduction should not be concerning here. For an issue to occur when anchor depth is 3 blocks back, you must have a 4 block re-org. In the many years of Ethereum PoW, a 4 block re-org has never been observed [^lovejoy-reorg]. So we are not practically at risk of inherent randomness causing a re-org. In other POW chains, re-orgs of 4+ blocks resulted from a consensus split of some form, including the recent Litecoin attack, or an attack from a surge in hashpower. Anchor height depth is not intended to protect against those two vectors. # Rationale ## Shielded sync bandwidth analysis The per-pool block space limits are chosen so that the worst-case daily bandwidth for lightweight wallet syncing does not increase relative to the current protocol. This section presents the analysis. ### Parameters | Parameter | Value | |-----------|-------| | Block size limit | 2,000,000 bytes | | Block target spacing | 25 seconds | | Blocks per day | $ 86{,}400 / 25 = 3{,}456$ | | Compact block header size | ~90 bytes | **Orchard and Ironwood pools:** | Parameter | Value | |-----------|-------| | $\mathsf{OrchardProtocolBlockActionLimit}$ | 330 actions per pool | | Compact sync bandwidth per action | 148 bytes | | Compact bandwidth per block | $330 \times 148 = 48{,}840$ bytes | **Sapling pool:** | Parameter | Value | |-----------|-------| | $\mathsf{SaplingBlockIOLimit}$ | 300 (inputs + outputs) | | Compact sync bandwidth per spend | 32 bytes | | Compact sync bandwidth per output | 116 bytes | | Compact bandwidth per block (worst case, all outputs) | $300 \times 116 = 34{,}800$ bytes | ### Daily bandwidth comparison | Metric | Current (75s, no pool limits) | Proposed (25s, action limits) | |--------|-------------------------------|-------------------------------| | Blocks per day | 1,152 | 3,456 | | Max Orchard + Ironwood actions/block | ~617 (block-size limited) | 330 | | Max Sapling IOs/block | ~2,140 (block-size limited) | 300 | | Orchard or Ironwood compact BW/day | ~105.2 MB | 168.79 MB | | Sapling compact BW/day | ~270.38 MB | 120.27 MB | | Compact block headers/day | ~0.10 MB | 0.31 MB | | **Worst-case total BW/day** | **~270.5 MB** | **169.10 MB** | | Worst-case trial decrypts/day | ~4.8M | ~2.3M | The worst-case compact sync bandwidth is **169.10 MB/day**, a reduction of **37%** from today's worst case of approximately 270.5 MB/day. This is despite a 3× increase in block frequency and overall throughput capacity. The binding constraint is Orchard or Ironwood at 330 actions per block: $330 \times 148 \times 3{,}456 + 90 \times 3{,}456 = 169.10\textsf{ MB/day}$. The trial decryption count also decreases significantly, since the per-block action limits more than offset the 3× increase in block count. Note that the trial decrypt count is 2× the number of shielded outputs/actions, because wallets must attempt decryption with both the internal and external incoming viewing keys (IVKs). The internal IVK detects change outputs sent back to the wallet, while the external IVK detects incoming payments. In principle, wallets could avoid trial decrypts with their IVK assuming other sync trade-offs are taken, but current Sapling and Orchard-protocol wallets always attempt both. ### Normal transaction throughput For standard 2-action Orchard or Ironwood transactions, the action limit of 330 allows $\lfloor 330 / 2 \rfloor = 165$ transactions per block, giving: $$\mathsf{orchard\_protocol\_tps} = 165 \;/\; 25 = 6.6 \textsf{ TPS}$$ For comparison, the current protocol (75s blocks, block-size limited) supports approximately 2.9 TPS for 2-action Orchard transactions. This is a **2.3× increase** in normal Orchard throughput. **Sapling throughput.** For standard Sapling transactions (2 spends + 2 outputs = 4 IOs), the limit of 300 IOs allows $\lfloor 300 / 4 \rfloor = 75$ transactions per block, giving $75 / 25 = 3.0$ TPS. Even with the reduced Sapling limit, the post-NU7 Sapling TPS (3.0) still exceeds the current pre-NU7 Orchard TPS (2.9). ### Fee incentives and DoS resistance A concern with per-pool limits is that a DoS attacker could fill one pool's budget to crowd out transactions in another pool. The global shielded budget prevents this from being worse than filling any single pool, but it is worth examining whether fee incentives create an asymmetry. Under ZIP 317 [^zip-0317], the conventional fee is based on *logical actions*: each Sapling output or spend counts as one logical action, and each Orchard or Ironwood action counts as one logical action. The marginal fee per logical action is the same regardless of pool. Therefore, an attacker gains no fee advantage from choosing one pool over another. The cost per unit of shielded budget consumed is identical. Furthermore, because the global shielded budget is shared, filling one pool's budget necessarily reduces the remaining budget for all other pools by the same amount. An attacker who spends their entire budget on Sapling spam at 300 IOs leaves only 30 Orchard or Ironwood actions available in that block. But this attack is no cheaper than filling 330 Orchard or Ironwood actions directly, since the per-action fee is the same. The global budget ensures that the total shielded sync cost per block is bounded to 330 units regardless of the attacker's pool choice. The 330-action per-pool cap also allows either Orchard or Ironwood transactions to use the full global budget when other shielded pools are not used. ## Difficulty averaging window [difficulty-averaging-window] This proposal increases $\mathsf{PoWAveragingWindow}$ from 17 to 102 at NU7 activation (specified in [Averaging window](#averaging-window) under Consensus changes), so that the wall-clock smoothing window is $102 \times 25 = 17 \times 150 = 2{,}550$ seconds — the same wall-clock window the value $\mathsf{PoWAveragingWindow} = 17$ was originally chosen to provide at Zcash's launch target spacing of 150 s. At today's 75 s spacing the same value covers only 1,275 s, and at NU7's proposed 25 s spacing it would cover only 425 s. The motivations are: 1. To preserve the wall-clock duration over which difficulty is smoothed, so that NU7 does not amplify difficulty-manipulation attacks like the one recently observed on Litecoin [^litecoin-mweb-incident]. 2. As an additional improvement over keeping $\mathsf{PoWAveragingWindow} = 17$, to reduce the standard deviation of block-spacing averages over short rolling windows. Under a Zebra difficulty-adjustment simulator [^daa-recovery-benchmark] with a stable hash rate and with $\mathsf{PoWAveragingWindow} = 17$ unchanged across the transition, the expected block spacing recovers to within 5% of the new 25 s target within 62 blocks of NU7 activation: | Expected spacing | Blocks after activation | Wall-clock | |-----------------------|-------------------------|------------| | 75 s (pre-NU7 target) | — | — | | 56.8 s (activation) | 0 | — | | $\leq 30$ s | 30 | \~21 min | | $\leq 26.25$ s | 62 | \~36 min | Setting $\mathsf{PoWAveragingWindow} = 102$ is expected to require roughly 6× as many blocks to cross each threshold, which is the same wall-clock duration as recovery would have taken at Zcash's launch 150 s spacing with $\mathsf{PoWAveragingWindow} = 17$. For a real-world reference point, the Blossom upgrade [^zip-0208] made a 2× target-spacing reduction (150 s → 75 s) with $\mathsf{PoWAveragingWindow}$ unchanged; mainnet block spacing (20-block rolling average) reached approximately 74 s at height 653,664 — 64 blocks after activation. Two geographically-distributed devnets of 99 Zebra nodes across 14 regions (1 vCPU per node), one at $\mathsf{PoWAveragingWindow} = 17$ and one at 51, confirmed a \~1-second reduction in the standard deviation of 5- and 10-block rolling-average block spacings. The variance reduction is expected to be somewhat larger at $\mathsf{PoWAveragingWindow} = 102$. # Deployment This proposal is intended to be deployed as part of NU7, should tokenholder polling and developer consensus agree on it. A separate ZIP will specify the deployment details including activation heights and consensus branch IDs. # References [^BCP14]: [Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14) [^protocol]: [Zcash Protocol Specification, Version 2025.6.3 or later](protocol/protocol.pdf) [^protocol-networks]: [Zcash Protocol Specification, Version 2025.6.3. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks) [^protocol-constants]: [Zcash Protocol Specification, Version 2025.6.3. Section 5.3: Constants](protocol/protocol.pdf#constants) [^protocol-diffadjustment]: [Zcash Protocol Specification, Version 2025.6.3. Section 7.7.3: Difficulty adjustment](protocol/protocol.pdf#diffadjustment) [^protocol-txnencoding]: [Zcash Protocol Specification, Version 2025.6.3. Section 7.1: Transaction Encoding and Consensus](protocol/protocol.pdf#txnencoding) [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) [^zip-0205]: [ZIP 205: Deployment of the Sapling Network Upgrade](zip-0205.rst) [^zip-0206]: [ZIP 206: Deployment of the Blossom Network Upgrade](zip-0206.rst) [^zip-0208]: [ZIP 208: Shorter Block Target Spacing](zip-0208.rst) [^zip-0229]: [ZIP 229: Version 6 Transaction Format](zip-0229.md) [^zip-0315]: [ZIP 315: Best Practices for Wallet Implementations](zip-0315.rst) [^zip-0317]: [ZIP 317: Proportional Transfer Fee Mechanism](zip-0317.rst) [^crosslink]: [Crosslink — a Zcash Finality Protocol](https://electric-coin-company.github.io/zcash-crosslink/) [^slowfastblocks]: [On Slow and Fast Block Times](https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/) [^syncsimulator]: [Shielded Sync Simulator](https://nu7syncsimulator.valargroup.dev/) [^lightwallet-protocol]: [Zcash Light Wallet Protocol v0.5.0: `compact_formats.proto`](https://github.com/zcash/lightwallet-protocol/blob/v0.5.0/walletrpc/compact_formats.proto) [^lovejoy-reorg]: [Lovejoy, James P. (2020). *An Empirical Analysis of Chain Reorganizations and Double-Spend Attacks on Proof-of-Work Cryptocurrencies.* M.Eng. thesis, Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science.](https://static1.squarespace.com/static/6675a0d5fc9e317c60db9b37/t/66eb3560532516773c4f7ece/1726690657755/LovejoyJamesP-meng-eecs-2020+%281%29.pdf) [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) [^verification-benchmark]: [Zebra worst-case block verification benchmark (`worst_case_tx_verification.rs`)](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-consensus/benches/worst_case_tx_verification.rs) [^daa-recovery-benchmark]: [Zebra difficulty-adjustment recovery simulator: `benchmark_hash_rate_shock_daa_configurations` in `zebra-state/src/service/check/difficulty.rs`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L555). The 3× target-spacing transition is exercised by [`simulate_three_x_target_spacing_reduction`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L397) in the same file. [^litecoin-mweb-incident]: [Litecoin MWEB Security Incident Postmortem](https://litecoin.com/news/litecoin-mweb-security-incident-postmortem)