Experiment: `Transaction::V6` variants only (#9339)

* Update main.yml

* feat: auto-sync upstream

* fix: merge errors

* Merge pull request #6 from ShieldedLabs/aphelionz/v6-transactions

Add Transaction::V6 Variants

* fix: enable tx_v6 on zebra-chain when it's enabled on zebra-state

* fix: more feature flag dependencies

* cleanup: remove prop.txt

* Update zebra-chain/src/transaction.rs

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* cleanup: removing SL-specific workflow

* fix: skip some windows-related denies

* Update deny.toml

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* fix: better deny.toml entry for windows-core

* Update zebra-chain/src/transaction/serialize.rs

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* Update zebra-chain/src/transaction/serialize.rs

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* Update zebra-chain/src/transaction/tests/vectors.rs

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* Update zebra-chain/src/transaction.rs

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>

* feat: passthrough functions for v6 -> v5

* fix: rust fmt

---------

Co-authored-by: Mark Henderson <mark@allspice.io>
Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
This commit is contained in:
Mark Henderson 2025-04-09 14:52:13 -04:00 committed by GitHub
parent cc5c5edd35
commit d061232312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 707 additions and 210 deletions

File diff suppressed because it is too large Load Diff

View File

@ -98,6 +98,12 @@ skip-tree = [
# wait until zcash_client_backend update rustix
{ name = "rustix", version = "=0.38.44" },
# wait for reqwest to update windows-registry
{ name = "windows-strings", version = "=0.3.1" },
# wait for sentry to update windows-core
{ name = "windows-core", version = "=0.52.0" }
]
# This section is considered when running `cargo deny check sources`.

View File

@ -60,6 +60,8 @@ proptest-impl = [
bench = ["zebra-test"]
tx_v6 = []
[dependencies]
# Cryptography

View File

@ -143,6 +143,28 @@ pub enum Transaction {
/// The orchard data for this transaction, if any.
orchard_shielded_data: Option<orchard::ShieldedData>,
},
/// A `version = 6` transaction, which is reserved for current development.
#[cfg(feature = "tx_v6")]
V6 {
/// The Network Upgrade for this transaction.
///
/// Derived from the ConsensusBranchId field.
network_upgrade: NetworkUpgrade,
/// The earliest time or block height that this transaction can be added to the
/// chain.
lock_time: LockTime,
/// The latest block height that this transaction can be added to the chain.
expiry_height: block::Height,
/// The transparent inputs to the transaction.
inputs: Vec<transparent::Input>,
/// The transparent outputs from the transaction.
outputs: Vec<transparent::Output>,
/// The sapling shielded data for this transaction, if any.
sapling_shielded_data: Option<sapling::ShieldedData<sapling::SharedAnchor>>,
/// The orchard data for this transaction, if any.
orchard_shielded_data: Option<orchard::ShieldedData>,
// TODO: Add the rest of the v6 fields.
},
}
impl fmt::Display for Transaction {
@ -253,6 +275,8 @@ impl Transaction {
| Transaction::V3 { .. }
| Transaction::V4 { .. } => None,
Transaction::V5 { .. } => Some(AuthDigest::from(self)),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Some(AuthDigest::from(self)),
}
}
@ -342,6 +366,8 @@ impl Transaction {
match self {
Transaction::V1 { .. } | Transaction::V2 { .. } => false,
Transaction::V3 { .. } | Transaction::V4 { .. } | Transaction::V5 { .. } => true,
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => true,
}
}
@ -363,6 +389,8 @@ impl Transaction {
Transaction::V3 { .. } => 3,
Transaction::V4 { .. } => 4,
Transaction::V5 { .. } => 5,
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => 6,
}
}
@ -374,6 +402,8 @@ impl Transaction {
| Transaction::V3 { lock_time, .. }
| Transaction::V4 { lock_time, .. }
| Transaction::V5 { lock_time, .. } => *lock_time,
#[cfg(feature = "tx_v6")]
Transaction::V6 { lock_time, .. } => *lock_time,
};
// `zcashd` checks that the block height is greater than the lock height.
@ -421,6 +451,8 @@ impl Transaction {
| Transaction::V3 { lock_time, .. }
| Transaction::V4 { lock_time, .. }
| Transaction::V5 { lock_time, .. } => *lock_time,
#[cfg(feature = "tx_v6")]
Transaction::V6 { lock_time, .. } => *lock_time,
};
let mut lock_time_bytes = Vec::new();
lock_time
@ -457,6 +489,15 @@ impl Transaction {
block::Height(0) => None,
block::Height(expiry_height) => Some(block::Height(*expiry_height)),
},
#[cfg(feature = "tx_v6")]
Transaction::V6 { expiry_height, .. } => match expiry_height {
// # Consensus
//
// > No limit: To set no limit on transactions (so that they do not expire), nExpiryHeight should be set to 0.
// https://zips.z.cash/zip-0203#specification
block::Height(0) => None,
block::Height(expiry_height) => Some(block::Height(*expiry_height)),
},
}
}
@ -473,6 +514,10 @@ impl Transaction {
Transaction::V5 {
network_upgrade, ..
} => Some(*network_upgrade),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
network_upgrade, ..
} => Some(*network_upgrade),
}
}
@ -486,6 +531,8 @@ impl Transaction {
Transaction::V3 { ref inputs, .. } => inputs,
Transaction::V4 { ref inputs, .. } => inputs,
Transaction::V5 { ref inputs, .. } => inputs,
#[cfg(feature = "tx_v6")]
Transaction::V6 { ref inputs, .. } => inputs,
}
}
@ -504,6 +551,8 @@ impl Transaction {
Transaction::V3 { ref outputs, .. } => outputs,
Transaction::V4 { ref outputs, .. } => outputs,
Transaction::V5 { ref outputs, .. } => outputs,
#[cfg(feature = "tx_v6")]
Transaction::V6 { ref outputs, .. } => outputs,
}
}
@ -552,6 +601,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -587,6 +638,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => 0,
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => 0,
}
}
@ -626,6 +679,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -662,6 +717,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => None,
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => None,
}
}
@ -670,6 +727,8 @@ impl Transaction {
match self {
// No JoinSplits
Transaction::V1 { .. } | Transaction::V5 { .. } => false,
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => false,
// JoinSplits-on-BCTV14
Transaction::V2 { joinsplit_data, .. } | Transaction::V3 { joinsplit_data, .. } => {
@ -717,6 +776,8 @@ impl Transaction {
}
| Transaction::V1 { .. }
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -738,6 +799,12 @@ impl Transaction {
..
} => Box::new(sapling_shielded_data.anchors()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.anchors()),
// No Spends
Transaction::V1 { .. }
| Transaction::V2 { .. }
@ -750,6 +817,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
}
}
@ -775,6 +847,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.spends_per_anchor()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.spends_per_anchor()),
// No Spends
Transaction::V1 { .. }
@ -788,6 +865,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
}
}
@ -803,6 +885,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.outputs()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.outputs()),
// No Outputs
Transaction::V1 { .. }
@ -816,6 +903,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
}
}
@ -833,6 +925,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.nullifiers()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.nullifiers()),
// No Spends
Transaction::V1 { .. }
@ -846,6 +943,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
}
}
@ -863,6 +965,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.note_commitments()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Box::new(sapling_shielded_data.note_commitments()),
// No Spends
Transaction::V1 { .. }
@ -876,6 +983,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Box::new(std::iter::empty()),
}
}
@ -891,6 +1003,11 @@ impl Transaction {
sapling_shielded_data,
..
} => sapling_shielded_data.is_some(),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data,
..
} => sapling_shielded_data.is_some(),
}
}
@ -905,6 +1022,11 @@ impl Transaction {
orchard_shielded_data,
..
} => orchard_shielded_data.as_ref(),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
orchard_shielded_data,
..
} => orchard_shielded_data.as_ref(),
// No Orchard shielded data
Transaction::V1 { .. }
@ -1029,6 +1151,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -1076,6 +1200,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -1117,6 +1243,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(iter::empty()),
};
joinsplit_value_balances.map(ValueBalance::from_sprout_amount)
@ -1158,6 +1286,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => sapling_shielded_data.value_balance,
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => sapling_shielded_data.value_balance,
Transaction::V1 { .. }
| Transaction::V2 { .. }
@ -1170,6 +1303,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => Amount::zero(),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => Amount::zero(),
};
ValueBalance::from_sapling_amount(sapling_value_balance)
@ -1290,6 +1428,14 @@ impl Transaction {
*network_upgrade = nu;
Ok(())
}
#[cfg(feature = "tx_v6")]
Transaction::V6 {
ref mut network_upgrade,
..
} => {
*network_upgrade = nu;
Ok(())
}
}
}
@ -1315,6 +1461,11 @@ impl Transaction {
ref mut expiry_height,
..
} => expiry_height,
#[cfg(feature = "tx_v6")]
Transaction::V6 {
ref mut expiry_height,
..
} => expiry_height,
}
}
@ -1326,6 +1477,8 @@ impl Transaction {
Transaction::V3 { ref mut inputs, .. } => inputs,
Transaction::V4 { ref mut inputs, .. } => inputs,
Transaction::V5 { ref mut inputs, .. } => inputs,
#[cfg(feature = "tx_v6")]
Transaction::V6 { ref mut inputs, .. } => inputs,
}
}
@ -1352,6 +1505,11 @@ impl Transaction {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Some(&mut sapling_shielded_data.value_balance),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: Some(sapling_shielded_data),
..
} => Some(&mut sapling_shielded_data.value_balance),
Transaction::V1 { .. }
| Transaction::V2 { .. }
| Transaction::V3 { .. }
@ -1363,6 +1521,11 @@ impl Transaction {
sapling_shielded_data: None,
..
} => None,
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data: None,
..
} => None,
}
}
@ -1411,6 +1574,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -1459,6 +1624,8 @@ impl Transaction {
..
}
| Transaction::V5 { .. } => Box::new(std::iter::empty()),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => Box::new(std::iter::empty()),
}
}
@ -1477,6 +1644,11 @@ impl Transaction {
orchard_shielded_data: Some(orchard_shielded_data),
..
} => Some(orchard_shielded_data),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
orchard_shielded_data: Some(orchard_shielded_data),
..
} => Some(orchard_shielded_data),
Transaction::V1 { .. }
| Transaction::V2 { .. }
@ -1486,6 +1658,11 @@ impl Transaction {
orchard_shielded_data: None,
..
} => None,
#[cfg(feature = "tx_v6")]
Transaction::V6 {
orchard_shielded_data: None,
..
} => None,
}
}
@ -1507,6 +1684,10 @@ impl Transaction {
Transaction::V5 {
ref mut outputs, ..
} => outputs,
#[cfg(feature = "tx_v6")]
Transaction::V6 {
ref mut outputs, ..
} => outputs,
}
}
}

View File

@ -924,6 +924,8 @@ pub fn transaction_to_fake_v5(
orchard_shielded_data: None,
},
v5 @ V5 { .. } => v5.clone(),
#[cfg(feature = "tx_v6")]
v6 @ V6 { .. } => v6.clone(),
}
}
@ -1008,6 +1010,8 @@ pub fn v5_transactions<'b>(
| Transaction::V3 { .. }
| Transaction::V4 { .. } => None,
ref tx @ Transaction::V5 { .. } => Some(tx.clone()),
#[cfg(feature = "tx_v6")]
ref tx @ Transaction::V6 { .. } => Some(tx.clone()),
})
}

View File

@ -672,6 +672,55 @@ impl ZcashSerialize for Transaction {
// `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
orchard_shielded_data.zcash_serialize(&mut writer)?;
}
#[cfg(feature = "tx_v6")]
Transaction::V6 {
network_upgrade,
lock_time,
expiry_height,
inputs,
outputs,
sapling_shielded_data,
orchard_shielded_data,
} => {
// Transaction V6 spec:
// https://zips.z.cash/zip-0230#specification
// Denoted as `nVersionGroupId` in the spec.
writer.write_u32::<LittleEndian>(TX_V5_VERSION_GROUP_ID)?;
// Denoted as `nConsensusBranchId` in the spec.
writer.write_u32::<LittleEndian>(u32::from(
network_upgrade
.branch_id()
.expect("valid transactions must have a network upgrade with a branch id"),
))?;
// Denoted as `lock_time` in the spec.
lock_time.zcash_serialize(&mut writer)?;
// Denoted as `nExpiryHeight` in the spec.
writer.write_u32::<LittleEndian>(expiry_height.0)?;
// Denoted as `tx_in_count` and `tx_in` in the spec.
inputs.zcash_serialize(&mut writer)?;
// Denoted as `tx_out_count` and `tx_out` in the spec.
outputs.zcash_serialize(&mut writer)?;
// A bundle of fields denoted in the spec as `nSpendsSapling`, `vSpendsSapling`,
// `nOutputsSapling`,`vOutputsSapling`, `valueBalanceSapling`, `anchorSapling`,
// `vSpendProofsSapling`, `vSpendAuthSigsSapling`, `vOutputProofsSapling` and
// `bindingSigSapling`.
sapling_shielded_data.zcash_serialize(&mut writer)?;
// A bundle of fields denoted in the spec as `nActionsOrchard`, `vActionsOrchard`,
// `flagsOrchard`,`valueBalanceOrchard`, `anchorOrchard`, `sizeProofsOrchard`,
// `proofsOrchard`, `vSpendAuthSigsOrchard`, and `bindingSigOrchard`.
orchard_shielded_data.zcash_serialize(&mut writer)?;
// TODO: Add the rest of v6 transaction fields.
}
}
Ok(())
}

View File

@ -908,6 +908,36 @@ fn binding_signatures() {
)
.expect("a valid redjubjub::VerificationKey");
bvk.verify(sighash.as_ref(), &sapling_shielded_data.binding_sig)
.expect("verification passes");
at_least_one_v5_checked = true;
}
}
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data,
..
} => {
if let Some(sapling_shielded_data) = sapling_shielded_data {
// V6 txs have the outputs spent by their transparent inputs hashed into
// their SIGHASH, so we need to exclude txs with transparent inputs.
//
// References:
//
// <https://zips.z.cash/zip-0244#s-2c-amounts-sig-digest>
// <https://zips.z.cash/zip-0244#s-2d-scriptpubkeys-sig-digest>
if tx.has_transparent_inputs() {
continue;
}
let sighash = tx.sighash(nu, HashType::ALL, &[], None);
let bvk = redjubjub::VerificationKey::try_from(
sapling_shielded_data.binding_verification_key(),
)
.expect("a valid redjubjub::VerificationKey");
bvk.verify(sighash.as_ref(), &sapling_shielded_data.binding_sig)
.expect("verification passes");

View File

@ -28,6 +28,8 @@ impl<'a> TxIdBuilder<'a> {
| Transaction::V3 { .. }
| Transaction::V4 { .. } => self.txid_v1_to_v4(),
Transaction::V5 { .. } => self.txid_v5(),
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => self.txid_v6(),
}
}
@ -48,4 +50,10 @@ impl<'a> TxIdBuilder<'a> {
// We compute v5 txid (from ZIP-244) using librustzcash.
Some(Hash(*self.trans.to_librustzcash(nu).ok()?.txid().as_ref()))
}
/// Passthrough to txid_v5 for V6 transactions.
#[cfg(feature = "tx_v6")]
fn txid_v6(self) -> Option<Hash> {
self.txid_v5()
}
}

View File

@ -142,6 +142,8 @@ impl From<&Transaction> for UnminedTxId {
match transaction {
V1 { .. } | V2 { .. } | V3 { .. } | V4 { .. } => Legacy(transaction.into()),
V5 { .. } => Witnessed(transaction.into()),
#[cfg(feature = "tx_v6")]
V6 { .. } => Witnessed(transaction.into()),
}
}
}

View File

@ -31,6 +31,8 @@ getblocktemplate-rpcs = [
"zebra-chain/getblocktemplate-rpcs",
]
tx_v6 = ["zebra-chain/tx_v6", "zebra-state/tx_v6"]
# Test-only features
proptest-impl = ["proptest", "proptest-derive", "zebra-chain/proptest-impl", "zebra-state/proptest-impl"]

View File

@ -523,6 +523,19 @@ where
sapling_shielded_data,
orchard_shielded_data,
)?,
#[cfg(feature="tx_v6")]
Transaction::V6 {
sapling_shielded_data,
orchard_shielded_data,
..
} => Self::verify_v6_transaction(
&req,
&network,
script_verifier,
cached_ffi_transaction.clone(),
sapling_shielded_data,
orchard_shielded_data,
)?,
};
if let Some(unmined_tx) = req.mempool_transaction() {
@ -1027,6 +1040,26 @@ where
}
}
/// Passthrough to verify_v5_transaction, but for V6 transactions.
#[cfg(feature = "tx_v6")]
fn verify_v6_transaction(
request: &Request,
network: &Network,
script_verifier: script::Verifier,
cached_ffi_transaction: Arc<CachedFfiTransaction>,
sapling_shielded_data: &Option<sapling::ShieldedData<sapling::SharedAnchor>>,
orchard_shielded_data: &Option<orchard::ShieldedData>,
) -> Result<AsyncChecks, TransactionError> {
Self::verify_v5_transaction(
request,
network,
script_verifier,
cached_ffi_transaction,
sapling_shielded_data,
orchard_shielded_data,
)
}
/// Verifies if a transaction's transparent inputs are valid using the provided
/// `script_verifier` and `cached_ffi_transaction`.
///

View File

@ -48,6 +48,8 @@ elasticsearch = [
"zebra-chain/elasticsearch",
]
tx_v6 = ["zebra-chain/tx_v6"]
[dependencies]
bincode = { workspace = true }
chrono = { workspace = true, features = ["clock", "std"] }

View File

@ -1563,6 +1563,22 @@ impl Chain {
sapling_shielded_data,
orchard_shielded_data,
),
#[cfg(feature="tx_v6")]
V6 {
inputs,
outputs,
sapling_shielded_data,
orchard_shielded_data,
..
} => (
inputs,
outputs,
&None,
&None,
sapling_shielded_data,
orchard_shielded_data,
),
V1 { .. } | V2 { .. } | V3 { .. } => unreachable!(
"older transaction versions only exist in finalized blocks, because of the mandatory canopy checkpoint",
),
@ -1731,6 +1747,22 @@ impl UpdateWith<ContextuallyVerifiedBlock> for Chain {
sapling_shielded_data,
orchard_shielded_data,
),
#[cfg(feature="tx_v6")]
V6 {
inputs,
outputs,
sapling_shielded_data,
orchard_shielded_data,
..
} => (
inputs,
outputs,
&None,
&None,
sapling_shielded_data,
orchard_shielded_data,
),
V1 { .. } | V2 { .. } | V3 { .. } => unreachable!(
"older transaction versions only exist in finalized blocks, because of the mandatory canopy checkpoint",
),

View File

@ -34,6 +34,8 @@ impl FakeChainHelper for Arc<Block> {
Transaction::V3 { inputs, .. } => &mut inputs[0],
Transaction::V4 { inputs, .. } => &mut inputs[0],
Transaction::V5 { inputs, .. } => &mut inputs[0],
#[cfg(feature = "tx_v6")]
Transaction::V6 { inputs, .. } => &mut inputs[0],
};
match input {

View File

@ -158,6 +158,8 @@ test_sync_to_mandatory_checkpoint_testnet = []
test_sync_past_mandatory_checkpoint_mainnet = []
test_sync_past_mandatory_checkpoint_testnet = []
tx_v6 = ["zebra-chain/tx_v6", "zebra-state/tx_v6", "zebra-consensus/tx_v6"]
[dependencies]
zebra-chain = { path = "../zebra-chain", version = "1.0.0-beta.45" }
zebra-consensus = { path = "../zebra-consensus", version = "1.0.0-beta.45" }

View File

@ -568,6 +568,8 @@ impl SpendConflictTestInput {
// No JoinSplits
Transaction::V1 { .. } | Transaction::V5 { .. } => {}
#[cfg(feature = "tx_v6")]
Transaction::V6 { .. } => {}
}
}
}
@ -638,6 +640,14 @@ impl SpendConflictTestInput {
Self::remove_sapling_transfers_with_conflicts(sapling_shielded_data, &conflicts)
}
#[cfg(feature = "tx_v6")]
Transaction::V6 {
sapling_shielded_data,
..
} => {
Self::remove_sapling_transfers_with_conflicts(sapling_shielded_data, &conflicts)
}
// No Spends
Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } => {}
}
@ -709,6 +719,12 @@ impl SpendConflictTestInput {
..
} => Self::remove_orchard_actions_with_conflicts(orchard_shielded_data, &conflicts),
#[cfg(feature = "tx_v6")]
Transaction::V6 {
orchard_shielded_data,
..
} => Self::remove_orchard_actions_with_conflicts(orchard_shielded_data, &conflicts),
// No Spends
Transaction::V1 { .. }
| Transaction::V2 { .. }