ZIP: 248
Title: Extensible Transaction Format
Owners: Jack Grigg <thestr4d@gmail.com>
Kris Nuttycombe <kris@nutty.land>
Daira-Emma Hopwood <daira@jacaranda.org>
Schell Scivally <efsubenovex@gmail.com>
Status: Draft
Category: Consensus / Wallet
Created: 2025-12-17
License: MIT
Discussions-To: <https://github.com/zcash/zips/pull/1163>
Pull-Request: <https://github.com/zcash/zips/pull/1156>
The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in BCP 14 1 when, and only when, they appear in all capitals.
The character § is used when referring to sections of the Zcash Protocol Specification. 2
The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 ‘Mainnet and Testnet’. 4
The term "full validator" in this document is to be interpreted as defined in § 3.3 ‘The Block Chain’. 3
The terms "Orchard protocol", "Orchard pool", and "Ironwood pool" are to be interpreted as described in ZIP 229. 10 Following the convention in the Zcash Protocol Specification, slanted text refers to pool names, to distinguish them from shielded protocols.
The terms below are to be interpreted as follows:
This ZIP proposes an encoding for V7 Zcash transactions that is intended to reduce the impact of future changes to the Zcash transaction format on the Zcash ecosystem. It defines a new typecode-length-value encoding for a sequence of protocol bundles, and a "value balance" map that describes the effect of each bundle on the transparent transaction value pool for each asset. The entries of this map serve the same purpose as the Sapling and Orchard value balance fields have done in the past.
In the past, Zcash network upgrades that changed the transaction format have resulted in substantial disruption for wallets and other third-party clients in the Zcash ecosystem. In order to continue functioning after a network upgrade, clients were required to upgrade their Zcash transaction parsers to read the new format, even if the context in which those parsers were being used didn't need or couldn't make use of newly added transaction data. An example of this is that transparent-only wallets were forced to update their parsers to understand the Sapling and Orchard parts of transactions, even if they would never read or act upon those parts. This has led on occasion to significant problems in the Zcash ecosystem, including situations where funds have been locked and rendered unspendable from transparent-only wallets.
For some kinds of changes to consensus features, it's imperative that every wallet be aware of and be adapted to those changes, and in those cases making a major (breaking) transaction version update as we've done in the past is appropriate. For many new features, however, it is possible for a wallet to continue functioning correctly without having to fully understand a transaction using that feature.
For example, if TZEs were to be added to the protocol, it would be possible for wallets to continue operating with transparent/Sapling/Orchard functionality, ignoring TZE parts. There is substantial precedent for this sort of behavior; transparent-only hardware wallets are currently still important in the Zcash ecosystem, and many wallets didn't begin interacting with Orchard transaction parts until quite a while after Orchard activation.
After this change to transaction encoding, wallets and other third parties will not be required to update their transaction parsers in advance of a network upgrade for the introduction of many (and perhaps most) types of new protocol features. This will enable the Zcash ecosystem to make smaller and more incremental network upgrades without breaking existing wallets.
This change alters the encoding of transactions, but does not alter the information content of the transaction. As such, the only implication of this change is that the use of this transaction format acts as a 1-bit distinguisher that reveals that the wallet that generated the transaction has been updated to be aware of the new format. This information leakage is unavoidable for any transaction format change.
In the future, this change may reduce the amount of information leakage, since transactions created using the proposed TLV format will include bundles only for those protocols for which the transaction modifies chain state. For example, if this transaction format change is deployed in NU8 and a hypothetical NU9 defines a bundle type for TZE components, it will not be possible for a chain observer to distinguish whether or not the wallet that produced an Orchard-only transaction is one that has been updated to understand the TZE component. Under prior practices for changing the transaction format, this would have been distinguishable.
In summary, this proposal provides a net improvement in user privacy in addition to its other benefits.
This ZIP refines and codifies the concept of "protocol bundles" that emerged from the implementation of the ZIP 225 9 transaction format. It makes bundles first-class objects and defines a registry of bundle type and variant identifiers. Within the period that a given transaction format version is used on the Zcash network, the semantics of the bundle associated with a given (bundleType, bundleVariant) pair are fixed.
A protocol bundle is a self-contained component of a transaction that implements a specific piece of protocol functionality. Each bundle is identified by a (bundleType, bundleVariant) pair, where:
A transaction MUST NOT contain more than one variant of any given bundle type. This constraint is enforced by the map structure of the transaction encoding: the maps mEffectBundles, and mAuthBundles are each keyed by bundleType alone; mValuePoolDeltas is keyed by bundle type and asset ID.
Each bundle type/variant pair defines:
The transparent transaction value pool is an ephemeral concept that exists only within the scope of processing a single transaction. It serves as a balancing mechanism through which value flows between bundles.
Each bundle may contribute a value pool delta — a signed value indicating how much the bundle adds to or removes from the transparent transaction value pool for a given asset. A positive delta means the bundle is adding value to the pool (e.g., a shielded spend releasing value), while a negative delta means the bundle is consuming value from the pool (e.g., a shielded output absorbing value, or a transaction fee).
For a valid transaction, the sum of all value pool deltas for each asset MUST equal zero. This ensures that value is neither created nor destroyed — it is only transferred between bundles within the transaction.
This holds for coinbase transactions as well. The part of the block subsidy that the transaction pays out enters the transparent transaction value pool as the value pool delta of the coinbase bundle, and the fees collected from the other transactions in the block enter it as the value pool delta of the fee bundle; the coinbase outputs then consume that value like any other bundle.
When a ZIP introduces a new bundle type or a new variant of an existing bundle type, it MUST:
(bundleType, bundleVariant) pair in the registry defined below. The bundleType and bundleVariant are each non-negative integers. If the ZIP introduces a new bundle type, it requests a new bundleType value with bundleVariant 0. If it introduces a new variant of an existing bundle type, it requests a new bundleVariant value for the existing bundleType.mValuePoolDeltas (the value pool delta map).mEffectBundles (the effecting data map).mAuthBundles (the authorizing data map).A bundle type MUST NOT permit entries in mAuthBundles unless it also permits entries in mEffectBundles. That is, authorizing data cannot exist without corresponding effecting data for a given bundle type.
Once a (bundleType, bundleVariant) pair is assigned for a given transaction version, its semantics are fixed for the lifetime of that transaction version. A subsequent network upgrade may define a new transaction version that reassigns identifiers or changes bundle semantics, but within a single transaction version, bundle type and variant identifiers have stable, unchanging meanings.
A new variant of an existing bundle type MUST affect the same value pool(s) as the original bundle type. This ensures that a client that does not recognize a particular bundleVariant can still determine which pool(s) are affected by the bundle and inform its user accordingly.
The following (bundleType, bundleVariant) pairs are registered for the V7 transaction format. All currently-defined values are encoded as single-byte compactSize values where they appear in the transaction format.
The mValuePoolDeltas column indicates whether or not an entry for this bundle type MAY appear in mValuePoolDeltas. For rows where an ❌ is present, the value pool delta for every pool is guaranteed to be zero, and so entries in mValuePoolDeltas MUST NOT be present.
The mEffectBundles column indicates whether or not an entry for this bundle type MAY appear in mEffectBundles. For rows where an ❌ is present, the bundle has no effecting data, and so an entry in mEffectBundles MUST NOT be present.
The mAuthBundles column indicates whether or not an entry for this bundle type MAY appear in mAuthBundles. For rows where an ❌ is present, the bundle has no authorizing data, and so an entry in mAuthBundles MUST NOT be present.
| BundleType | BundleVariant | mValuePoolDeltas |
mEffectBundles |
mAuthBundles |
Defining ZIP | Bundle kind |
|---|---|---|---|---|---|---|
| 0 | 0 | ✅ | ✅ | ✅ | This ZIP | Transparent |
| 1 | 0 | ✅ | ✅ | ❌ | This ZIP | Coinbase |
| 2 | 0 | ✅ | ✅ | ✅ | This ZIP | Sapling |
| 3 | 0 | ✅ | ✅ | ✅ | This ZIP | Orchard |
| 4 | 0 | ✅ | ✅ | ✅ | This ZIP | Ironwood |
| 5 | 0 | ✅ | ❌ | ❌ | ZIP 2002 | Transaction fee |
| 6 | 0 | ✅ | ❌ | ❌ | ZIP 233 | ZIP 233 NSM field |
Additional bundle types or variants MAY be added to this registry via modifications to this ZIP specified in other ZIPs. Such modifications MUST specify all of the information required by the Bundle Type Registration section above.
The following bundle kinds have no allocated (bundleType, bundleVariant) pair. Where a bundle type is given, the kind is a new variant of that existing type and only its variant identifier is unassigned. Those proposed by a ZIP name it; the rest are provided to illustrate how potential future upgrades might affect the bundle registry:
| BundleType | BundleVariant | mValuePoolDeltas |
mEffectBundles |
mAuthBundles |
Defining ZIP | Bundle kind |
|---|---|---|---|---|---|---|
| 2 | 1 (provisional) | ✅ | ✅ | ✅ | ZIP 231 | Sapling-post-ZIP 231 |
| 3 | 1 (provisional) | ✅ | ✅ | ✅ | ZIP 231 | Orchard post-ZIP 231 |
| 3 | 2 (provisional) | ✅ | ✅ | ✅ | ZIP 226 | OrchardZSA |
| 4 | 1 (provisional) | ✅ | ✅ | ✅ | ZIP 231 | Ironwood post-ZIP 231 |
| 0 | ❌ | ✅ | ✅ | ZIP 270 | Key rotation | |
| 0 | ✅ | ✅ | ✅ | TBD | Lockbox disbursement | |
| 0 | ❌ | ✅ | ❌ | ZIP 231 | Memos | |
| 0 | ✅ | ✅ | ✅ | ZIP 227 | ZSA Issuance | |
| 0 | ✅ | ✅ | ✅ | TZEs | ||
| 0 | ✅ | ✅ | ✅ | Pool that only has a long-term storage protocol (PQ, very simple thus insulated from counterfeiting fears, can be used for payments but higher latency for that purpose) | ||
| 0 | ✅ | ✅ | ✅ | Tachyon | ||
| 0 | ✅ | ✅ | ❌ | Staking | ||
| 0 | ✅ | ✅ | ✅ | Unstaking (if it can't be combined with the Staking bundle) | ||
| 0 | ✅ | ✅ | ✅ | Post-quantum fast payment protocol |
| Bytes | Name | Data Type | Description |
|---|---|---|---|
| Common Transaction Fields | |||
| 4 | header |
uint32 |
Contains:
|
| 4 | nVersionGroupId |
uint32 |
Version group ID (nonzero). |
| 4 | nConsensusBranchId |
uint32 |
Consensus branch ID (nonzero). |
| 4 | lock_time |
uint32 |
Unix-epoch UTC time or block height, encoded as in Bitcoin. |
| 4 | nExpiryHeight |
uint32 |
A block height in the range {1 .. 499999999} after which the transaction will expire, or 0 to disable expiry. 7 |
| Transaction transparent value pool balance map | |||
| varies | nValuePoolDeltas |
compactSize |
Number of entries in the mValuePoolDeltas map. |
| varies | mValuePoolDeltas |
ValuePoolDelta[nValuePoolDeltas] |
A map describing the change to the transparent value pool produced by each bundle. Only bundles that produces changes to the transparent value balance will have corresponding entries in this map. For bundles that have no data except for a value, such as the ZIP 233 amount, no additional bundle data will be present in the Bundles section. |
| Bundles | |||
| varies | nEffectBundles |
compactSize |
Number of bundles in the transaction that have per-bundle data. |
| varies | mEffectBundles |
BundleData[nEffectBundles] |
A map from bundle identifier to the effecting data of a bundle. |
| varies | nAuthBundles |
compactSize |
Number of bundles in the transaction that have per-bundle data. |
| varies | mAuthBundles |
BundleData[nAuthBundles] |
A map from bundle identifier to the authorizing data of a bundle. |
mValuePoolDeltas is interpreted as a map keyed by the tuple
\((\mathsf{BundleType}, \mathsf{AssetUuid})\kern-0.03em\textsf{.}\)
Lookups in this map are denoted with the syntax
\(\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].\)
A lookup for a key that is not present yields 0, consistent with the requirement that a record having zero value is elided from the encoding.
mEffectBundles and mAuthBundles are interpreted as maps keyed by bundleType.
Encoding constraints on these maps (uniqueness, ordering, and cross-map consistency) are specified in Parsing Rules.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
| varies | bundleType |
compactSize |
An encoding of the bundle type identifier. |
| varies | bundleVariant |
compactSize |
An encoding of the bundle variant identifier. |
| 1 | assetClass |
uint8 |
An asset class identifier. 0x00 for the ZEC asset, 0x01 for other assets. |
| one of {0, 64} | assetUuid |
byte[0] or byte[64] |
If assetClass == 0, the zero-length byte array, otherwise a byte array containing a universally unique 64-byte identifier for the asset. |
| 8 | value |
nonzero int64 |
The net change to the transparent transaction value pool for the given asset, produced by the bundle with this bundle type identifier. This value MUST be nonzero; if a ValuePoolDelta record would have zero value, it MUST be elided from the encoding of mValuePoolDeltas instead. |
Let \(\mathsf{Zec}\) be a distinguished value representing the ZEC asset. It is used as the asset identifier when \(\mathsf{assetClass} = 0\kern-0.03em\textsf{.}\)
Let
\(\mathsf{AssetUuid}(\mathsf{d})\)
be the asset indicated by the mValuePoolDeltas entry
\(\mathsf{d}.\)
\(\mathsf{AssetUuid}\)
groups the entries of mValuePoolDeltas by asset. The values of the entries in each such group are required to sum to zero; this balance rule is specified in Cross-bundle and chain-context rules.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
| varies | bundleType |
compactSize |
An encoding of the bundle type identifier. |
| varies | bundleVariant |
compactSize |
An encoding of the bundle variant identifier. |
| varies | nBundleDataLen |
compactSize |
The length of the vBundleData byte array. |
| varies | vBundleData |
byte[nBundleDataLen] |
The effecting or authorizing data for the bundle, dependent upon whether the BundleData occurs in mEffectBundles or mAuthBundles. |
The rules in this section are requirements on the byte encoding of a V7 transaction. A byte stream that violates any of these rules is not a well-formed V7 transaction and MUST be rejected by any parser, regardless of which bundle types the parser understands. Enforcement of these rules is what makes it safe for a wallet to parse, identify, and compute the transaction identifier for a transaction containing bundle types that the wallet does not itself implement.
mValuePoolDeltas, mEffectBundles, and mAuthBundles MUST contain at most one entry per key, and the entries MUST be encoded in strictly increasing key order. For mValuePoolDeltas the key order is (bundleType, assetClass, assetUuid) compared lexicographically (with assetUuid compared as a byte string). For mEffectBundles and mAuthBundles the key order is bundleType.ValuePoolDelta record MUST have a nonzero value field. A ValuePoolDelta record that would have value = 0 MUST be elided from the encoding of mValuePoolDeltas.ValuePoolDelta record, assetUuid MUST be the zero-length byte array if assetClass = 0, and MUST be a 64-byte value if assetClass = 1. No other value of assetClass is permitted.bundleType that appears in any of mValuePoolDeltas, mEffectBundles, or mAuthBundles, all entries for that bundleType across all three maps MUST encode the same bundleVariant. (This, combined with the constraint that each of mEffectBundles and mAuthBundles is keyed by bundleType, ensures that a transaction uses at most one variant of any given bundle type.)bundleType that appears in mAuthBundles, a corresponding entry with the same bundleVariant MUST exist in mEffectBundles.vSpendProofsSapling and vSpendAuthSigsSapling each have nSpendsSapling elements;vOutputProofsSapling has nOutputsSapling elements;vSpendAuthSigsOrchard has nActionsOrchard elements, and proofsOrchard aggregates exactly nActionsOrchard per-action proofs.A wallet that successfully parses a V7 transaction under these rules is guaranteed to be able to compute the transaction identifier (given, for each bundle type it does not understand, the corresponding 32-byte bundle_effects_digest value as described in Implications for Wallets), and to enumerate the transparent value flows of the transaction at the granularity of bundle types.
This ZIP requires the following modifications to the consensus rules in the Zcash Protocol Specification. These rules are additional to the parsing rules above; a transaction that satisfies the parsing rules but violates any of these consensus rules is well-formed but invalid.
Let CoinbaseBundleId be the identifier of the coinbase bundle, and FeeBundleId be the identifier of the fee bundle. In V7 transactions,
\(\mathsf{CoinbaseBundleId} = 1\)
and
\(\mathsf{FeeBundleId} = 5\)
as defined in the table above.
The following rules constrain the contents of individual bundles. A wallet or full validator only needs to enforce a given rule in this subsection if it understands the bundle type that the rule applies to.
assetClass value for any entry in mValuePoolDeltas having bundleType = FeeBundleId MUST be 0 (fee amounts are denominated in ZEC and no other asset).assetClass value for any entry in mValuePoolDeltas having bundleType = CoinbaseBundleId MUST be 0 (the block subsidy is denominated in ZEC and no other asset). The same applies to the blockSubsidy and lockboxValue fields of its effecting data.tx_in_count = 0.nSpendsSapling field of the Sapling bundle's effecting data MUST be 0.enableSpends bit of the flagsOrchard field of every Orchard protocol bundle MUST be 0.enableCrossAddress bit of flagsOrchard MUST be 0; that is, transfers into the Orchard pool are restricted to the protocol-level address of the action's spend. 15 The bit is unrestricted in an Ironwood bundle.The following rules relate the contents of a bundle to the other bundles of its transaction, or to the block that contains it. They MUST be enforced by full validators.
blockHeight field of the coinbase bundle's effecting data MUST equal the height of the block containing the transaction.blockSubsidy field of the coinbase bundle's effecting data MUST equal the block subsidy for that block, as defined in § 7.8 'Block Subsidy and Founders' Reward'. 5lockboxValue field of the coinbase bundle's effecting data MUST equal the total value that the funding streams for that block deposit into the deferred pool, as defined in § 7.10 'Payment of Funding Streams, Deferred Lockbox, and Lockbox Disbursement'. 6This ZIP introduces sighash algorithm versioning. Where previously each transaction version had a single associated sighash algorithm, going forward it is possible for signers to use any sighash algorithm within the closed set specified for a given transaction version (and made available in consensus via network upgrades).
The sighash version is encoded as a single byte alongside any associated data that the sighash algorithm version requires (for deterministically computing the digest):
sighashInfo = [sighashVersion] || associatedData
where associatedData is specific to the bundle it appears in.
Each bundle type defines the sighash algorithm versions available to its signers, the associatedData that each version requires, and the digest that a signature using it commits to. Those definitions are given for the bundle types registered by this ZIP in Bundle Definitions.
Version 0 is by convention the "commit to all effecting data" sighash algorithm. Other versions can commit to whatever makes sense for desired functionality within a given transaction version. Consensus rules choose the digest algorithm for each signer based on sighashVersion.
Sighash version information is present alongside each signature in the authorizing data of each bundle.
All digests are personalized BLAKE2b-256 hashes. In cases where no elements are available for hashing (for example, if there are no transparent transaction inputs), a personalized hash of the empty byte array will be used. The personalization string therefore provides domain separation for the hashes of even empty data fields.
The notation BLAKE2b-256(personalization_string, []) is used to refer to hashes constructed in this manner.
A new transaction digest algorithm is defined that constructs the identifier for a V7 transaction from a tree of hashes. The overall structure of the hash is as follows:
txid_digest
├── header_digest
├── value_pool_deltas_digest
└── effects_bundles_digest
├─ (bundle_type_id || bundle_variant || transparent_effects_digest)
├─ (bundle_type_id || bundle_variant || coinbase_effects_digest)
├─ (bundle_type_id || bundle_variant || sapling_effects_digest)
│ ├── sapling_spends_digest
│ │ ├── sapling_spends_compact_digest
│ │ └── sapling_spends_noncompact_digest
│ └── sapling_outputs_digest
│ ├── sapling_outputs_compact_digest
│ ├── sapling_outputs_memos_digest
│ └── sapling_outputs_noncompact_digest
├─ (bundle_type_id || bundle_variant || orchard_effects_digest)
│ ├── orchard_actions_compact_digest
│ ├── orchard_actions_memos_digest
│ └── orchard_actions_noncompact_digest
├─ (bundle_type_id || bundle_variant || ironwood_effects_digest)
│ ├── ironwood_actions_compact_digest
│ ├── ironwood_actions_memos_digest
│ └── ironwood_actions_noncompact_digest
└─ (bundle_type_id || bundle_variant || unknown_bundle_effects_digest) ...
Each node written as snake_case in this tree is a BLAKE2b-256 hash of its children, initialized with a personalization string specific to that branch of the tree. Nodes that are not themselves digests are written in camelCase. In the specification below, nodes of the tree are presented in depth-first order.
A BLAKE2b-256 hash of the following values:
T.1: header_digest (32-byte hash output) T.2: value_pool_deltas_digest (32-byte hash output) T.3: effects_bundles_digest (32-byte hash output)
The personalization field of this hash is set to:
"ZcashTxHash_" || CONSENSUS_BRANCH_ID
ZcashTxHash_ has 1 underscore character.
As in ZIP 244 12, CONSENSUS_BRANCH_ID is the 4-byte little-endian encoding of the consensus branch ID for the epoch of the block containing the transaction.
A BLAKE2b-256 hash of the following values:
T.1a: version (4-byte little-endian version identifier including overwintered flag) T.1b: nVersionGroupId (4-byte little-endian version group identifier) T.1c: nConsensusBranchId (4-byte little-endian consensus branch id) T.1d: lock_time (4-byte little-endian nLockTime value) T.1e: nExpiryHeight (4-byte little-endian block height)
The personalization field of this hash is set to:
"ZTxIdHeadersHash"
A BLAKE2b-256 hash of the concatenated encodings of all entries in mValuePoolDeltas, in transaction order. For each entry, the following values are concatenated:
T.2a: bundleType (compactSize encoding) T.2b: bundleVariant (compactSize encoding) T.2c: assetClass (1 byte) T.2d: assetUuid (0 or 64 bytes, depending on assetClass) T.2e: value (8-byte signed little-endian)
The personalization field of this hash is set to:
"ZTxIdVPDeltaHash"
In the case that the transaction has no value pool delta entries (which would only occur for transactions that have no effect on any value pool), value_pool_deltas_digest is:
BLAKE2b-256("ZTxIdVPDeltaHash", [])
A BLAKE2b-256 hash of the concatenated tagged bundle effect digests for all bundles present in mEffectBundles, in transaction order. For each bundle, the following values are concatenated:
T.3a: bundleType (compactSize encoding) T.3b: bundleVariant (compactSize encoding) T.3c: bundle_effects_digest (32-byte hash output)
where bundle_effects_digest is the root hash of the bundle's effecting data tree, as defined for each bundle type in Bundle Definitions.
The personalization field of this hash is set to:
"ZTxIdEffBnd_Hash" (1 underscore character)
In the case that the transaction has no effect bundles, effects_bundles_digest is:
BLAKE2b-256("ZTxIdEffBnd_Hash", [])
A new per-input transaction digest algorithm is defined that constructs a hash that may be signed by a transaction creator to commit to the effects of the transaction. This follows closely the algorithm from ZIP 244 12.
The digest algorithm used for a given signature is determined by the sighashVersion from the signer's sighashInfo, as specified in the Sighash Versioning section. For sighash version 0 (the only version currently defined for V7 transactions), the digest algorithm is as specified below. Future network upgrades may define additional sighash algorithm versions with divergent behavior.
For transactions that have no transparent inputs, the v0 signature digest is identical to the transaction identifier digest.
For transactions with transparent inputs, the signature digest replaces effects_bundles_digest with a signature_bundles_digest that incorporates hash_type-dependent transparent signing data:
signature_digest ├── header_digest ├── value_pool_deltas_digest └── signature_bundles_digest
A BLAKE2b-256 hash of the following values:
S.1: header_digest (32-byte hash output) S.2: value_pool_deltas_digest (32-byte hash output) S.3: signature_bundles_digest (32-byte hash output)
The personalization field of this hash is set to:
"ZcashTxHash_" || CONSENSUS_BRANCH_ID
This value has the same personalization as the transaction identifier digest, so that what is being signed in the case that there are no transparent inputs is exactly the transaction id.
If the transaction has no transparent inputs, signature_bundles_digest is identical to effects_bundles_digest.
Otherwise, signature_bundles_digest is constructed the same as effects_bundles_digest, except that transparent_effects_digest is replaced with transparent_sig_digest.
All Zcash wallets SHOULD, without undue delay, switch to sending only V7 transactions once they are allowed on the network. This applies to all transactions regardless of whether they use new V7 features.
Zcash wallets MUST support parsing V7 transactions by the time they are allowed on the network.
Because the V7 transaction format uses a type-length-value encoding for bundles, a wallet is not required to understand the internal encoding of every bundle in order to parse a transaction. However, a wallet that encounters a bundle with an unrecognized bundleType SHOULD alert the user that the transaction contains components it does not understand. A wallet that encounters a bundle with a recognized bundleType but unrecognized bundleVariant SHOULD alert the user that the transaction affects a pool the wallet is aware of, but in a way the wallet does not fully understand.
For bundle types not understood by a wallet, the wallet can compute the transaction identifier so long as it has been provided with the 32-byte bundle_effects_digest value for each bundle that it does not understand. This enables partial verification of transactions containing unknown bundle types.
A wallet MUST NOT construct or sign a transaction containing a bundle type or variant that it does not fully understand.
The sections above are independent of any particular bundle type. This section defines the bundle types that this ZIP registers: the encoding of their effecting and authorizing data, the sighash algorithm versions available to their signers, and their contributions to the digests defined in Digest Algorithms. A ZIP that registers a further bundle type defines the same things for it, as required by Bundle Type Registration.
The transparent bundle's value pool delta in mValuePoolDeltas represents the net value flowing from the transparent inputs to the transparent outputs.
A full validator MUST verify that the ZEC value pool delta for bundleType = 0 equals the total value of the transparent inputs minus the total value of the transparent outputs. (The input values are not encoded in the transaction itself; they are obtained from the UTXOs being spent.)
This rule applies to coinbase transactions unchanged. A coinbase transaction has no transparent inputs, so its transparent value pool delta is the negation of the total value of its transparent outputs; the value that those outputs consume is contributed to the transparent transaction value pool by the coinbase bundle and the fee bundle.
The effecting data for the transparent bundle describes the transparent inputs being spent and the transparent outputs being created.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
varies |
tx_in_count |
compactSize |
Number of transparent inputs. |
varies |
tx_in_effecting |
TransparentInputEffecting[tx_in_count] |
Effecting data for each transparent input. |
varies |
tx_out_count |
compactSize |
Number of transparent outputs. |
varies |
tx_out |
TransparentOutput[tx_out_count] |
Transparent outputs. |
| Bytes | Name | Data Type | Description |
|---|---|---|---|
32 |
prevout_hash |
byte[32] |
The transaction ID of the output being spent. |
4 |
prevout_index |
uint32 |
The index of the output being spent within that transaction. |
4 |
nSequence |
uint32 |
Sequence number, encoded as in Bitcoin. |
| Bytes | Name | Data Type | Description |
|---|---|---|---|
8 |
value |
int64 |
The value of the output in zatoshi. |
varies |
scriptPubKeyLen |
compactSize |
Length of the scriptPubKey. |
scriptPubKeyLen |
scriptPubKey |
byte[scriptPubKeyLen] |
The script that must be satisfied to spend this output. |
For the transparent bundle at bundleVariant = 0, sighash version 0 is the only version defined, and its associatedData is the empty byte string. A signature made with it commits to the digest defined in S.3.0: transparent_sig_digest.
In the case that transparent inputs or outputs are present, the transparent effects digest is a BLAKE2b-256 hash of the following values:
T.3.0a: prevouts_digest (32-byte hash) T.3.0b: sequence_digest (32-byte hash) T.3.0c: outputs_digest (32-byte hash)
The personalization field of this hash is set to:
"ZTxIdTranspaHash"
In the case that the transaction has no transparent components, transparent_effects_digest is:
BLAKE2b-256("ZTxIdTranspaHash", [])
A BLAKE2b-256 hash of the field encoding of all (prevout_hash, prevout_index) pairs from the transparent effecting data.
The personalization field of this hash is set to:
"ZTxIdPrevoutHash"
In the case that the transaction has transparent outputs but no transparent inputs, prevouts_digest is:
BLAKE2b-256("ZTxIdPrevoutHash", [])
A BLAKE2b-256 hash of the 32-bit little-endian representation of all nSequence field values from the transparent effecting data.
The personalization field of this hash is set to:
"ZTxIdSequencHash"
In the case that the transaction has transparent outputs but no transparent inputs, sequence_digest is:
BLAKE2b-256("ZTxIdSequencHash", [])
A BLAKE2b-256 hash of the concatenated field encodings of all transparent outputs. The field encoding of each output consists of the encoded output value (8-byte little endian) followed by the scriptPubKey byte array (with leading compactSize length).
The personalization field of this hash is set to:
"ZTxIdOutputsHash"
In the case that the transaction has transparent inputs but no transparent outputs, outputs_digest is:
BLAKE2b-256("ZTxIdOutputsHash", [])
This digest is a BLAKE2b-256 hash of the following values:
S.3.0a: hash_type (1 byte) S.3.0b: prevouts_sig_digest (32-byte hash) S.3.0c: amounts_sig_digest (32-byte hash) S.3.0d: scriptpubkeys_sig_digest (32-byte hash) S.3.0e: sequence_sig_digest (32-byte hash) S.3.0f: outputs_sig_digest (32-byte hash) S.3.0g: txin_sig_digest (32-byte hash)
The personalization field of this hash is set to:
"ZTxIdTranspaHash"
An 8-bit unsigned value. The SIGHASH encodings from the legacy script system are used: one of SIGHASH_ALL (0x01), SIGHASH_NONE (0x02), or SIGHASH_SINGLE (0x03), optionally combined with SIGHASH_ANYONECANPAY (0x80).
The following restrictions apply:
hash_type (not 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83) causes validation failure.SIGHASH_SINGLE without a corresponding output at the same index causes validation failure.If the SIGHASH_ANYONECANPAY flag is not set, identical to prevouts_digest (T.3.0a).
Otherwise:
BLAKE2b-256("ZTxIdPrevoutHash", [])
If the SIGHASH_ANYONECANPAY flag is not set, a BLAKE2b-256 hash of the concatenation of the 8-byte signed little-endian representations of all value fields for the coins spent by the transparent inputs to the transaction.
The personalization field of this hash is set to:
"ZTxTrAmountsHash"
If the SIGHASH_ANYONECANPAY flag is set:
BLAKE2b-256("ZTxTrAmountsHash", [])
If the SIGHASH_ANYONECANPAY flag is not set, a BLAKE2b-256 hash of the concatenation of the field encodings (each including a leading compactSize) of all scriptPubKey fields for the coins spent by the transparent inputs.
The personalization field of this hash is set to:
"ZTxTrScriptsHash"
If the SIGHASH_ANYONECANPAY flag is set:
BLAKE2b-256("ZTxTrScriptsHash", [])
Identical to sequence_digest (T.3.0b) regardless of hash_type.
If the sighash type is neither SIGHASH_SINGLE nor SIGHASH_NONE, identical to outputs_digest (T.3.0c).
If the sighash type is SIGHASH_SINGLE and a transparent output exists at the same index as the input being signed, a hash of that output's encoding.
Otherwise:
BLAKE2b-256("ZTxIdOutputsHash", [])
For signatures over a transparent input, a BLAKE2b-256 hash of:
S.3.0g.i: prevout (36 bytes: 32-byte hash + 4-byte index) S.3.0g.ii: value (8-byte signed little-endian) S.3.0g.iii: scriptPubKey (with compactSize length prefix) S.3.0g.iv: nSequence (4-byte unsigned little-endian)
The personalization field of this hash is set to:
"Zcash___TxInHash" (3 underscores)
For signatures over a Sapling Spend or Orchard Action:
BLAKE2b-256("Zcash___TxInHash", [])
In the case that the transaction contains transparent inputs, this is a BLAKE2b-256 hash of the following concatenated values for each transparent input:
A.1.0a: TransparentSighashInfo (field encoding bytes) A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix)
The field encoding of TransparentSighashInfo is defined in Transparent Sighash Information (``TransparentSighashInfo`)`_.
The personalization field of this hash is set to:
"ZTxAuthTransHash"
In the case that the transaction has no transparent inputs:
BLAKE2b-256("ZTxAuthTransHash", [])
A transaction is a coinbase transaction if and only if mEffectBundles contains an entry with bundleType = 1. The coinbase bundle replaces the otherwise-unspendable transparent input that identified a coinbase transaction in previous transaction versions, and carries the block height that that input was required to encode.
The block subsidy is the whole of the new issuance for the block, which consensus splits between the miner, the funding streams that pay to an address, and the funding streams that deposit into the deferred pool (the "lockbox") 14. Only the part that is not deposited into the lockbox is paid out by this transaction, so the coinbase bundle's value pool delta in mValuePoolDeltas is the block subsidy less the lockbox deposit. The fees collected from the other transactions in the block are contributed separately, as the value pool delta of the fee bundle.
The bundle's own effecting data carries the two components, as blockSubsidy and lockboxValue, so that the split is recoverable from the transaction rather than only their difference.
The coinbase bundle has no authorizing data.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
4 |
blockHeight |
uint32 |
The height of the block in which the transaction is mined. |
8 |
blockSubsidy |
uint64 |
The block subsidy for that block, in zatoshis. |
8 |
lockboxValue |
uint64 |
The part of that block subsidy deposited into the lockbox, in zatoshis. |
varies |
coinbaseDataLen |
compactSize |
Length of the coinbaseData byte array. |
coinbaseDataLen |
coinbaseData |
byte[coinbaseDataLen] |
Data chosen by the miner. Consensus assigns no meaning to its contents. |
blockHeight MUST be in the range {1 .. 499999999}.lockboxValue MUST be in the range {0 .. blockSubsidy}.coinbaseDataLen MUST be at most 94.A BLAKE2b-256 hash of the following values:
T.3.1a: blockHeight (4-byte little-endian block height) T.3.1b: blockSubsidy (8-byte unsigned little-endian) T.3.1c: lockboxValue (8-byte unsigned little-endian) T.3.1d: coinbaseData (byte array with leading ``compactSize`` length)
The personalization field of this hash is set to:
"ZTxIdCoinbasHash"
This digest is present only for coinbase transactions; a transaction that has no coinbase bundle contributes no entry for it to effects_bundles_digest.
The effecting data for the Sapling bundle describes the Sapling spends and outputs. Unlike the V5 transaction format defined in ZIP 225 9, the value balance is not included here; it appears in mValuePoolDeltas instead.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
varies |
nSpendsSapling |
compactSize |
Number of Sapling Spend descriptions. |
96 * nSpendsSapling |
vSpendsSapling |
SaplingSpendEffecting[nSpendsSapling] |
Effecting data for each Sapling Spend. |
varies |
nOutputsSapling |
compactSize |
Number of Sapling Output descriptions. |
756 * nOutputsSapling |
vOutputsSapling |
SaplingOutput[nOutputsSapling] |
Sapling Output descriptions. |
The anchor is not part of the effecting data; it appears in Sapling Authorizing Data.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
32 |
cv |
byte[32] |
A value commitment to the net value of the input note. |
32 |
nullifier |
byte[32] |
The nullifier of the input note. |
32 |
rk |
byte[32] |
The randomized validating key for this Spend. |
This is identical to OutputDescriptionV5 as defined in ZIP 225 9.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
32 |
cv |
byte[32] |
A value commitment to the net value of the output note. |
32 |
cmu |
byte[32] |
The \(u\!\) -coordinate of the note commitment for the output note. |
32 |
ephemeralKey |
byte[32] |
An encoding of an ephemeral Jubjub public key. |
580 |
encCiphertext |
byte[580] |
The encrypted contents of the note plaintext. |
80 |
outCiphertext |
byte[80] |
The encrypted contents of the byte string created by concatenation of the transmission key with the ephemeral secret key. |
For the Sapling bundle at bundleVariant = 0, sighash version 0 is the only version defined, and its associatedData is the empty byte string. A Sapling spendAuthSig or bindingSig made with it commits to the digest defined in v0 Signature Digest, computed with hash_type = SIGHASH_ALL (0x01).
In the case that Sapling spends or outputs are present, the Sapling effects digest is a BLAKE2b-256 hash of the following values:
T.3.2a: sapling_spends_digest (32-byte hash) T.3.2b: sapling_outputs_digest (32-byte hash)
The personalization field of this hash is set to:
"ZTxIdSaplingH_v7"
Note that unlike ZIP 244, neither the value balance nor the anchor is included here. The value balance is committed via value_pool_deltas_digest, and the anchor via sapling_auth_digest; the personalization differs from ZIP 244's ZTxIdSaplingHash because what is directly hashed has changed.
In the case that the transaction has no Sapling spends or outputs, sapling_effects_digest is:
BLAKE2b-256("ZTxIdSaplingH_v7", [])
In the case that Sapling spends are present, this digest is a BLAKE2b-256 hash of the following values:
T.3.2a.i: sapling_spends_compact_digest (32-byte hash) T.3.2a.ii: sapling_spends_noncompact_digest (32-byte hash)
The personalization field of this hash is set to:
"ZTxIdSSpendsHash"
In the case that the transaction has Sapling outputs but no Sapling spends, sapling_spends_digest is:
BLAKE2b-256("ZTxIdSSpendsHash", [])
A BLAKE2b-256 hash of the field encoding of all nullifier field values of Sapling spends belonging to the transaction.
The personalization field of this hash is set to:
"ZTxIdSSpendCHash"
A BLAKE2b-256 hash of the non-nullifier information for all Sapling spends belonging to the transaction. For each spend, the following elements are included in the hash:
T.3.2a.ii.1: cv (32 bytes) T.3.2a.ii.2: anchor (32 bytes) T.3.2a.ii.3: rk (32 bytes)
The anchor is hashed for each spend (even though it is shared in the encoding).
The personalization field of this hash is set to:
"ZTxIdSSpendNHash"
In the case that Sapling outputs are present, this digest is a BLAKE2b-256 hash of the following values:
T.3.2b.i: sapling_outputs_compact_digest (32-byte hash) T.3.2b.ii: sapling_outputs_memos_digest (32-byte hash) T.3.2b.iii: sapling_outputs_noncompact_digest (32-byte hash)
The personalization field of this hash is set to:
"ZTxIdSOutputHash"
In the case that the transaction has Sapling spends but no Sapling outputs, sapling_outputs_digest is:
BLAKE2b-256("ZTxIdSOutputHash", [])
A BLAKE2b-256 hash of the subset of Sapling output information included in the ZIP 307 13 CompactBlock format for all Sapling outputs belonging to the transaction. For each output, the following elements are included:
T.3.2b.i.1: cmu (32 bytes) T.3.2b.i.2: ephemeralKey (32 bytes) T.3.2b.i.3: encCiphertext[..52] (first 52 bytes)
The personalization field of this hash is set to:
"ZTxIdSOutC__Hash" (2 underscore characters)
A BLAKE2b-256 hash of the memo field data for all Sapling outputs belonging to the transaction. For each output:
T.3.2b.ii.1: encCiphertext[52..564] (512 bytes, encrypted memo)
The personalization field of this hash is set to:
"ZTxIdSOutM__Hash" (2 underscore characters)
A BLAKE2b-256 hash of the remaining Sapling output information not included in the CompactBlock format. For each output:
T.3.2b.iii.1: cv (32 bytes) T.3.2b.iii.2: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) T.3.2b.iii.3: outCiphertext (80 bytes)
The personalization field of this hash is set to:
"ZTxIdSOutN__Hash" (2 underscore characters)
In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 hash of the following concatenated values:
A.1.2a: anchorSapling (32 bytes, present iff nSpendsSapling > 0) A.1.2b: vSpendProofsSapling (192 bytes per spend) A.1.2c: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) A.1.2d: vOutputProofsSapling (192 bytes per output) A.1.2e: bindingSigSapling (SaplingSignature field encoding)
The SaplingSignature field encoding is defined in Sapling Signature (``SaplingSignature`)`_ and includes sighashInfo.
The personalization field of this hash is set to:
"ZTxAuthSapliH_v7"
The personalization differs from ZIP 244's ZTxAuthSapliHash because this digest now also commits to the anchor.
In the case that the transaction has no Sapling spends or outputs:
BLAKE2b-256("ZTxAuthSapliH_v7", [])
The Orchard protocol supports two value pools, each with its own note commitment tree, nullifier set, and chain value pool balance. Each is acted upon by its own bundle type: the Orchard bundle, bundleType = 3, acts on the Orchard pool, and the Ironwood bundle, bundleType = 4, acts on the Ironwood pool.
Both bundle types use the encoding defined in this section. Where a field is described below as belonging to the bundle's pool, that pool is the Orchard pool for an Orchard bundle and the Ironwood pool for an Ironwood bundle.
The bits of flagsOrchard have the same meaning for both pools, and so are named without the Orchard suffix they carried in the V5 transaction format, following ZIP 229 10. Their values are constrained per pool by the Bundle-local rules.
The effecting data for an Orchard protocol bundle describes the Orchard actions. Unlike the V5 transaction format defined in ZIP 225 9, the value balance is not included here; it appears in mValuePoolDeltas instead.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
varies |
nActionsOrchard |
compactSize |
The number of Orchard Action descriptions. |
820 * nActionsOrchard |
vActionsOrchard |
OrchardActionEffecting[nActionsOrchard] |
Effecting data for each Orchard Action. |
1 |
flagsOrchard |
byte |
An 8-bit value representing a set of flags. Ordered from LSB to MSB:
|
flagsOrchard is present if and only if
\(\mathtt{nActionsOrchard} > 0\kern-0.03em\textsf{.}\)
The anchor is not part of the effecting data; it appears in Orchard Protocol Authorizing Data.
| Bytes | Name | Data Type | Description |
|---|---|---|---|
32 |
cv |
byte[32] |
A value commitment to the net value of the input note minus the output note. |
32 |
nullifier |
byte[32] |
The nullifier of the input note. |
32 |
rk |
byte[32] |
The randomized validating key for this Action. |
32 |
cmx |
byte[32] |
The \(x\!\) -coordinate of the note commitment for the output note. |
32 |
ephemeralKey |
byte[32] |
An encoding of an ephemeral Pallas public key. |
580 |
encCiphertext |
byte[580] |
The encrypted contents of the note plaintext. |
80 |
outCiphertext |
byte[80] |
The encrypted contents of the byte string created by concatenation of the transmission key with the ephemeral secret key. |
For the Orchard and Ironwood bundles at bundleVariant = 0, sighash version 0 is the only version defined, and its associatedData is the empty byte string. An Orchard spendAuthSig or bindingSig made with it commits to the digest defined in v0 Signature Digest, computed with hash_type = SIGHASH_ALL (0x01).
The digest defined here and in its child sections is the Orchard bundle's instance of a digest shape shared with the Ironwood bundle; T.3.4 gives the Ironwood instance.
In the case that Orchard actions are present, the Orchard effects digest is a BLAKE2b-256 hash of the following values:
T.3.3a: orchard_actions_compact_digest (32-byte hash) T.3.3b: orchard_actions_memos_digest (32-byte hash) T.3.3c: orchard_actions_noncompact_digest (32-byte hash) T.3.3d: flagsOrchard (1 byte)
The personalization field of this hash is set to:
"ZTxIdOrchardH_v7"
Note that unlike ZIP 244, neither the value balance nor the anchor is included here. The value balance is committed via value_pool_deltas_digest, and the anchor via orchard_auth_digest; the personalization differs from ZIP 244's ZTxIdOrchardHash because what is directly hashed has changed.
In the case that the transaction has no Orchard actions, orchard_effects_digest is:
BLAKE2b-256("ZTxIdOrchardH_v7", [])
A BLAKE2b-256 hash of the subset of Orchard action information intended for inclusion in the CompactBlock format. For each action:
T.3.3a.i: nullifier (32 bytes) T.3.3a.ii: cmx (32 bytes) T.3.3a.iii: ephemeralKey (32 bytes) T.3.3a.iv: encCiphertext[..52] (first 52 bytes)
The personalization field of this hash is set to:
"ZTxIdOrcActCHash"
A BLAKE2b-256 hash of the memo field data for all Orchard actions. For each action:
T.3.3b.i: encCiphertext[52..564] (512 bytes, encrypted memo)
The personalization field of this hash is set to:
"ZTxIdOrcActMHash"
A BLAKE2b-256 hash of the remaining Orchard action information not intended for inclusion in the CompactBlock format. For each action:
T.3.3c.i: cv (32 bytes) T.3.3c.ii: rk (32 bytes) T.3.3c.iii: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) T.3.3c.iv: outCiphertext (80 bytes)
The personalization field of this hash is set to:
"ZTxIdOrcActNHash"
The Ironwood bundle uses the same effecting data encoding as the Orchard bundle, and ironwood_effects_digest is computed over that data exactly as orchard_effects_digest and its children are computed (T.3.3), except that each personalization string is replaced as follows:
| Digest | Orchard bundle | Ironwood bundle |
|---|---|---|
| effects digest | ZTxIdOrchardH_v7 |
ZTxIdIronwd_Hash |
| actions compact digest | ZTxIdOrcActCHash |
ZTxIdIrnActCHash |
| actions memos digest | ZTxIdOrcActMHash |
ZTxIdIrnActMHash |
| actions noncompact digest | ZTxIdOrcActNHash |
ZTxIdIrnActNHash |
The personalization strings differ so that the digest of a bundle acting on one pool cannot be reused as the digest of a bundle acting on the other.
In the case that the transaction has no Ironwood actions, ironwood_effects_digest is:
BLAKE2b-256("ZTxIdIronwd_Hash", [])
In the case that Orchard actions are present, this is a BLAKE2b-256 hash of the following concatenated values:
A.1.3a: anchorOrchard (32 bytes) A.1.3b: proofsOrchard (aggregated proofs) A.1.3c: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) A.1.3d: bindingSigOrchard (OrchardSignature field encoding)
The OrchardSignature field encoding is defined in Orchard Signature (``OrchardSignature`)`_ and includes sighashInfo.
The personalization field of this hash is set to:
"ZTxAuthOrchaH_v7"
The personalization differs from ZIP 244's ZTxAuthOrchaHash because this digest now also commits to the anchor.
In the case that the transaction has no Orchard actions:
BLAKE2b-256("ZTxAuthOrchaH_v7", [])
The Ironwood bundle uses the same authorizing data encoding as the Orchard bundle, and ironwood_auth_digest is computed over that data exactly as orchard_auth_digest (A.1.3), including its commitment to the anchor, except that the personalization field of the hash is set to:
"ZTxAuthIrnwdHash"
In the case that the transaction has no Ironwood actions:
BLAKE2b-256("ZTxAuthIrnwdHash", [])
Effecting data bundles and authorizing data bundles are stored separately in the transaction format so that the authorizing data may be pruned by straightforward truncation of the encoded representation of the transaction.
Representing the coinbase as a bundle makes the value pool delta balance rule universal. Previously the coinbase transaction was the sole exception: its deltas summed to the negation of the block subsidy rather than to zero, because the subsidy entered the transparent transaction value pool implicitly. With the subsidy carried in the coinbase bundle's value pool delta, every transaction balances to zero in every asset, and a wallet can enumerate the value flows of a coinbase transaction using the same rule it applies to any other transaction.
Carrying blockSubsidy and lockboxValue in the effecting data states both components of the issuance in the bundle they belong to, and commits them to the transaction identifier along with the rest of that data. The value pool delta is their difference, so without them a client could see how much the coinbase pays out but not how much was issued or how much went to the lockbox. Deriving them instead is not open to every client: the subsidy is not a function of the block height alone once issuance depends on accumulated chain state, so evaluating the issuance schedule would require a client to track that state.
The Orchard and Ironwood bundles share one encoding because the Orchard pool and the Ironwood pool are two pools of the same shielded protocol. The action encoding, proving system, authorization, and note encryption are common to both; the pools differ in their note commitment trees, nullifier sets, and chain value pool balances.
Each pool gets its own bundle type rather than a variant of a single type because a variant is required to affect the same value pool(s) as the type it varies, so that a client encountering an unrecognized variant still knows which pools the bundle touches. Two pools therefore cannot share a bundle type, and separate types also keep the two value pool deltas separable, which a client needs in order to report the two chain value pool balances independently.
The Sapling and Orchard protocol anchors are authorizing data rather than effecting data, following ZIP 229 10. An anchor selects the note commitment tree state that the bundle's proofs are verified against, which is a property of how the spends are authorized rather than of what the transaction does. Placing it there lets a bundle be re-anchored to a more recent root without changing the transaction identifier, while the proofs still bind to the anchor actually used.
The coinbase bundle also gives the coinbase metadata a place of its own. In previous transaction versions that metadata was encoded as the scriptSig of a single transparent input whose previous output reference pointed at nothing, so a coinbase transaction had to be recognized by that unspendable reference, and the block height had to be encoded as a script push. The coinbase bundle encodes the height directly, and its presence identifies the transaction. The coinbaseData limit of 94 bytes holds the encoded size of that field to what the previous encoding spent on the same content. A coinbase scriptSig was limited to 100 bytes, of which the leading push of the block height took 5; of the 95 bytes that remained, the compactSize length prefix of coinbaseData now takes one.
Neither the previous output reference nor the sequence number of the input being replaced is carried over. Both were artifacts of encoding the coinbase metadata as a transparent input: the reference identified no output, and the sequence number had no effect on the validity of a transaction that spends nothing.
This section should be removed as soon as all the considerations described here are accounted for in ZIP.
Wallets or consensus-dependent applications that send transactions, might do something wrong that compromises user funds or privacy if they do not take into account consensus changes in an upgrade; therefore, only a subset of consensus changes can be safely adapted to using this mechanism.
In particular, consensus rules may change in such a way that a wallet doing what it has done in the past causes risk of loss of funds.
An example of this was ZIP 212 8. In that case the existing mechanisms failed to prevent loss of funds because in practice, wallets updated the consensus branch ID without updating note encryption. We made the mistake of requiring wallets to change their behaviour for an existing transaction version. Except for certain cases involving severe security flaws, we should avoid doing that again.
If a wallet needs to actively do something differently (for example, advertising addresses in a new format or creating an output with a TZE precondition) in order to be affected by a new feature, then it is reasonably safe for it to ignore the feature as long as it can still parse transactions and, and create and sign transactions that don't make use of those features.
It is okay that such a wallet might not be able to see funds that depend on new features, as long as they do not create such funds themselves.
Loss of funds is unacceptable. Temporary inaccessibility of funds in certain circumstances can be okay -- provided that this potential inaccessibility and the circumstances where it can occur is documented and an explicit design decision.
Modify how we approach transaction format evolution, such that (after one more change to transaction encoding) it is possible for a wallet that has not adopted a parser for a given transaction format to continue to function after an additive change to the transaction format. Another way to state this is that we should make it possible to make "semver-compatible" transaction format changes.
Treat bundles as individually versioned.
Sketch of the format:
Rename assetDigest to assetUuid in ZIP 227
| 1 | 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 |
|---|
| 2 | Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later |
|---|
| 3 | Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain |
|---|
| 4 | Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet |
|---|
| 5 | Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward |
|---|
| 6 | Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.10: Payment of Funding Streams, Deferred Lockbox, and Lockbox Disbursement |
|---|
| 7 | ZIP 203: Transaction Expiry |
|---|
| 8 | ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext |
|---|
| 9 | ZIP 225: Version 5 Transaction Format |
|---|
| 10 | ZIP 229: Version 6 Transaction Format |
|---|
| 11 | ZIP 239: Relay of Version 5 Transactions |
|---|
| 12 | ZIP 244: Transaction Identifier Non-Malleability |
|---|
| 13 | ZIP 307: Light Client Protocol for Payment Detection |
|---|
| 14 | ZIP 2001: Lockbox Funding Streams |
|---|
| 15 | ZIP 2006: Restricting Transfers into the Orchard Pool |
|---|