Skip to content

ZSA integration (step 3): Add initial Transaction V6 support to Zebra (currently copies V5 behavior)#16

Closed
dmidem wants to merge 45 commits into
zsa-integration-zsadepsfrom
zsa-integration-txv6
Closed

ZSA integration (step 3): Add initial Transaction V6 support to Zebra (currently copies V5 behavior)#16
dmidem wants to merge 45 commits into
zsa-integration-zsadepsfrom
zsa-integration-txv6

Conversation

@dmidem
Copy link
Copy Markdown
Collaborator

@dmidem dmidem commented Oct 17, 2024

This PR introduces initial support for Transaction version 6 (Tx V6) in the Zebra codebase as part of the broader effort to add ZSA (Zcash Shielded Assets) support.

Key changes

  • Added a new V6 variant to the Transaction enum in the zebra-chain crate, currently replicating the behavior of V5.
  • Updated relevant code paths across the project to handle the new V6 variant, ensuring basic compatibility.
  • Tx V6 currently functions as a copy of Tx V5 (including tests); its behavior will be updated in future PRs to reflect the actual V6 specification, incorporating ZSA-specific features and changes.
  • Placeholder/dummy values are used for activation height, group ID, etc., which will be replaced with proper values in future updates.

Notes

  • This implementation provides a foundational structure for Tx V6 but does not yet include ZSA-specific features, new transaction structures, or detailed serialization/deserialization changes.
  • Future work will focus on completing Tx V6 support with ZSA-specific elements, proper configuration values, and full integration into the consensus layer.

Next steps

  • Address any FIXME comments in the code.
  • Converted zebra-chain::orchard::ShieldedData struct to be a generic that supports both V5 and V6.
  • Implement serialization/deserialization for V6 (previous work from the /tx_v6_with_ser_1.8.0 branch can be utilized).
  • Update Tx V6 to perform its intended behaviors distinct from V5 in subsequent PRs.
  • Implement verification processes for Tx V6 transactions.
  • Add tests for Tx V6 transactions.

dmidem added 25 commits August 18, 2024 21:47
This commit introduces basic support for Transaction version 6 (Tx V6). This initial implementation treats Tx V6
as a simple copy of Tx V5, without yet integrating ZSA-specific features or the new transaction structure.

- Added a new V6 variant to the Transaction enum in the zebra-chain crate.
- Updated relevant code to handle the new V6 variant.

Note: Tests and additional adjustments are still pending, and will be addressed in subsequent commits.
@dmidem dmidem changed the title Step3: Add initial Transaction V6 support to Zebra (currently copies V5 behavior) Stepv3: Add initial Transaction V6 support to Zebra (currently copies V5 behavior) Oct 17, 2024
@dmidem dmidem changed the title Stepv3: Add initial Transaction V6 support to Zebra (currently copies V5 behavior) Step 3: Add initial Transaction V6 support to Zebra (currently copies V5 behavior) Oct 17, 2024
@dmidem dmidem reopened this Oct 29, 2024
@PaulLaux PaulLaux requested a review from arya2 October 31, 2024 15:06
Copy link
Copy Markdown

@PaulLaux PaulLaux left a comment

Choose a reason for hiding this comment

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

added some comments

/// Orchard transactions must use transaction version 5 and this version
/// group ID.
// FIXME: use a proper value!
pub const TX_V6_VERSION_GROUP_ID: u32 = 0x26A7_270B;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Let's use a random number in the meanwhile.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Optional: It's 0x124A69F8 in zcash_primitives, if that was random, let's use that so it won't need an update.

Copy link
Copy Markdown
Collaborator Author

@dmidem dmidem Jan 11, 2025

Choose a reason for hiding this comment

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

Changed to 0x124A69F8 in #37. Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

@dmidem dmidem Feb 13, 2025

Choose a reason for hiding this comment

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

Temporarily changed to 0x7777_7777 to align with the a new value used in librustzcash (zcash_primitives) and test vectors. Kept a FIXME comment to change it in the future.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Temporarily changed to 0x124A_69F8 to align with the a value used in OLD version of librustzcash (zcash_primitives) and test vectors. Kept a FIXME comment to change it in the future.

Comment thread zebra-chain/src/transaction.rs Outdated
/// The orchard data for this transaction, if any.
orchard_shielded_data: Option<orchard::ShieldedData>,
},
// FIXME: implement V6 properly (now it's just a coipy of V5)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

a copy

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Adding the changed-files and codespell lint jobs from here may be trivial and help catch typos.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread zebra-chain/src/transaction.rs Outdated
orchard_shielded_data: Option<orchard::ShieldedData>,
},
// FIXME: implement V6 properly (now it's just a coipy of V5)
/// A `version = 6` transaction , which supports Orchard ZSA, Orchard Vanille, Sapling and
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

which supports OrchardZSA, Orchard, Sapling ...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

// FIXME: implement V6 properly (now it's just a coipy of V5)
/// A `version = 6` transaction , which supports Orchard ZSA, Orchard Vanille, Sapling and
/// transparent, but not Sprout.
V6 {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

can we put this behind a feature flag?
(this and all subsequent V6 handling)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done in #37.

}
| Transaction::V6 {
sapling_shielded_data: None,
..
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Let's simplify the entire function:

   /// Access the deduplicated [`sapling::tree::Root`]s in this transaction,
    /// regardless of version.
    pub fn sapling_anchors(&self) -> Box<dyn Iterator<Item = sapling::tree::Root> + '_> {
        // This function returns a boxed iterator because the different
        // transaction variants end up having different iterator types
        match self {
            Transaction::V4 {
                sapling_shielded_data: Some(sapling_shielded_data),
                ..
            } => Box::new(sapling_shielded_data.anchors()),

            Transaction::V5 {
                sapling_shielded_data: Some(sapling_shielded_data),
                ..
            } => Box::new(sapling_shielded_data.anchors()),

            Transaction::V6 {
                sapling_shielded_data: Some(sapling_shielded_data),
                ..
            } => Box::new(sapling_shielded_data.anchors()),

        // No Spends (V1, V2, V3 and V4, V5, V6 without sapling shielded data)
        _ => Box::new(iter::empty()),
    }
}

(x4 for all sapling functions)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@arya2 what do you think about this simplification across the entire file?
This will significantly reduce boilerplate without affecting semantics.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The simplification looks nice, I'd lean towards whatever's easiest since it all needs to be refactored to a new-type around the zcash_primitives Transaction type soon, and if there's no difference in difficulty, I'd go with:

use Transaction::*;

match self {
    V4 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    } => Box::new(sapling_shielded_data.anchors()),

    V5 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    }
    | V6 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    } => Box::new(sapling_shielded_data.anchors()),

    // No Spends
    V1 { .. } | V2 { .. } | V3 { .. } | V4 { .. } | V5 { .. } | V6 { .. } => {
        Box::new(std::iter::empty())
    }
}

because it currently seems excessively explicit/verbose, but avoiding a catch-all arm makes it easier to see that it needs an update when a new variant is added. If only Rust supported enums in range patterns we could have the best of both here and elsewhere in Zebra (I think there's a crate for it but adding a crate seems worse than being verbose). Stable support for if let guards would've been nice here and elsewhere in this file too 🤷.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Such simplification would work here and in similar places. However, if we add a feature flag for the V6 feature as we discussed:

V5 { ... } |
#[cfg(feature = "tx-v6")]
V6 { ... } => { ... }

It wouldn't compile. Here's a playground example to illustrate the issue.

I introduced the "tx-v6" feature flag in the next PR (#17, "Step 4"). However, it would definitely be better to include it in this PR ("Step 3") since I introduced V6 here (the absence of the "tx-v6" feature flag in this PR makes the review process confusing).

Anyway, we can't afford to use the | operator for such simplification during the transition period when the "tx-v6" feature flag is needed. Although I'm not completely sure if Rust doesn't have workarounds to achieve that.

And it was one of the reasons why I added the tx_v5_and_v6 macro here – to avoid such code duplication. However, the macro itself can be confusing because its usage doesn't follow the existing style for processing transaction version matches. I might need to remove it, and we can discuss this further.

Comment thread zebra-chain/src/transaction/txid.rs Outdated
// auto-detects the transaction version by the first byte, so the same function
// can be used here for both V5 and V6.
// FIXME: fix spec refs below for V6
/// Compute the Transaction ID for a V5/V6 transaction in the given network upgrade.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

// Compute the Transaction ID for transactions V5 to V6.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread zebra-chain/src/transaction/txid.rs Outdated
Comment on lines +46 to +48
// FIXME: it looks like the updated zcash_primitives in librustzcash
// auto-detects the transaction version by the first byte, so the same function
// can be used here for both V5 and V6.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

remove these 3 lines

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

txid_v5_v6()'s approach would work for all transactions, but it's an unnecessary memory/cache allocation when txid_v1_to_v4() is so simple and already implemented.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Removed the FIXME comment.

Comment thread zebra-state/src/service/check/utxo.rs Outdated
finalized_state,
)?;

// FIXME: what about v6?
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remove comment and fix line 69 to be
// This is a particular issue for v5 and v6 transactions,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

&None,
&None,
sapling_shielded_data,
orchard_shielded_data,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

do we need to deal with issue bundle here?
(x2)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, this is probably the best place to update the issued_assets map for the non-finalized part of the chain, same for revert_chain_with() when rolling back the chain for a fork.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

@dmidem dmidem Feb 24, 2025

Choose a reason for hiding this comment

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

Handled in future PRs (see zsa-integration-state branch).


conflict: SpendConflictForTransactionV5,
},
// FIXME: add and use V6?
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

// FIXME: add V6 test

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.


/// The version group ID for version 6 transactions.
///
/// Orchard transactions must use transaction version 5 and this version
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// Orchard transactions must use transaction version 5 and this version
/// Orchard ZSA transactions must use transaction version 6 and this version

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Comment thread zebra-chain/src/transaction.rs Outdated
/// The orchard data for this transaction, if any.
orchard_shielded_data: Option<orchard::ShieldedData>,
},
// FIXME: implement V6 properly (now it's just a coipy of V5)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Adding the changed-files and codespell lint jobs from here may be trivial and help catch typos.

}
| Transaction::V6 {
sapling_shielded_data: None,
..
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The simplification looks nice, I'd lean towards whatever's easiest since it all needs to be refactored to a new-type around the zcash_primitives Transaction type soon, and if there's no difference in difficulty, I'd go with:

use Transaction::*;

match self {
    V4 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    } => Box::new(sapling_shielded_data.anchors()),

    V5 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    }
    | V6 {
        sapling_shielded_data: Some(sapling_shielded_data),
        ..
    } => Box::new(sapling_shielded_data.anchors()),

    // No Spends
    V1 { .. } | V2 { .. } | V3 { .. } | V4 { .. } | V5 { .. } | V6 { .. } => {
        Box::new(std::iter::empty())
    }
}

because it currently seems excessively explicit/verbose, but avoiding a catch-all arm makes it easier to see that it needs an update when a new variant is added. If only Rust supported enums in range patterns we could have the best of both here and elsewhere in Zebra (I think there's a crate for it but adding a crate seems worse than being verbose). Stable support for if let guards would've been nice here and elsewhere in this file too 🤷.

Comment on lines +863 to +866
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.spends_per_anchor()),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nitpick/Optional: Transaction::V5 | Transaction::V6 would work here and for all of the sapling methods below too.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It would be a good simplification, but it's probably not compatible with the "tx-v6" feature flag. I’ve provided more details in this response.

orchard_shielded_data: None,
},
v5 @ V5 { .. } => v5.clone(),
V6 {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would rename the function to something like transaction_to_fake_min_v5() instead of converting v6 transactions to v5 here, since there aren't any v6 transactions in the test blocks (zebra_test::vectors::{MAINNET_BLOCKS, TESTNET_BLOCKS}, accessed via network.block_iter() in some places), and if they're added later, it would improve test coverage to keep them as v6 transactions in the tests where this is used (a total of ~20 places counting indirect calls, and only v5_transaction_is_accepted_after_nu5_activation_for_network looks like it would need an update other than a rename).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Link to this comment copied to #37.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed: renamed transaction_to_fake_v5 function to transaction_to_fake_min_v5 and changed V6 arm of the match to:

V6 => panic!("V6 transactions are not supported in this test!"),

} => {
// Transaction V6 spec:
// FIXME: specify a proper ref
// https://zips.z.cash/protocol/protocol.pdf#txnencoding
Copy link
Copy Markdown
Collaborator

@arya2 arya2 Nov 1, 2024

Choose a reason for hiding this comment

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

Optional: Leave both so it can be referenced while it's only in the ZIP and won't need an update if the encoding is meant to eventually be added to the protocol specification, though I'm not sure if that's the intention, I asked here.

Update: I've only found the version group IDs for V5 in the protocol spec so far, I think we'll probably want to keep this reference here (or add it back later).

/// Orchard transactions must use transaction version 5 and this version
/// group ID.
// FIXME: use a proper value!
pub const TX_V6_VERSION_GROUP_ID: u32 = 0x26A7_270B;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Optional: It's 0x124A69F8 in zcash_primitives, if that was random, let's use that so it won't need an update.

Comment thread zebra-chain/src/transaction/txid.rs Outdated
Comment on lines +46 to +48
// FIXME: it looks like the updated zcash_primitives in librustzcash
// auto-detects the transaction version by the first byte, so the same function
// can be used here for both V5 and V6.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

txid_v5_v6()'s approach would work for all transactions, but it's an unnecessary memory/cache allocation when txid_v1_to_v4() is so simple and already implemented.

&None,
&None,
sapling_shielded_data,
orchard_shielded_data,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, this is probably the best place to update the issued_assets map for the non-finalized part of the chain, same for revert_chain_with() when rolling back the chain for a fork.

@dmidem
Copy link
Copy Markdown
Collaborator Author

dmidem commented Mar 3, 2025

Closed in favour of #37

1 similar comment
@dmidem
Copy link
Copy Markdown
Collaborator Author

dmidem commented Mar 3, 2025

Closed in favour of #37

@dmidem dmidem closed this Mar 3, 2025
dmidem added a commit that referenced this pull request Jun 23, 2025
This pull request merges the changes from several incremental PRs into
one cumulative set of updates on top of the `zsa1` branch. It introduces
ZSA-compatible crates, Network Upgrade 7 (Nu7), initial Transaction V6
support, Orchard generics for ZSA, property-based testing enhancements,
note commitment handling for ZSA issuance, and initial consensus
modifications for Orchard ZSA.

It does not include the final state management changes or additional
tests — those come in subsequent PRs.

Below is a high-level overview of the merged changes:

1. **ZSA-Compatible Crates Integration (Step 1)**
   #24: 
- Replaces core libraries (`halo2`, `zcash_note_encryption`, etc.) with
QED-it’s ZSA-compatible forks.
- Maintains full support for Orchard “Vanilla” without activating any
new ZSA features yet.

2. **Network Upgrade 7 (Nu7) Support (Step 2)**
   #15  
- Introduces code paths and placeholders for Nu7, the upcoming network
upgrade required for ZSA.
- Adds `FIXME` comments where final activation heights and other
specifics must be filled in.

3. **Transaction V6 Foundations (Step 3)**
   #16  
- Adds a `V6` variant to Zebra’s `Transaction` enum, initially mirroring
`V5` logic.
- Sets a baseline for future ZSA-related modifications, including
placeholders for relevant fields and logic.

4. **Refactor Orchard Structures to Generics (Step 4)**
   #17  
- Converts key Orchard data structures (e.g., `ShieldedData`) to
generics, enabling a single code path for both Orchard Vanilla and
Orchard ZSA.
- Implements serialization/deserialization for `V6` transactions,
including a `burn` field in the ZSA flavor.

5. **Orchard Proptests with ZSA Enhancements (Step 5)**
   #18
- Extends the property-based testing framework to handle ZSA-specific
fields and behaviors in `Transaction V6`.
- Refactors code organization (e.g., extracting `Burn` types) for better
clarity and future expansion.

6. **Integration of ZSA Issuance Commitments (Step 6)**
   #25
- Merges issuance action note commitments with existing shielded data
commitments for `V6` transactions.
- Ensures `Transaction::orchard_note_commitments` includes issuance note
commitments when present, preserving `V5` behavior.

7. **Initial ZSA Consensus Support (Step 7)**
   #28
   - Modifies `zebra-consensus` to support Orchard ZSA.  

**Next Steps**  
- **State Management & Additional Testing**: Future PRs will introduce
state-layer modifications, refine consensus checks, and add more
comprehensive tests.

By consolidating these first several steps into a single PR, we aim to
simplify the review process .
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.

3 participants