Skip to content

Commit

Permalink
Made Amount more generic. (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi authored Aug 11, 2023
1 parent 242316e commit e83521d
Show file tree
Hide file tree
Showing 22 changed files with 621 additions and 357 deletions.
3 changes: 3 additions & 0 deletions masp_primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ sha2 = "0.9"
# - Metrics
memuse = "0.2.1"

# - Checked arithmetic
num-traits = "0.2.14"

# - Secret management
subtle = "2.2.3"

Expand Down
33 changes: 17 additions & 16 deletions masp_primitives/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
pedersen_hash::{pedersen_hash, Personalization},
Node, ValueCommitment,
},
transaction::components::amount::Amount,
transaction::components::amount::{I32Sum, ValueSum},
};
use borsh::{BorshDeserialize, BorshSerialize};
use group::{Curve, GroupEncoding};
Expand All @@ -16,7 +16,7 @@ use std::{
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AllowedConversion {
/// The asset type that the note represents
assets: Amount,
assets: I32Sum,
/// Memorize generator because it's expensive to recompute
generator: jubjub::ExtendedPoint,
}
Expand Down Expand Up @@ -71,15 +71,15 @@ impl AllowedConversion {
}
}

impl From<AllowedConversion> for Amount {
fn from(allowed_conversion: AllowedConversion) -> Amount {
impl From<AllowedConversion> for I32Sum {
fn from(allowed_conversion: AllowedConversion) -> I32Sum {
allowed_conversion.assets
}
}

impl From<Amount> for AllowedConversion {
impl From<I32Sum> for AllowedConversion {
/// Produces an asset generator without cofactor cleared
fn from(assets: Amount) -> Self {
fn from(assets: I32Sum) -> Self {
let mut asset_generator = jubjub::ExtendedPoint::identity();
for (asset, value) in assets.components() {
// Compute the absolute value (failing if -i64::MAX is
Expand Down Expand Up @@ -123,7 +123,7 @@ impl BorshDeserialize for AllowedConversion {
/// computation of checking whether the asset generator corresponds to the
/// deserialized amount.
fn deserialize(buf: &mut &[u8]) -> borsh::maybestd::io::Result<Self> {
let assets = Amount::read(buf)?;
let assets = I32Sum::read(buf)?;
let gen_bytes =
<<jubjub::ExtendedPoint as GroupEncoding>::Repr as BorshDeserialize>::deserialize(buf)?;
let generator = Option::from(jubjub::ExtendedPoint::from_bytes(&gen_bytes))
Expand Down Expand Up @@ -174,15 +174,15 @@ impl SubAssign for AllowedConversion {

impl Sum for AllowedConversion {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(AllowedConversion::from(Amount::zero()), Add::add)
iter.fold(AllowedConversion::from(ValueSum::zero()), Add::add)
}
}

#[cfg(test)]
mod tests {
use crate::asset_type::AssetType;
use crate::convert::AllowedConversion;
use crate::transaction::components::amount::Amount;
use crate::transaction::components::amount::ValueSum;

/// Generate ZEC asset type
fn zec() -> AssetType {
Expand All @@ -199,11 +199,12 @@ mod tests {
#[test]
fn test_homomorphism() {
// Left operand
let a = Amount::from_pair(zec(), 5).unwrap()
+ Amount::from_pair(btc(), 6).unwrap()
+ Amount::from_pair(xan(), 7).unwrap();
let a = ValueSum::from_pair(zec(), 5i32).unwrap()
+ ValueSum::from_pair(btc(), 6i32).unwrap()
+ ValueSum::from_pair(xan(), 7i32).unwrap();
// Right operand
let b = Amount::from_pair(zec(), 2).unwrap() + Amount::from_pair(xan(), 10).unwrap();
let b =
ValueSum::from_pair(zec(), 2i32).unwrap() + ValueSum::from_pair(xan(), 10i32).unwrap();
// Test homomorphism
assert_eq!(
AllowedConversion::from(a.clone() + b.clone()),
Expand All @@ -213,9 +214,9 @@ mod tests {
#[test]
fn test_serialization() {
// Make conversion
let a: AllowedConversion = (Amount::from_pair(zec(), 5).unwrap()
+ Amount::from_pair(btc(), 6).unwrap()
+ Amount::from_pair(xan(), 7).unwrap())
let a: AllowedConversion = (ValueSum::from_pair(zec(), 5i32).unwrap()
+ ValueSum::from_pair(btc(), 6i32).unwrap()
+ ValueSum::from_pair(xan(), 7i32).unwrap())
.into();
// Serialize conversion
let mut data = Vec::new();
Expand Down
8 changes: 4 additions & 4 deletions masp_primitives/src/sapling/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
redjubjub::{PublicKey, Signature},
Node,
},
transaction::components::{Amount, GROTH_PROOF_SIZE},
transaction::components::{I128Sum, GROTH_PROOF_SIZE},
};

use super::{Diversifier, PaymentAddress, ProofGenerationKey, Rseed};
Expand Down Expand Up @@ -73,7 +73,7 @@ pub trait TxProver {
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
amount: &Amount,
amount: &I128Sum,
sighash: &[u8; 32],
) -> Result<Signature, ()>;
}
Expand All @@ -92,7 +92,7 @@ pub mod mock {
redjubjub::{PublicKey, Signature},
Diversifier, Node, PaymentAddress, ProofGenerationKey, Rseed,
},
transaction::components::{Amount, GROTH_PROOF_SIZE},
transaction::components::{I128Sum, GROTH_PROOF_SIZE},
};

use super::TxProver;
Expand Down Expand Up @@ -169,7 +169,7 @@ pub mod mock {
fn binding_sig(
&self,
_ctx: &mut Self::SaplingProvingContext,
_value: &Amount,
_value: &I128Sum,
_sighash: &[u8; 32],
) -> Result<Signature, ()> {
Err(())
Expand Down
14 changes: 7 additions & 7 deletions masp_primitives/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{

use self::{
components::{
amount::Amount,
amount::{I128Sum, ValueSum},
sapling::{
self, ConvertDescriptionV5, OutputDescriptionV5, SpendDescription, SpendDescriptionV5,
},
Expand Down Expand Up @@ -269,10 +269,10 @@ impl<A: Authorization> TransactionData<A> {
}

impl<A: Authorization> TransactionData<A> {
pub fn sapling_value_balance(&self) -> Amount {
pub fn sapling_value_balance(&self) -> I128Sum {
self.sapling_bundle
.as_ref()
.map_or(Amount::zero(), |b| b.value_balance.clone())
.map_or(ValueSum::zero(), |b| b.value_balance.clone())
}
}

Expand Down Expand Up @@ -355,8 +355,8 @@ impl Transaction {
})
}

fn read_amount<R: Read>(mut reader: R) -> io::Result<Amount> {
Amount::read(&mut reader).map_err(|_| {
fn read_i128_sum<R: Read>(mut reader: R) -> io::Result<I128Sum> {
I128Sum::read(&mut reader).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"Amount valueBalance out of range",
Expand Down Expand Up @@ -407,9 +407,9 @@ impl Transaction {
let n_converts = cd_v5s.len();
let n_outputs = od_v5s.len();
let value_balance = if n_spends > 0 || n_outputs > 0 {
Self::read_amount(&mut reader)?
Self::read_i128_sum(&mut reader)?
} else {
Amount::zero()
ValueSum::zero()
};

let spend_anchor = if n_spends > 0 {
Expand Down
61 changes: 24 additions & 37 deletions masp_primitives/src/transaction/builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Structs for building transactions.

use std::convert::TryInto;
use std::error;
use std::fmt;
use std::sync::mpsc::Sender;
Expand All @@ -19,7 +18,7 @@ use crate::{
sapling::{prover::TxProver, Diversifier, Node, Note, PaymentAddress},
transaction::{
components::{
amount::{Amount, BalanceError, MAX_MONEY},
amount::{BalanceError, I128Sum, U64Sum, ValueSum, MAX_MONEY},
sapling::{
self,
builder::{SaplingBuilder, SaplingMetadata},
Expand All @@ -43,10 +42,10 @@ const DEFAULT_TX_EXPIRY_DELTA: u32 = 20;
pub enum Error<FeeError> {
/// Insufficient funds were provided to the transaction builder; the given
/// additional amount is required in order to construct the transaction.
InsufficientFunds(Amount),
InsufficientFunds(I128Sum),
/// The transaction has inputs in excess of outputs and fees; the user must
/// add a change output.
ChangeRequired(Amount),
ChangeRequired(U64Sum),
/// An error occurred in computing the fees for a transaction.
Fee(FeeError),
/// An overflow or underflow occurred when computing value balances
Expand Down Expand Up @@ -251,7 +250,7 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
value: u64,
memo: MemoBytes,
) -> Result<(), sapling::builder::Error> {
if value > MAX_MONEY.try_into().unwrap() {
if value > MAX_MONEY {
return Err(sapling::builder::Error::InvalidAmount);
}
self.sapling_builder
Expand All @@ -273,9 +272,9 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
&mut self,
to: &TransparentAddress,
asset_type: AssetType,
value: i64,
value: u64,
) -> Result<(), transparent::builder::Error> {
if value < 0 || value > MAX_MONEY {
if value > MAX_MONEY {
return Err(transparent::builder::Error::InvalidAmount);
}

Expand All @@ -293,13 +292,13 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
}

/// Returns the sum of the transparent, Sapling, and TZE value balances.
pub fn value_balance(&self) -> Result<Amount, BalanceError> {
pub fn value_balance(&self) -> Result<I128Sum, BalanceError> {
let value_balances = [
self.transparent_builder.value_balance()?,
self.sapling_builder.value_balance(),
];

Ok(value_balances.into_iter().sum::<Amount>())
Ok(value_balances.into_iter().sum::<I128Sum>())
}

/// Builds a transaction from the configured spends and outputs.
Expand All @@ -326,7 +325,7 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
fn build_internal<FE>(
self,
prover: &impl TxProver,
fee: Amount,
fee: U64Sum,
) -> Result<(Transaction, SaplingMetadata), Error<FE>> {
let consensus_branch_id = BranchId::for_height(&self.params, self.target_height);

Expand All @@ -338,9 +337,9 @@ impl<P: consensus::Parameters, R: RngCore> Builder<P, R> {
//

// After fees are accounted for, the value balance of the transaction must be zero.
let balance_after_fees = self.value_balance()? - fee;
let balance_after_fees = self.value_balance()? - I128Sum::from_sum(fee);

if balance_after_fees != Amount::zero() {
if balance_after_fees != ValueSum::zero() {
return Err(Error::InsufficientFunds(-balance_after_fees));
};

Expand Down Expand Up @@ -480,17 +479,16 @@ mod tests {
merkle_tree::{CommitmentTree, IncrementalWitness},
sapling::Rseed,
transaction::{
components::amount::{Amount, DEFAULT_FEE, MAX_MONEY},
sapling::builder::{self as build_s},
transparent::builder::{self as build_t},
components::amount::{I128Sum, ValueSum, DEFAULT_FEE},
sapling::builder as build_s,
TransparentAddress,
},
zip32::ExtendedSpendingKey,
};

use super::{Builder, Error};

#[test]
/*#[test]
fn fails_on_overflow_output() {
let extsk = ExtendedSpendingKey::master(&[]);
let dfvk = extsk.to_diversifiable_full_viewing_key();
Expand All @@ -507,12 +505,12 @@ mod tests {
Some(ovk),
to,
zec(),
MAX_MONEY as u64 + 1,
MAX_MONEY + 1,
MemoBytes::empty()
),
Err(build_s::Error::InvalidAmount)
);
}
}*/

/// Generate ZEC asset type
fn zec() -> AssetType {
Expand Down Expand Up @@ -565,21 +563,6 @@ mod tests {
);
}

#[test]
fn fails_on_negative_transparent_output() {
let mut rng = OsRng;

let transparent_address = TransparentAddress(rng.gen::<[u8; 20]>());
let tx_height = TEST_NETWORK
.activation_height(NetworkUpgrade::MASP)
.unwrap();
let mut builder = Builder::new(TEST_NETWORK, tx_height);
assert_eq!(
builder.add_transparent_output(&transparent_address, zec(), -1,),
Err(build_t::Error::InvalidAmount)
);
}

#[test]
fn fails_on_negative_change() {
let mut rng = OsRng;
Expand All @@ -597,7 +580,9 @@ mod tests {
let builder = Builder::new(TEST_NETWORK, tx_height);
assert_eq!(
builder.mock_build(),
Err(Error::InsufficientFunds(DEFAULT_FEE.clone()))
Err(Error::InsufficientFunds(I128Sum::from_sum(
DEFAULT_FEE.clone()
)))
);
}

Expand All @@ -615,7 +600,8 @@ mod tests {
assert_eq!(
builder.mock_build(),
Err(Error::InsufficientFunds(
Amount::from_pair(zec(), 50000).unwrap() + &*DEFAULT_FEE
I128Sum::from_pair(zec(), 50000).unwrap()
+ &I128Sum::from_sum(DEFAULT_FEE.clone())
))
);
}
Expand All @@ -630,7 +616,8 @@ mod tests {
assert_eq!(
builder.mock_build(),
Err(Error::InsufficientFunds(
Amount::from_pair(zec(), 50000).unwrap() + &*DEFAULT_FEE
I128Sum::from_pair(zec(), 50000).unwrap()
+ &I128Sum::from_sum(DEFAULT_FEE.clone())
))
);
}
Expand Down Expand Up @@ -663,7 +650,7 @@ mod tests {
assert_eq!(
builder.mock_build(),
Err(Error::InsufficientFunds(
Amount::from_pair(zec(), 1).unwrap()
ValueSum::from_pair(zec(), 1).unwrap()
))
);
}
Expand Down
4 changes: 3 additions & 1 deletion masp_primitives/src/transaction/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ pub mod amount;
pub mod sapling;
pub mod transparent;
pub use self::{
amount::Amount,
amount::{
I128Sum, I16Sum, I32Sum, I64Sum, I8Sum, U128Sum, U16Sum, U32Sum, U64Sum, U8Sum, ValueSum,
},
sapling::{ConvertDescription, OutputDescription, SpendDescription},
transparent::{TxIn, TxOut},
};
Expand Down
Loading

0 comments on commit e83521d

Please sign in to comment.