diff --git a/Cargo.toml b/Cargo.toml index 348c250f46..63d21cbf60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ sapling = { package = "sapling-crypto", version = "0.1.3" } # - Orchard nonempty = "0.7" -orchard = { version = "0.8.0", default-features = false } +orchard = { version = "0.8.0", default-features = false } pasta_curves = "0.5" # - Transparent diff --git a/zcash_client_backend/src/data_api/wallet.rs b/zcash_client_backend/src/data_api/wallet.rs index 4ea35f4b40..d9a44b70c5 100644 --- a/zcash_client_backend/src/data_api/wallet.rs +++ b/zcash_client_backend/src/data_api/wallet.rs @@ -1123,6 +1123,7 @@ where .orchard_bundle() .and_then(|bundle| { bundle + .as_vanilla_bundle() .decrypt_output_with_key(output_index, &orchard_internal_ivk) .map(|(note, _, _)| Note::Orchard(note)) }) diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs index f95d7efb80..c9b6d78a85 100644 --- a/zcash_client_backend/src/decrypt.rs +++ b/zcash_client_backend/src/decrypt.rs @@ -1,6 +1,5 @@ -use std::collections::HashMap; - use sapling::note_encryption::{PreparedIncomingViewingKey, SaplingDomain}; +use std::collections::HashMap; use zcash_note_encryption::{try_note_decryption, try_output_recovery_with_ovk}; use zcash_primitives::{ consensus::{self, BlockHeight}, @@ -159,7 +158,7 @@ pub fn decrypt_transaction<'a, P: consensus::Parameters, AccountId: Copy>( .collect(); #[cfg(feature = "orchard")] - let orchard_bundle = tx.orchard_bundle(); + let orchard_bundle = tx.orchard_bundle().map(|bundle| bundle.as_vanilla_bundle()); #[cfg(feature = "orchard")] let orchard_outputs = orchard_bundle .iter() diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index d85ea3d643..1ca71ebaa6 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -30,9 +30,9 @@ use crate::{ }, }; -use orchard::builder::BundleType; +use orchard::builder::{BundleType, InProgress, Unproven}; use orchard::note::AssetBase; -use orchard::orchard_flavor::OrchardVanilla; +use orchard::orchard_flavor::{OrchardFlavor, OrchardVanilla}; use orchard::Address; #[cfg(feature = "transparent-inputs")] @@ -41,16 +41,7 @@ use crate::transaction::components::transparent::builder::TransparentInputInfo; #[cfg(not(feature = "transparent-inputs"))] use std::convert::Infallible; -#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] -use orchard::{ - issuance, - issuance::{IssueBundle, IssueInfo}, - keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}, - orchard_flavor::OrchardZSA, -}; -#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] -use rand_core::OsRng; - +use crate::transaction::OrchardBundle; #[cfg(zcash_unstable = "zfuture")] use crate::{ extensions::transparent::{ExtensionTxBuilder, ToPayload}, @@ -62,6 +53,16 @@ use crate::{ fees::FutureFeeRule, }, }; +use orchard::bundle::Authorized; +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] +use orchard::{ + issuance, + issuance::{IssueBundle, IssueInfo}, + keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}, + orchard_flavor::OrchardZSA, +}; +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] +use rand_core::OsRng; /// Since Blossom activation, the default transaction expiry delta should be 40 blocks. /// @@ -868,8 +869,6 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< }; let mut unproven_orchard_bundle = None; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - let mut unproven_orchard_zsa_bundle = None; let mut orchard_meta = orchard::builder::BundleMetadata::empty(); if let Some(builder) = self.orchard_builder { @@ -879,12 +878,12 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< { let (bundle, meta) = builder.build(&mut rng).map_err(Error::OrchardBuild)?; - unproven_orchard_zsa_bundle = Some(bundle); + unproven_orchard_bundle = Some(OrchardBundle::OrchardZSA(bundle)); orchard_meta = meta; } } else { let (bundle, meta) = builder.build(&mut rng).map_err(Error::OrchardBuild)?; - unproven_orchard_bundle = Some(bundle); + unproven_orchard_bundle = Some(OrchardBundle::OrchardVanilla(bundle)); orchard_meta = meta; } }; @@ -902,8 +901,6 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< sapling_bundle, orchard_bundle: unproven_orchard_bundle, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: unproven_orchard_zsa_bundle, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: self.issuance_builder, #[cfg(zcash_unstable = "zfuture")] tze_bundle, @@ -949,42 +946,28 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< .transpose() .map_err(Error::SaplingBuild)?; - let orchard_bundle = unauthed_tx - .orchard_bundle - .map(|b| { - b.create_proof( - &orchard::circuit::ProvingKey::build::(), + let orchard_bundle: Option> = match unauthed_tx.orchard_bundle { + Some(OrchardBundle::OrchardVanilla(b)) => { + Some(OrchardBundle::OrchardVanilla(prove_and_sign( + b, &mut rng, - ) - .and_then(|b| { - b.apply_signatures( - &mut rng, - *shielded_sig_commitment.as_ref(), - &self.orchard_saks, - ) - }) - }) - .transpose() - .map_err(Error::OrchardBuild)?; + &orchard::circuit::ProvingKey::build::(), + shielded_sig_commitment.as_ref(), + &self.orchard_saks, + )?)) + } - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - let orchard_zsa_bundle = unauthed_tx - .orchard_zsa_bundle - .map(|b| { - b.create_proof( - &orchard::circuit::ProvingKey::build::(), - &mut rng, - ) - .and_then(|b| { - b.apply_signatures( - &mut rng, - *shielded_sig_commitment.as_ref(), - &self.orchard_saks, - ) - }) - }) - .transpose() - .map_err(Error::OrchardBuild)?; + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + Some(OrchardBundle::OrchardZSA(b)) => Some(OrchardBundle::OrchardZSA(prove_and_sign( + b, + &mut rng, + &orchard::circuit::ProvingKey::build::(), + shielded_sig_commitment.as_ref(), + &self.orchard_saks, + )?)), + + None => None, + }; #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] let issue_bundle = unauthed_tx @@ -1003,8 +986,6 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< sapling_bundle, orchard_bundle, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle, #[cfg(zcash_unstable = "zfuture")] tze_bundle, @@ -1020,6 +1001,22 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder< } } +fn prove_and_sign( + bundle: orchard::Bundle, V, D>, + mut rng: &mut (impl RngCore + CryptoRng), + proving_key: &orchard::circuit::ProvingKey, + shielded_sig_commitment: &[u8; 32], + orchard_saks: &[orchard::keys::SpendAuthorizingKey], +) -> Result, Error> +where + D: OrchardFlavor, +{ + bundle + .create_proof(proving_key, &mut rng) + .and_then(|b| b.apply_signatures(&mut rng, *shielded_sig_commitment, orchard_saks)) + .map_err(Error::OrchardBuild) +} + #[cfg(zcash_unstable = "zfuture")] impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> ExtensionTxBuilder<'a> for Builder<'a, P, U> diff --git a/zcash_primitives/src/transaction/components/orchard.rs b/zcash_primitives/src/transaction/components/orchard.rs index f8eee9e8cd..6bdedcf298 100644 --- a/zcash_primitives/src/transaction/components/orchard.rs +++ b/zcash_primitives/src/transaction/components/orchard.rs @@ -2,8 +2,11 @@ use std::convert::TryFrom; use std::io::{self, Read, Write}; +use super::Amount; +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] use crate::transaction::components::issuance::read_asset; -use byteorder::{ReadBytesExt, WriteBytesExt}; +use crate::transaction::{OrchardBundle, Transaction}; +use byteorder::ReadBytesExt; use nonempty::NonEmpty; use orchard::{ bundle::{Authorization, Authorized, Flags}, @@ -12,16 +15,14 @@ use orchard::{ orchard_flavor::{OrchardVanilla, OrchardZSA}, primitives::redpallas::{self, SigType, Signature, SpendAuth, VerificationKey}, value::{NoteValue, ValueCommitment}, - Action, Anchor, + Action, Anchor, Bundle, }; use zcash_encoding::{Array, CompactSize, Vector}; use zcash_note_encryption::note_bytes::NoteBytes; -use super::Amount; -use crate::transaction::Transaction; - +use zcash_protocol::value::ZatBalance; #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] -use byteorder::LittleEndian; +use {byteorder::LittleEndian, byteorder::WriteBytesExt}; pub const FLAG_SPENDS_ENABLED: u8 = 0b0000_0001; pub const FLAG_OUTPUTS_ENABLED: u8 = 0b0000_0010; @@ -51,24 +52,6 @@ impl MapAuth for () { } } -pub trait ReadBurn { - fn read_burn(reader: &mut R) -> io::Result>; -} - -// OrchardVanilla has no burn to read -impl ReadBurn for OrchardVanilla { - fn read_burn(_reader: &mut R) -> io::Result> { - Ok(Vec::new()) - } -} - -// Read burn for OrchardZSA -impl ReadBurn for OrchardZSA { - fn read_burn(reader: &mut R) -> io::Result> { - Vector::read(reader, |r| read_burn(r)) - } -} - /// Reads an [`orchard::Bundle`] from a v5 transaction format. pub fn read_orchard_bundle( mut reader: R, @@ -149,7 +132,7 @@ pub fn read_orchard_zsa_bundle( let value_balance = Transaction::read_amount(&mut reader)?; - let burn = OrchardZSA::read_burn(&mut reader)?; + let burn = Vector::read(&mut reader, |r| read_burn(r))?; let binding_signature = read_signature::<_, redpallas::Binding>(&mut reader)?; @@ -165,6 +148,7 @@ pub fn read_orchard_zsa_bundle( ))) } +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] fn read_burn(reader: &mut R) -> io::Result<(AssetBase, NoteValue)> { Ok((read_asset(reader)?, read_note_value(reader)?)) } @@ -286,6 +270,7 @@ pub fn read_signature(mut reader: R) -> io::Result(mut reader: R) -> io::Result { let mut bytes = [0; 8]; reader.read_exact(&mut bytes)?; @@ -311,30 +296,14 @@ impl WriteBurn for OrchardZSA { /// Writes an [`orchard::Bundle`] in the appropriate transaction format. pub fn write_orchard_bundle( mut writer: W, - bundle: Option<&orchard::Bundle>, + bundle: Option<&OrchardBundle>, ) -> io::Result<()> { - if let Some(bundle) = &bundle { - Vector::write_nonempty(&mut writer, bundle.actions(), |w, a| { - write_action_without_auth(w, a) - })?; - - writer.write_all(&[bundle.flags().to_byte()])?; - writer.write_all(&bundle.value_balance().to_i64_le_bytes())?; - writer.write_all(&bundle.anchor().to_bytes())?; - Vector::write( - &mut writer, - bundle.authorization().proof().as_ref(), - |w, b| w.write_u8(*b), - )?; - Array::write( - &mut writer, - bundle.actions().iter().map(|a| a.authorization()), - |w, auth| w.write_all(&<[u8; 64]>::from(*auth)), - )?; - - writer.write_all(&<[u8; 64]>::from( - bundle.authorization().binding_signature(), - ))?; + if let Some(bundle) = bundle { + match bundle { + OrchardBundle::OrchardVanilla(b) => write_v5_bundle(b, writer)?, + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardBundle::OrchardZSA(b) => write_orchard_zsa_bundle(writer, b)?, + } } else { CompactSize::write(&mut writer, 0)?; } @@ -342,19 +311,41 @@ pub fn write_orchard_bundle( Ok(()) } +/// Writes an [`orchard::Bundle`] in the v5 transaction format. +pub fn write_v5_bundle( + bundle: &Bundle, + mut writer: W, +) -> io::Result<()> { + Vector::write_nonempty(&mut writer, bundle.actions(), |w, a| { + write_action_without_auth(w, a) + })?; + + writer.write_all(&[bundle.flags().to_byte()])?; + writer.write_all(&bundle.value_balance().to_i64_le_bytes())?; + writer.write_all(&bundle.anchor().to_bytes())?; + Vector::write( + &mut writer, + bundle.authorization().proof().as_ref(), + |w, b| w.write_all(&[*b]), + )?; + Array::write( + &mut writer, + bundle.actions().iter().map(|a| a.authorization()), + |w, auth| w.write_all(&<[u8; 64]>::from(*auth)), + )?; + writer.write_all(&<[u8; 64]>::from( + bundle.authorization().binding_signature(), + ))?; + + Ok(()) +} + /// Writes an [`orchard::Bundle`] in the appropriate transaction format. #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] pub fn write_orchard_zsa_bundle( mut writer: W, - bundle: Option<&orchard::Bundle>, + bundle: &orchard::Bundle, ) -> io::Result<()> { - if bundle.is_none() { - CompactSize::write(&mut writer, 0)?; - return Ok(()); - } - - let bundle = bundle.unwrap(); - // Exactly one action group for NU7 CompactSize::write(&mut writer, 1)?; @@ -435,51 +426,45 @@ pub mod testing { use proptest::prelude::*; use crate::transaction::components::amount::testing::arb_amount; - use crate::transaction::components::Amount; - use crate::transaction::TxVersion; + use crate::transaction::{OrchardBundle, TxVersion}; use orchard::bundle::{ testing::{self as t_orch}, - Authorized, Bundle, + Authorized, }; - use orchard::orchard_flavor::{OrchardVanilla, OrchardZSA}; + use orchard::orchard_flavor::OrchardZSA; prop_compose! { pub fn arb_bundle(n_actions: usize)( orchard_value_balance in arb_amount(), bundle in t_orch::BundleArb::arb_bundle(n_actions) - ) -> Bundle { + ) -> OrchardBundle { // overwrite the value balance, as we can't guarantee that the // value doesn't exceed the MAX_MONEY bounds. - bundle.try_map_value_balance::<_, (), _>(|_| Ok(orchard_value_balance)).unwrap() - } - } - - pub fn arb_bundle_for_version( - v: TxVersion, - ) -> impl Strategy>> { - if v.has_orchard() { - Strategy::boxed((1usize..100).prop_flat_map(|n| prop::option::of(arb_bundle(n)))) - } else { - Strategy::boxed(Just(None)) + OrchardBundle::OrchardVanilla(bundle.try_map_value_balance::<_, (), _>(|_| Ok(orchard_value_balance)).unwrap()) } } prop_compose! { + #[allow(unreachable_code)] pub fn arb_zsa_bundle(n_actions: usize)( - orchard_value_balance in arb_amount(), - bundle in t_orch::BundleArb::arb_bundle(n_actions) - ) -> Bundle { + _orchard_value_balance in arb_amount(), + _bundle in t_orch::BundleArb::::arb_bundle(n_actions) + ) -> OrchardBundle { // overwrite the value balance, as we can't guarantee that the // value doesn't exceed the MAX_MONEY bounds. - bundle.try_map_value_balance::<_, (), _>(|_| Ok(orchard_value_balance)).unwrap() + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + return OrchardBundle::OrchardZSA(_bundle.try_map_value_balance::<_, (), _>(|_| Ok(_orchard_value_balance)).unwrap()); + panic!("ZSA is not supported in this version"); } } - pub fn arb_zsa_bundle_for_version( + pub fn arb_bundle_for_version( v: TxVersion, - ) -> impl Strategy>> { + ) -> impl Strategy>> { if v.has_orchard_zsa() { Strategy::boxed((1usize..100).prop_flat_map(|n| prop::option::of(arb_zsa_bundle(n)))) + } else if v.has_orchard() { + Strategy::boxed((1usize..100).prop_flat_map(|n| prop::option::of(arb_bundle(n)))) } else { Strategy::boxed(Just(None)) } diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 2b974fe108..a1a43a0593 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -14,7 +14,7 @@ mod tests; use blake2b_simd::Hash as Blake2bHash; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use memuse::DynamicUsage; -use orchard::{builder::Unproven, orchard_flavor::OrchardVanilla}; +use orchard::{builder::Unproven, orchard_flavor::OrchardVanilla, Bundle}; use std::convert::TryFrom; use std::fmt; use std::fmt::Debug; @@ -39,14 +39,13 @@ use self::{ util::sha256d::{HashReader, HashWriter}, }; +#[cfg(zcash_unstable = "zfuture")] +use self::components::tze::{self, TzeIn, TzeOut}; #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] use crate::transaction::components::issuance; #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] use orchard::{issuance::IssueBundle, orchard_flavor::OrchardZSA}; -#[cfg(zcash_unstable = "zfuture")] -use self::components::tze::{self, TzeIn, TzeOut}; - const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270; const OVERWINTER_TX_VERSION: u32 = 3; const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; @@ -299,9 +298,6 @@ pub trait Authorization { type SaplingAuth: sapling::bundle::Authorization; type OrchardAuth: orchard::bundle::Authorization; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - type OrchardZsaAuth: orchard::bundle::Authorization; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] type IssueAuth: orchard::issuance::IssueAuth; @@ -310,7 +306,7 @@ pub trait Authorization { } /// [`Authorization`] marker type for fully-authorized transactions. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Authorized; impl Authorization for Authorized { @@ -318,9 +314,6 @@ impl Authorization for Authorized { type SaplingAuth = sapling::bundle::Authorized; type OrchardAuth = orchard::bundle::Authorized; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - type OrchardZsaAuth = orchard::bundle::Authorized; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] type IssueAuth = orchard::issuance::Signed; @@ -340,9 +333,6 @@ impl Authorization for Unauthorized { sapling_builder::InProgress; type OrchardAuth = orchard::builder::InProgress; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - type OrchardZsaAuth = orchard::builder::InProgress; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] type IssueAuth = orchard::issuance::Unauthorized; @@ -371,6 +361,56 @@ impl PartialEq for Transaction { } } +#[derive(Debug, Clone)] +pub enum OrchardBundle { + OrchardVanilla(Bundle), + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardZSA(Bundle), +} + +impl OrchardBundle { + pub fn value_balance(&self) -> &Amount { + match self { + OrchardBundle::OrchardVanilla(b) => b.value_balance(), + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardBundle::OrchardZSA(b) => b.value_balance(), + } + } + + pub fn map_authorization( + self, + context: &mut R, + spend_auth: impl FnMut(&mut R, &A, A::SpendAuth) -> B::SpendAuth, + step: impl FnOnce(&mut R, A) -> B, + ) -> OrchardBundle { + match self { + OrchardBundle::OrchardVanilla(b) => { + OrchardBundle::OrchardVanilla(b.map_authorization(context, spend_auth, step)) + } + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardBundle::OrchardZSA(b) => { + OrchardBundle::OrchardZSA(b.map_authorization(context, spend_auth, step)) + } + } + } + + pub fn as_vanilla_bundle(&self) -> &Bundle { + match self { + OrchardBundle::OrchardVanilla(b) => b, + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardBundle::OrchardZSA(_) => panic!("Wrong bundle type"), + } + } + + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + pub fn as_zsa_bundle(&self) -> &Bundle { + match self { + OrchardBundle::OrchardVanilla(_) => panic!("Wrong bundle type"), + OrchardBundle::OrchardZSA(b) => b, + } + } +} + /// The information contained in a Zcash transaction. #[derive(Debug)] pub struct TransactionData { @@ -381,9 +421,7 @@ pub struct TransactionData { transparent_bundle: Option>, sprout_bundle: Option, sapling_bundle: Option>, - orchard_bundle: Option>, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: Option>, + orchard_bundle: Option>, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: Option>, #[cfg(zcash_unstable = "zfuture")] @@ -401,10 +439,7 @@ impl TransactionData { transparent_bundle: Option>, sprout_bundle: Option, sapling_bundle: Option>, - orchard_bundle: Option>, - #[rustfmt::skip] - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: Option>, + orchard_bundle: Option>, #[rustfmt::skip] #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: Option>, @@ -419,8 +454,6 @@ impl TransactionData { sapling_bundle, orchard_bundle, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle, #[cfg(zcash_unstable = "zfuture")] tze_bundle: None, @@ -439,7 +472,7 @@ impl TransactionData { transparent_bundle: Option>, sprout_bundle: Option, sapling_bundle: Option>, - orchard_bundle: Option>, + orchard_bundle: Option>, tze_bundle: Option>, ) -> Self { TransactionData { @@ -485,19 +518,10 @@ impl TransactionData { self.sapling_bundle.as_ref() } - pub fn orchard_bundle( - &self, - ) -> Option<&orchard::Bundle> { + pub fn orchard_bundle(&self) -> Option<&OrchardBundle> { self.orchard_bundle.as_ref() } - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - pub fn orchard_zsa_bundle( - &self, - ) -> Option<&orchard::Bundle> { - self.orchard_zsa_bundle.as_ref() - } - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] pub fn issue_bundle(&self) -> Option<&IssueBundle> { self.issue_bundle.as_ref() @@ -556,20 +580,10 @@ impl TransactionData { ) } - #[cfg(not(zcash_unstable = "nu6" /* TODO nu7 */ ))] fn digest_orchard>(&self, digester: &D) -> D::OrchardDigest { digester.digest_orchard(self.orchard_bundle.as_ref()) } - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - fn digest_orchard>(&self, digester: &D) -> D::OrchardDigest { - if self.version.has_orchard_zsa() { - digester.digest_orchard_zsa(self.orchard_zsa_bundle.as_ref()) - } else { - digester.digest_orchard(self.orchard_bundle.as_ref()) - } - } - /// Maps the bundles from one type to another. /// /// This shouldn't be necessary for most use cases; it is provided for handling the @@ -583,17 +597,8 @@ impl TransactionData { Option>, ) -> Option>, f_orchard: impl FnOnce( - Option>, - ) -> Option< - orchard::bundle::Bundle, - >, - #[rustfmt::skip] - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - f_zsa_orchard: impl FnOnce( - Option>, - ) -> Option< - orchard::bundle::Bundle, - >, + Option>, + ) -> Option>, #[rustfmt::skip] #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] f_issue: impl FnOnce( @@ -614,8 +619,6 @@ impl TransactionData { sapling_bundle: f_sapling(self.sapling_bundle), orchard_bundle: f_orchard(self.orchard_bundle), #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: f_zsa_orchard(self.orchard_zsa_bundle), - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: f_issue(self.issue_bundle), #[cfg(zcash_unstable = "zfuture")] tze_bundle: f_tze(self.tze_bundle), @@ -627,11 +630,6 @@ impl TransactionData { f_transparent: impl transparent::MapAuth, mut f_sapling: impl sapling_serialization::MapAuth, mut f_orchard: impl orchard_serialization::MapAuth, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - mut f_orchard_zsa: impl orchard_serialization::MapAuth< - A::OrchardZsaAuth, - B::OrchardZsaAuth, - >, #[rustfmt::skip] #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] f_issue: impl issuance::MapIssueAuth, @@ -663,14 +661,6 @@ impl TransactionData { ) }), #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: self.orchard_zsa_bundle.map(|b| { - b.map_authorization( - &mut f_orchard_zsa, - |f, _, s| f.map_spend_auth(s), - |f, a| f.map_authorization(a), - ) - }), - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: self .issue_bundle .map(|b| b.map_authorization(|a| f_issue.map_issue_authorization(a))), @@ -831,8 +821,6 @@ impl Transaction { }), orchard_bundle: None, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: None, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: None, #[cfg(zcash_unstable = "zfuture")] tze_bundle: None, @@ -885,9 +873,7 @@ impl Transaction { transparent_bundle, sprout_bundle: None, sapling_bundle, - orchard_bundle, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: None, + orchard_bundle: orchard_bundle.map(OrchardBundle::OrchardVanilla), #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: None, #[cfg(zcash_unstable = "zfuture")] @@ -942,8 +928,7 @@ impl Transaction { transparent_bundle, sprout_bundle: None, sapling_bundle, - orchard_bundle: None, - orchard_zsa_bundle, + orchard_bundle: orchard_zsa_bundle.map(OrchardBundle::OrchardZSA), issue_bundle, #[cfg(zcash_unstable = "zfuture")] tze_bundle, @@ -1080,10 +1065,7 @@ impl Transaction { self.write_header(&mut writer)?; self.write_transparent(&mut writer)?; self.write_sapling(&mut writer)?; - orchard_serialization::write_orchard_zsa_bundle( - &mut writer, - self.orchard_zsa_bundle.as_ref(), - )?; + orchard_serialization::write_orchard_bundle(&mut writer, self.orchard_bundle.as_ref())?; issuance::write_v6_bundle(self.issue_bundle.as_ref(), &mut writer)?; #[cfg(zcash_unstable = "zfuture")] self.write_tze(&mut writer)?; @@ -1169,13 +1151,7 @@ pub trait TransactionDigest { fn digest_orchard( &self, - orchard_bundle: Option<&orchard::Bundle>, - ) -> Self::OrchardDigest; - - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - fn digest_orchard_zsa( - &self, - orchard_bundle: Option<&orchard::Bundle>, + orchard_bundle: Option<&OrchardBundle>, ) -> Self::OrchardDigest; #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] @@ -1250,7 +1226,6 @@ pub mod testing { transparent_bundle in transparent_testing::arb_bundle(), sapling_bundle in sapling_testing::arb_bundle_for_version(version), orchard_bundle in orchard_testing::arb_bundle_for_version(version), - _orchard_zsa_bundle in orchard_testing::arb_zsa_bundle_for_version(version), _issue_bundle in issuance::testing::arb_bundle_for_version(version), version in Just(version) ) -> TransactionData { @@ -1264,8 +1239,6 @@ pub mod testing { sapling_bundle, orchard_bundle, #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - orchard_zsa_bundle: _orchard_zsa_bundle, - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] issue_bundle: _issue_bundle, } } diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 14fd491b94..8a737f5c43 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -3,10 +3,6 @@ use std::ops::Deref; use proptest::prelude::*; -use crate::{ - consensus::BranchId, legacy::Script, transaction::components::amount::NonNegativeAmount, -}; - use super::{ sapling, sighash::{ @@ -20,6 +16,12 @@ use super::{ txid::TxIdDigester, Authorization, Transaction, TransactionData, TxDigests, TxIn, }; +use crate::transaction::OrchardBundle::OrchardVanilla; +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] +use crate::transaction::OrchardBundle::OrchardZSA; +use crate::{ + consensus::BranchId, legacy::Script, transaction::components::amount::NonNegativeAmount, +}; #[cfg(zcash_unstable = "zfuture")] use super::components::tze; @@ -53,13 +55,16 @@ fn check_roundtrip(tx: Transaction) -> Result<(), TestCaseError> { ); prop_assert_eq!(tx.sapling_value_balance(), txo.sapling_value_balance()); prop_assert_eq!( - tx.orchard_bundle.as_ref().map(|v| *v.value_balance()), - txo.orchard_bundle.as_ref().map(|v| *v.value_balance()) - ); - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - prop_assert_eq!( - tx.orchard_zsa_bundle.as_ref().map(|v| *v.value_balance()), - txo.orchard_zsa_bundle.as_ref().map(|v| *v.value_balance()) + tx.orchard_bundle.as_ref().map(|v| match v { + OrchardVanilla(b) => *b.value_balance(), + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardZSA(b) => *b.value_balance(), + }), + txo.orchard_bundle.as_ref().map(|v| match v { + OrchardVanilla(b) => *b.value_balance(), + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardZSA(b) => *b.value_balance(), + }) ); #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] if tx.issue_bundle.is_some() { @@ -221,9 +226,6 @@ impl Authorization for TestUnauthorized { type SaplingAuth = sapling::bundle::Authorized; type OrchardAuth = orchard::bundle::Authorized; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - type OrchardZsaAuth = orchard::bundle::Authorized; - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] type IssueAuth = orchard::issuance::Signed; @@ -296,8 +298,6 @@ fn zip_0244() { txdata.sapling_bundle().cloned(), txdata.orchard_bundle().cloned(), #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - txdata.orchard_zsa_bundle().cloned(), - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] txdata.issue_bundle().cloned(), ); #[cfg(zcash_unstable = "zfuture")] diff --git a/zcash_primitives/src/transaction/txid.rs b/zcash_primitives/src/transaction/txid.rs index a89537c1fd..86364f0c9b 100644 --- a/zcash_primitives/src/transaction/txid.rs +++ b/zcash_primitives/src/transaction/txid.rs @@ -6,7 +6,6 @@ use blake2b_simd::{Hash as Blake2bHash, Params, State}; use byteorder::{LittleEndian, WriteBytesExt}; use ff::PrimeField; use orchard::bundle; -use orchard::orchard_flavor::OrchardVanilla; use crate::{ consensus::{BlockHeight, BranchId}, @@ -21,13 +20,8 @@ use super::{ amount::Amount, transparent::{self, TxIn, TxOut}, }, - Authorization, Authorized, TransactionDigest, TransparentDigests, TxDigests, TxId, TxVersion, -}; - -#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] -use orchard::{ - issuance::{IssueBundle, Signed}, - orchard_flavor::OrchardZSA, + Authorization, Authorized, OrchardBundle, TransactionDigest, TransparentDigests, TxDigests, + TxId, TxVersion, }; #[cfg(zcash_unstable = "zfuture")] @@ -35,6 +29,12 @@ use super::{ components::tze::{self, TzeIn, TzeOut}, TzeDigests, }; +use crate::transaction::OrchardBundle::OrchardVanilla; +#[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] +use { + crate::transaction::OrchardBundle::OrchardZSA, + orchard::issuance::{IssueBundle, Signed}, +}; /// TxId tree root personalization const ZCASH_TX_PERSONALIZATION_PREFIX: &[u8; 12] = b"ZcashTxHash_"; @@ -347,17 +347,15 @@ impl TransactionDigest for TxIdDigester { fn digest_orchard( &self, - orchard_bundle: Option<&bundle::Bundle>, + orchard_bundle: Option<&OrchardBundle>, ) -> Self::OrchardDigest { - orchard_bundle.map(|b| b.commitment().0) - } - - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - fn digest_orchard_zsa( - &self, - orchard_bundle: Option<&bundle::Bundle>, - ) -> Self::OrchardDigest { - orchard_bundle.map(|b| b.commitment().0) + orchard_bundle.map(|b| { + match b { + OrchardVanilla(v) => v.commitment().0, + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardZSA(z) => z.commitment().0, + } + }) } #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] @@ -541,20 +539,14 @@ impl TransactionDigest for BlockTxCommitmentDigester { fn digest_orchard( &self, - orchard_bundle: Option<&bundle::Bundle>, + orchard_bundle: Option<&OrchardBundle>, ) -> Self::OrchardDigest { orchard_bundle.map_or_else(bundle::commitments::hash_bundle_auth_empty, |b| { - b.authorizing_commitment().0 - }) - } - - #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] - fn digest_orchard_zsa( - &self, - orchard_bundle: Option<&bundle::Bundle>, - ) -> Self::OrchardDigest { - orchard_bundle.map_or_else(bundle::commitments::hash_bundle_auth_empty, |b| { - b.authorizing_commitment().0 + match b { + OrchardVanilla(bundle) => bundle.authorizing_commitment().0, + #[cfg(zcash_unstable = "nu6" /* TODO nu7 */ )] + OrchardZSA(bundle) => bundle.authorizing_commitment().0, + } }) }