Skip to content

fix!: address Ironwood review findings across mempool, consensus, rpc, and state - #10884

Merged
mergify[bot] merged 11 commits into
mainfrom
ironwood-review-fixes
Jul 2, 2026
Merged

fix!: address Ironwood review findings across mempool, consensus, rpc, and state#10884
mergify[bot] merged 11 commits into
mainfrom
ironwood-review-fixes

Conversation

@upbqdn

@upbqdn upbqdn commented Jul 2, 2026

Copy link
Copy Markdown
Member

Motivation

A multi-agent review of #10762 surfaced a set of Ironwood gaps — mostly in the pool-enumeration sites that must be updated in lockstep for each new shielded pool (mempool, RPC, metrics, indexer) — plus two panic/robustness issues, a latent type-safety fragility, and leftover ZIP-235 dead code. This fixes them and deduplicates the Orchard→Ironwood copy-paste.

Solution

Correctness:

  • consensus: enforce the coinbase output-decryptability rule (ZIP-213, all-zero OVK) for the Ironwood pool — it was only applied to Sapling/Orchard, but NU6.3+ routes shielded coinbase value into Ironwood.
  • mempool: track Ironwood nullifiers in VerifiedSet and reject_and_remove_same_effects, so conflicting Ironwood spends can't co-exist in a template that every node then rejects.
  • consensus: fail closed instead of unreachable!-panicking the shared halo2 verifier on an unexpected BatchError.
  • state: include Ironwood in supply metrics and the indexer spend index; fall back to the empty Ironwood tree during the brief post-v27→v28, pre-genesis-backfill window instead of panicking.
  • rpc: expose an ironwood section in verbose getrawtransaction/getblock.
  • chore: remove the dead zip235 cfg + SubsidyError::InvalidZip233Amount variant (no build enforced it).

Type safety:

  • chain: the history-tree functions took sapling_root/orchard_root/ironwood_root as adjacent positional arguments; the Orchard and Ironwood roots reuse the same orchard::tree::Root type, so a swapped pair compiled cleanly and would silently corrupt the ZIP-221 commitment. Group them in a named BlockCommitmentTreeRoots struct so a swap can't happen.

Refactor (no behavior change):

  • delegate update_ironwood_note_commitment_tree to the Orchard version; share queue_orchard_bundle (verifier resolved lazily, only when a bundle is present); share orchard_shaped_object in the RPC layer; share add_/remove_note_commitment_tree_and_anchor for the reorg paths; route the Orchard/Ironwood note-commitment DB accessors through CF-parameterized helpers (public signatures unchanged).

Tests

Full local gate green: fmt --check, clippy --all-features -D warnings, check --locked, cargo +nightly udeps, doc -D warnings, cargo vet, and the CI-profile nextest (1069/1069). The reorg-method and history-tree refactors are covered by the existing non_finalized_state prop + reorg and history_tree vector suites. Changelog entries drafted from ziff --changelog.

Specifications & References

Follow-up Work

None outstanding.

AI Disclosure

  • No AI tools were used in this PR
  • AI tools were used: Claude ran the multi-agent review, implemented the fixes, and drafted this description.

PR Checklist

  • The PR title follows conventional commits format
  • The PR follows the contribution guidelines.
  • This change was discussed in an issue or with the team beforehand.
  • The solution is tested.
  • The documentation and changelogs are up to date.

Comment thread zebra-consensus/src/primitives/halo2.rs
arya2
arya2 previously approved these changes Jul 2, 2026
Comment thread zebra-chain/src/primitives/zcash_note_encryption.rs
Comment thread zebra-consensus/src/transaction.rs
Base automatically changed from nu63-ironwood to main July 2, 2026 17:31
@mergify
mergify Bot dismissed arya2’s stale review July 2, 2026 17:31

The base branch was changed.

upbqdn added 11 commits July 2, 2026 20:01
…od pool

NU6.3+ routes shielded coinbase value into the Ironwood pool, but
`decrypts_successfully` only iterated the Sapling and Orchard bundles, so
the all-zero-OVK coinbase decryptability rule (ZIP-213) was never applied to
Ironwood coinbase outputs. Add the Ironwood arm using `IronwoodDomain`.
`VerifiedSet` tracked sprout/sapling/orchard nullifiers but not Ironwood, so
two mempool txs revealing the same Ironwood nullifier were both admitted, and
`reject_and_remove_same_effects` never evicted a mempool tx double-spending a
just-mined Ironwood nullifier. Either lets `getblocktemplate` build a block
template that every node then rejects. Mirror the Orchard handling for the
Ironwood pool.
…batch error

The `RestrictionUnsupportedByKey` arm called `unreachable!` inside the shared,
long-lived halo2 verifier service, so a future routing change or new
`#[non_exhaustive]` `BatchError` variant would crash the node instead of
rejecting one proof. Collapse it into the existing graceful per-item arm; the
routing invariant is kept as a comment.
…exing

`value_pool_metrics`/`chain_supply.total` omitted the Ironwood pool, so total
supply under-reported it every block post-NU6.3; and the `indexer` back-fill's
spend-sampling chain skipped Ironwood-only v6 txs. Add the Ironwood gauge, the
supply sum term, and Ironwood to the sampled spends.
`getrawtransaction <txid> 1` / `getblock <hash> 2` serialized an `orchard`
section but no `ironwood` one, so v6 Ironwood bundles (including Zebra's own
Ironwood coinbase) were invisible to explorers and wallets. Add an `ironwood`
field reusing the Orchard-shaped object, and factor the shared construction
into `orchard_shaped_object` (also dropping an incidental O(n^2) action scan).
…paths

Ironwood reuses the Orchard tree and bundle types, so
`update_ironwood_note_commitment_tree` now delegates to the Orchard version
(re-tagging only the error variant), and `verify_orchard_v6_bundle` /
`verify_orchard_bundle` share a `queue_orchard_bundle` helper. No behavior
change.
The ZIP-235 burn validation and its tests were removed, but the `zip235`
`cfg` value and `SubsidyError::InvalidZip233Amount` (gated on it) remained, so
a `--cfg zcash_unstable="zip235"` build compiled yet enforced nothing. Drop
both; they can return with the NU7 NSM implementation.
…ackfill

`ironwood_tree_by_height` panicked when the Ironwood column family was still
empty, which happens in the brief window after a v27->v28 upgrade before the
background `add_ironwood_tree` migration backfills genesis. That window is
always pre-NU6.3, when the Ironwood tree at every height is in fact empty, so
return the empty tree instead of panicking.
…e logic

`add_/remove_{orchard,ironwood}_tree_and_anchor` were verbatim copies over
identically-typed field triples, including the reorg `RevertPosition::Root`
invariant-restoration. Extract shared `add_/remove_note_commitment_tree_and_anchor`
helpers parameterized on the target fields and a pool label. No behavior change
(non-finalized-state prop + reorg tests pass).
The history-tree functions took `sapling_root`, `orchard_root`, and
`ironwood_root` as adjacent positional arguments; the Orchard and Ironwood
roots reuse the same `orchard::tree::Root` type, so a swapped pair compiled
cleanly and would silently corrupt the ZIP-221 chain-history commitment.
Group them in a named `BlockCommitmentTreeRoots` struct so a swap can't happen.
The Ironwood tree-range, subtree-list, subtree-for-tip, tree-create, and
subtree-insert accessors were verbatim copies of their Orchard counterparts,
differing only in the column-family name (both pools reuse the `orchard::tree`
types). Route them through CF-parameterized private helpers; the public
signatures are unchanged.
Copilot AI review requested due to automatic review settings July 2, 2026 18:02
@upbqdn
upbqdn force-pushed the ironwood-review-fixes branch from 48a3ac0 to 433c3d3 Compare July 2, 2026 18:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@conradoplg conradoplg changed the title fix: address Ironwood review findings across mempool, consensus, rpc, and state fix!: address Ironwood review findings across mempool, consensus, rpc, and state Jul 2, 2026
@mergify mergify Bot added the queued label Jul 2, 2026
@mergify

mergify Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 44 minutes 11 seconds in the queue, including 33 minutes 14 seconds running CI.

Required conditions to merge

mergify Bot added a commit that referenced this pull request Jul 2, 2026
@mergify
mergify Bot merged commit 138a830 into main Jul 2, 2026
172 of 176 checks passed
@mergify
mergify Bot deleted the ironwood-review-fixes branch July 2, 2026 19:26
@mergify mergify Bot removed the queued label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants