diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index f239b0ba0..4367e47aa 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,4 +1,9 @@ -//! Structs representing the components within Zcash transactions. +//! Types representing the components within Zcash transactions. + +use std::marker::PhantomData; + +use zcash_protocol::value::BalanceError; + pub mod amount { pub use zcash_protocol::value::{ BalanceError, ZatBalance as Amount, Zatoshis as NonNegativeAmount, COIN, @@ -31,3 +36,136 @@ pub use self::tze::{TzeIn, TzeOut}; // π_A + π_B + π_C pub const GROTH_PROOF_SIZE: usize = 48 + 96 + 48; + +/// The protocol-agnostic parts of a shielded bundle. +/// +/// The trait methods can be implemented without any knowledge of protocol-specific +/// details, only requiring the ability to parse the general bundle structure within a +/// transaction. +pub trait ShieldedBundle { + fn value_balance(&self) -> Amount; +} + +impl ShieldedBundle for sprout::Bundle { + fn value_balance(&self) -> Amount { + // We don't support building Sprout bundles in Rust. + self.value_balance() + .expect("Sprout bundles are all checked by consensus") + } +} + +impl ShieldedBundle for ::sapling::Bundle { + fn value_balance(&self) -> Amount { + *self.value_balance() + } +} + +impl ShieldedBundle for ::orchard::Bundle { + fn value_balance(&self) -> Amount { + *self.value_balance() + } +} + +/// The transparent part of a transaction. +pub trait TransparentPart { + type Bundle; + + fn value_balance(bundle: &Self::Bundle, get_prevout_value: F) -> Result + where + E: From, + F: FnMut(&OutPoint) -> Result; +} + +#[derive(Debug)] +pub struct Transparent { + _auth: PhantomData, +} + +impl TransparentPart for Transparent { + type Bundle = transparent::Bundle; + + fn value_balance(bundle: &Self::Bundle, get_prevout_value: F) -> Result + where + E: From, + F: FnMut(&OutPoint) -> Result, + { + bundle.value_balance(get_prevout_value) + } +} + +/// The Sprout part of a transaction. +pub trait SproutPart { + type Bundle: ShieldedBundle; +} + +/// Marker type for a transaction that may contain a Sprout part. +#[derive(Debug)] +pub struct Sprout; + +impl SproutPart for Sprout { + type Bundle = sprout::Bundle; +} + +/// The Sapling part of a transaction. +pub trait SaplingPart { + type Bundle: ShieldedBundle; +} + +/// Marker type for a transaction that may contain a Sapling part. +#[derive(Debug)] +pub struct Sapling { + _auth: PhantomData, +} + +impl SaplingPart for Sapling { + type Bundle = ::sapling::Bundle; +} + +/// The Orchard part of a transaction. +pub trait OrchardPart { + type Bundle: ShieldedBundle; +} + +/// Marker type for a transaction that may contain an Orchard part. +#[derive(Debug)] +pub struct Orchard { + _auth: PhantomData, +} + +impl OrchardPart for Orchard { + type Bundle = ::orchard::bundle::Bundle; +} + +/// The TZE part of a transaction. +#[cfg(zcash_unstable = "zfuture")] +pub trait TzePart { + type Bundle; +} + +/// Marker type for a transaction that may contain a TZE part. +#[cfg(zcash_unstable = "zfuture")] +#[derive(Debug)] +pub struct Tze { + _auth: PhantomData, +} + +#[cfg(zcash_unstable = "zfuture")] +impl TzePart for Tze { + type Bundle = tze::Bundle; +} + +/// The Transparent part of an authorized transaction. +pub trait AuthorizedTransparentPart: TransparentPart {} + +/// The Sprout part of an authorized transaction. +pub trait AuthorizedSproutPart: SproutPart {} + +/// The Sapling part of an authorized transaction. +pub trait AuthorizedSaplingPart: SaplingPart {} + +/// The Orchard part of an authorized transaction. +pub trait AuthorizedOrchardPart: OrchardPart {} + +/// The TZE part of an authorized transaction. +#[cfg(zcash_unstable = "zfuture")] +pub trait AuthorizedTzePart: TzePart {} diff --git a/zcash_primitives/src/transaction/components/orchard.rs b/zcash_primitives/src/transaction/components/orchard.rs index 9f7df66b6..bed830e9d 100644 --- a/zcash_primitives/src/transaction/components/orchard.rs +++ b/zcash_primitives/src/transaction/components/orchard.rs @@ -13,7 +13,7 @@ use orchard::{ }; use zcash_encoding::{Array, CompactSize, Vector}; -use super::Amount; +use super::{Amount, AuthorizedOrchardPart, Orchard}; use crate::transaction::Transaction; pub const FLAG_SPENDS_ENABLED: u8 = 0b0000_0001; @@ -44,6 +44,8 @@ impl MapAuth for () { } } +impl AuthorizedOrchardPart for Orchard {} + /// Reads an [`orchard::Bundle`] from a v5 transaction format. pub fn read_v5_bundle( mut reader: R, diff --git a/zcash_primitives/src/transaction/components/sapling.rs b/zcash_primitives/src/transaction/components/sapling.rs index 62e493865..8b63f82bb 100644 --- a/zcash_primitives/src/transaction/components/sapling.rs +++ b/zcash_primitives/src/transaction/components/sapling.rs @@ -21,7 +21,7 @@ use crate::{ transaction::Transaction, }; -use super::{Amount, GROTH_PROOF_SIZE}; +use super::{Amount, AuthorizedSaplingPart, Sapling, GROTH_PROOF_SIZE}; /// Returns the enforcement policy for ZIP 212 at the given height. pub fn zip212_enforcement(params: &impl Parameters, height: BlockHeight) -> Zip212Enforcement { @@ -84,6 +84,8 @@ impl MapAuth for () { } } +impl AuthorizedSaplingPart for Sapling {} + /// Consensus rules (§4.4) & (§4.5): /// - Canonical encoding is enforced here. /// - "Not small order" is enforced here. diff --git a/zcash_primitives/src/transaction/components/sprout.rs b/zcash_primitives/src/transaction/components/sprout.rs index b3e2370f7..eb8cc70fc 100644 --- a/zcash_primitives/src/transaction/components/sprout.rs +++ b/zcash_primitives/src/transaction/components/sprout.rs @@ -2,7 +2,7 @@ use std::io::{self, Read, Write}; -use super::{amount::Amount, GROTH_PROOF_SIZE}; +use super::{amount::Amount, AuthorizedSproutPart, Sprout, GROTH_PROOF_SIZE}; // π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H const PHGR_PROOF_SIZE: usize = 33 + 33 + 65 + 33 + 33 + 33 + 33 + 33; @@ -29,6 +29,8 @@ impl Bundle { } } +impl AuthorizedSproutPart for Sprout {} + #[derive(Clone)] #[allow(clippy::upper_case_acronyms)] pub(crate) enum SproutProof { diff --git a/zcash_primitives/src/transaction/components/transparent.rs b/zcash_primitives/src/transaction/components/transparent.rs index e2e730d26..dc6a2b666 100644 --- a/zcash_primitives/src/transaction/components/transparent.rs +++ b/zcash_primitives/src/transaction/components/transparent.rs @@ -7,7 +7,10 @@ use std::io::{self, Read, Write}; use crate::legacy::{Script, TransparentAddress}; -use super::amount::{Amount, BalanceError, NonNegativeAmount}; +use super::{ + amount::{Amount, BalanceError, NonNegativeAmount}, + AuthorizedTransparentPart, Transparent, +}; pub mod builder; @@ -202,6 +205,8 @@ impl TxOut { } } +impl AuthorizedTransparentPart for Transparent {} + #[cfg(any(test, feature = "test-dependencies"))] pub mod testing { use proptest::collection::vec; diff --git a/zcash_primitives/src/transaction/components/tze.rs b/zcash_primitives/src/transaction/components/tze.rs index 26e849cbc..5f1da37e8 100644 --- a/zcash_primitives/src/transaction/components/tze.rs +++ b/zcash_primitives/src/transaction/components/tze.rs @@ -7,7 +7,7 @@ use std::io::{self, Read, Write}; use zcash_encoding::{CompactSize, Vector}; -use super::amount::Amount; +use super::{amount::Amount, AuthorizedTzePart, Tze}; use crate::{extensions::transparent as tze, transaction::TxId}; pub mod builder; @@ -211,6 +211,8 @@ impl TzeOut { } } +impl AuthorizedTzePart for Tze {} + #[cfg(any(test, feature = "test-dependencies"))] pub mod testing { use proptest::collection::vec;