zebra/zebra-chain/src/value_balance.rs

187 lines
5.7 KiB
Rust

//! A type that can hold the four types of Zcash value pools.
use crate::amount::{Amount, Constraint, Error, NonNegative};
#[cfg(any(test, feature = "proptest-impl"))]
mod arbitrary;
#[cfg(test)]
mod tests;
/// An amount spread between different Zcash pools.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ValueBalance<C> {
transparent: Amount<C>,
sprout: Amount<C>,
sapling: Amount<C>,
orchard: Amount<C>,
}
impl<C> ValueBalance<C>
where
C: Constraint + Copy,
{
/// [Consensus rule]: The remaining value in the transparent transaction value pool MUST
/// be nonnegative.
///
/// This rule applies to Block and Mempool transactions.
///
/// [Consensus rule]: https://zips.z.cash/protocol/protocol.pdf#transactions
pub fn remaining_transaction_value(&self) -> Result<Amount<NonNegative>, Error> {
// This rule checks the transparent value balance minus the sum of the sprout,
// sapling, and orchard value balances in a transaction is nonnegative.
(self.transparent - (self.sprout + self.sapling + self.orchard)?)?
.constrain::<NonNegative>()
}
/// Creates a [`ValueBalance`] from the given transparent amount.
pub fn from_transparent_amount(transparent_amount: Amount<C>) -> Self {
ValueBalance {
transparent: transparent_amount,
..ValueBalance::zero()
}
}
/// Creates a [`ValueBalance`] from the given sprout amount.
pub fn from_sprout_amount(sprout_amount: Amount<C>) -> Self {
ValueBalance {
sprout: sprout_amount,
..ValueBalance::zero()
}
}
/// Creates a [`ValueBalance`] from the given sapling amount.
pub fn from_sapling_amount(sapling_amount: Amount<C>) -> Self {
ValueBalance {
sapling: sapling_amount,
..ValueBalance::zero()
}
}
/// Creates a [`ValueBalance`] from the given orchard amount.
pub fn from_orchard_amount(orchard_amount: Amount<C>) -> Self {
ValueBalance {
orchard: orchard_amount,
..ValueBalance::zero()
}
}
/// Get the transparent amount from the [`ValueBalance`].
pub fn transparent_amount(&self) -> Amount<C> {
self.transparent
}
/// Insert a transparent value balance into a given [`ValueBalance`]
/// leaving the other values untouched.
pub fn set_transparent_value_balance(
&mut self,
transparent_value_balance: ValueBalance<C>,
) -> &Self {
self.transparent = transparent_value_balance.transparent;
self
}
/// Get the sprout amount from the [`ValueBalance`].
pub fn sprout_amount(&self) -> Amount<C> {
self.sprout
}
/// Insert a sprout value balance into a given [`ValueBalance`]
/// leaving the other values untouched.
pub fn set_sprout_value_balance(&mut self, sprout_value_balance: ValueBalance<C>) -> &Self {
self.sprout = sprout_value_balance.sprout;
self
}
/// Get the sapling amount from the [`ValueBalance`].
pub fn sapling_amount(&self) -> Amount<C> {
self.sapling
}
/// Insert a sapling value balance into a given [`ValueBalance`]
/// leaving the other values untouched.
pub fn set_sapling_value_balance(&mut self, sapling_value_balance: ValueBalance<C>) -> &Self {
self.sapling = sapling_value_balance.sapling;
self
}
/// Get the orchard amount from the [`ValueBalance`].
pub fn orchard_amount(&self) -> Amount<C> {
self.orchard
}
/// Insert an orchard value balance into a given [`ValueBalance`]
/// leaving the other values untouched.
pub fn set_orchard_value_balance(&mut self, orchard_value_balance: ValueBalance<C>) -> &Self {
self.orchard = orchard_value_balance.orchard;
self
}
/// Creates a [`ValueBalance`] where all the pools are zero.
pub fn zero() -> Self {
let zero = Amount::zero();
Self {
transparent: zero,
sprout: zero,
sapling: zero,
orchard: zero,
}
}
}
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
/// Errors that can be returned when validating a [`ValueBalance`].
pub enum ValueBalanceError {
#[error("value balance contains invalid amounts")]
/// Any error related to [`Amount`]s inside the [`ValueBalance`]
AmountError(#[from] Error),
}
impl<C> std::ops::Add for ValueBalance<C>
where
C: Constraint,
{
type Output = Result<ValueBalance<C>, ValueBalanceError>;
fn add(self, rhs: ValueBalance<C>) -> Self::Output {
Ok(ValueBalance::<C> {
transparent: (self.transparent + rhs.transparent)?,
sprout: (self.sprout + rhs.sprout)?,
sapling: (self.sapling + rhs.sapling)?,
orchard: (self.orchard + rhs.orchard)?,
})
}
}
impl<C> std::ops::Add<ValueBalance<C>> for Result<ValueBalance<C>, ValueBalanceError>
where
C: Constraint,
{
type Output = Result<ValueBalance<C>, ValueBalanceError>;
fn add(self, rhs: ValueBalance<C>) -> Self::Output {
self? + rhs
}
}
impl<C> std::ops::Sub for ValueBalance<C>
where
C: Constraint,
{
type Output = Result<ValueBalance<C>, ValueBalanceError>;
fn sub(self, rhs: ValueBalance<C>) -> Self::Output {
Ok(ValueBalance::<C> {
transparent: (self.transparent - rhs.transparent)?,
sprout: (self.sprout - rhs.sprout)?,
sapling: (self.sapling - rhs.sapling)?,
orchard: (self.orchard - rhs.orchard)?,
})
}
}
impl<C> std::ops::Sub<ValueBalance<C>> for Result<ValueBalance<C>, ValueBalanceError>
where
C: Constraint,
{
type Output = Result<ValueBalance<C>, ValueBalanceError>;
fn sub(self, rhs: ValueBalance<C>) -> Self::Output {
self? - rhs
}
}