Release 0.8.1: spend legacy Orchard notes after NU6.3 - #39
Merged
Merged
Conversation
A send that spent an Orchard-pool note after NU6.3 failed with `Orchard proof generation failed: Prover(ProofFailed(InvalidInstances))` and broadcast nothing. Such notes are not only those received before activation (mainnet block 3,428,143): software that keeps change in the Orchard pool still creates them in v6 transactions after it, so the note's age does not matter. From NU6.3 the Orchard pool is on protocol V3, whose bundles must disable cross-address transfers, and only the post-NU6.3 circuit constrains that flag. The PCZT send path proved the Orchard bundle with the NU6.2 (`FixedPostNu6_2`) key regardless, which the prover refuses for a bundle carrying the flag. The fused builder never had the problem, because it derives the circuit from the transaction's consensus branch. The send path now does the same. `orchard_circuit_for_branch` names the circuit from the proposal's branch, and it travels with the PCZT through both the inline and the pipelined paths, so the prove step uses the cached key for that circuit and an Orchard-only transaction is verified with the matching verifying key. A transaction mixing Orchard spends with Ironwood outputs already let the extractor derive its keys per bundle. The regtest tier could not see it: NU6.3 activates at height 8, before any coinbase matures, so every funded wallet only ever held Ironwood notes. `regtest_orchard_v2_spend` activates it at 200 instead, funds a wallet with a legacy Orchard note before that, and pays a different wallet after it. Without this change it fails with exactly the error above.
emersonian
force-pushed
the
port-081
branch
2 times, most recently
from
September 25, 2026 20:51
f004541 to
b053cc1
Compare
emersonian
force-pushed
the
port-081
branch
from
September 27, 2026 21:49
b053cc1 to
ff6b412
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On 0.8.0, any send that spends a legacy Orchard-pool note after NU6.3 fails with
Orchard proof generation failed: Prover(ProofFailed(InvalidInstances))and broadcasts nothing. The note's age does not matter: besides notes received before activation (mainnet block 3,428,143), software that keeps change in the Orchard pool still creates them in v6 transactions afterwards. Only the PCZT send path is affected; sends through the fused builder (Sapling spends, transparent sources,z_shieldcoinbase,z_mergetoaddress) already chose the right key.Cause
From NU6.3 the Orchard pool is on protocol V3, whose bundles must disable cross-address transfers (consensus-mandated), and only the post-NU6.3 circuit constrains that flag.
BundleVersion::circuit_versionmaps both V3 pools toPostNu6_3, and the fused builder derives its key from the consensus branch accordingly. The PCZT send path instead proved every Orchard bundle with theFixedPostNu6_2key, whichProof::createrefuses for a bundle carrying the flag.Fix
orchard_circuit_for_branchderives the Orchard bundle's circuit from the proposal's consensus branch; it travels with the PCZT through the inline and pipelined paths.Test
The regtest tier activates NU6.3 at height 8, before any coinbase matures, so no funded wallet ever held an Orchard-pool note across activation.
regtest_orchard_v2_spendactivates it at 200 instead, funds a wallet with a legacy Orchard note before that, pins the spend's input pool to Orchard, and pays a different wallet after activation, requiring the transaction to be mined. It passes with this change and fails without it, with exactly the error above.Release
Release 0.8.1: CHANGELOG, version, lockfile, and the license bundle's version line. A drop-in upgrade from 0.8.0.