feat: add Zcash Shielded Assets (ZSA) support (draft)#10628
feat: add Zcash Shielded Assets (ZSA) support (draft)#10628oxarbitrage wants to merge 577 commits into
Conversation
…ding to #37 review remarks
…y.rs as it causes several tests to fail
…saction::arbitrary_with function in zebra-chain/src/transaction/arbitrary.rs
… zebra-chain/src/transaction/arbitrary.rs
… the same as in librustzcash
…ptance tests in ci-basic.yml
|
Thanks for this work — the We see two paths forward: Option A (preferred): We extract the minimal ZSA changeset and port it onto current main, reconciling with Ironwood V6 as we go. We review, fix, and iterate there. Main has diverged by 202 commits / 499 files since the
Tests (~62 files, ~1,200 lines) would come after the port compiles. We can take a first pass at this port if that would be helpful. Option B: We continue reviewing on this branch as-is. Faster to start but the V6 format reconciliation with Ironwood would need to happen anyway. Here are the high-level concerns from our first pass. We're not going into code-level details yet — those would come as inline comments during the port or a deeper review: A. V6 format divergence with Ironwood. Main now has its own V6 transaction support (Ironwood, NU6.3) with a different structure — newtypes ( B. All dependencies point to QED-it forks. C. Consensus validation architecture. D. Lockbox disbursement check relaxed. In E. Burn validation upstream coverage. ZIP 226 requires three burn rules: no native-asset burns ( |
Closes #10883
Motivation
This PR adds draft Zebra support for Zcash Shielded Assets (ZSA / OrchardZSA), following the current NU7 candidate ZIPs 226, 227, 230, and 246.
ZSA extends the Orchard protocol to support custom shielded assets that can be issued, transferred, and burned within the Orchard pool using transaction V6. Supporting ZSA in Zebra requires:
Solution
The new V6/ZSA consensus, state, and RPC paths are gated behind
zcash_unstable = "nu7"andtx_v6, so they are not enabled in normal builds without those flags.zebra-chainTransaction V6
Transaction::V6with a ZSA Orchard bundle, an optionalIssueData(issuance bundle), and azip233_amountfield (ZIP 233 network sustainability amount).TX_V6_VERSION_GROUP_ID.ShieldedDataFlavorabstractionShieldedDataFlavortrait to unify V5 (Orchard vanilla) and V6 (OrchardZSA) shielded data handling.Action,AuthorizedAction, andShieldedDataare now generic over aFlavor.OrchardVanillaandOrchardZSAare concrete flavor types with different associatedEncryptedNotesizes (580 vs 612 bytes, per ZIP 230) and burn types (NoBurnvsBurn).ENABLE_ZSAflag (bit 2 of the Orchard flags field), valid only in V6.orchard_zsamodule (new)issuance: wrapsorchard::IssueBundle<Signed>asIssueData, with serialization and note-commitment iteration.burn: definesBurnItem,Burn,NoBurn, andcompute_burn_value_commitment(for the adjusted value balance check with burned assets).asset_state: definesAssetState(wrappingorchard::AssetRecord),IssuedAssetChanges, andAssetStateError.IssuedAssetChanges::validate_and_get_changesrunsverify_issue_bundleandvalidate_bundle_burn, and is the single entry point for consensus-level asset state updates.Other changes
ValueCommitment::newextended to accept anAssetBasefor ZSA value commitments.orchard_note_commitments()iterators changed to yield values by copy (required by the flavored generics).zcash_primitives::consensus::BlockHeight→zcash_protocol::consensus::BlockHeightimport update.zebra-consensusENABLE_ZSAflag gating and rejects coinbase transactions that set it.transaction_sighashesinSemanticallyVerifiedBlock. This is required because issuance bundle signature verification is keyed on the sighash, which must be available at state-commit time.zebra-consensus/src/orchard_zsa.rsmodule with ZSA-specific consensus checks and tests.nAssetCreations), using a conservative placeholder while the upstreamlibrustzcash/orchardAPIs are still being finalized.zebra-stateIssuedAssetChangesfromSemanticallyVerifiedBlockthrough the state write path.Chain(non-finalized state) to accumulate and roll back issued-asset changes per block.orchard_issued_assetscolumn family to the RocksDB-backed finalized state, persisting asset state keyed byAssetBase.ReadRequest::AssetState { asset_base, include_non_finalized }/ReadResponse::AssetState(Option<AssetState>)pair, with aread::asset_state()helper that merges non-finalized and finalized views.zebra-rpcgetassetstateRPC method (declared unconditionally in theRpctrait; returns an error whentx_v6is disabled) accepting a hex-encoded asset base and an optionalinclude_non_finalizedflag.getrawtransaction(verbosity 1) andgetblock(verbosity 2) output:zip233amount,burnexists,issuanceexists, and OrchardenableZSA.zebra-testorchard-zsa-workflow-block-{1..5}.txt) exercising a complete lifecycle: issue 1000 units → transfer → burn 7 and 2 → finalize issuance → reject a subsequent issuance of 2000 (to verify the finalized flag is enforced).Tests
AssetStatebyte round-trip and invalid-data,IssuedAssetChangesvalidation,BurnItem/Burnround-trips,EncryptedNoteproptest round-trips for both flavors,ENABLE_ZSAflag gating in arbitrary generation, ZSA consensus check unit tests.zebra-consensus/src/orchard_zsa/tests.rs::check_orchard_zsa_workflow— drives a small regtest chain of ZSA workflow blocks (issue, transfer, burn) through the full Zebra node pipeline (deserializer → consensus router → state service) via theTranscripttest engine, asserting each block is accepted or rejected at the expected point and that the final state reflects the correct asset supply; mempool vector and property tests updated for V6 transactions.getassetstateRPC responses (success, not found, finalized-only, invalid hex, wrong length, invalid asset base) and updatedgetrawtransaction/getblocksnapshots.Specifications & References
zsa1branch)zsa1branch)AI Disclosure
PR Checklist
v4.2.0-devtarget branch was created by the Zebra maintainers for this purpose.)