diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d60ce8b3..357391b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,6 +134,6 @@ jobs: - name: Add target run: rustup toolchain install 1.81.0-x86_64-unknown-linux-gnu - name: Install cargo-audit - run: cargo install cargo-audit + run: cargo install cargo-audit --locked - name: Cargo Audit run: cargo audit diff --git a/Cargo.lock b/Cargo.lock index 8be7ee79..6e943812 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -519,9 +519,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] diff --git a/masp_primitives/src/transaction/components/amount.rs b/masp_primitives/src/transaction/components/amount.rs index 5c4b1837..573cf111 100644 --- a/masp_primitives/src/transaction/components/amount.rs +++ b/masp_primitives/src/transaction/components/amount.rs @@ -4,7 +4,7 @@ use borsh::schema::Fields; use borsh::schema::{Declaration, Definition}; use borsh::BorshSchema; use borsh::{BorshDeserialize, BorshSerialize}; -use num_traits::{CheckedAdd, CheckedMul, CheckedNeg, CheckedSub, One}; +use num_traits::{CheckedAdd, CheckedMul, CheckedNeg, CheckedSub, ConstZero, One, Zero}; use std::cmp::Ordering; use std::collections::btree_map::Keys; use std::collections::btree_map::{IntoIter, Iter}; @@ -78,13 +78,13 @@ where impl ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + PartialOrd, + Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + PartialOrd, { /// Creates a non-negative ValueSum from a Value. pub fn from_nonnegative(atype: Unit, amount: Value) -> Result { - if amount == Value::default() { + if amount.is_zero() { Ok(Self::zero()) - } else if Value::default() <= amount { + } else if Value::zero() <= amount { let mut ret = BTreeMap::new(); ret.insert(atype, amount); Ok(ValueSum(ret)) @@ -92,16 +92,44 @@ where Err(()) } } + + /// Compute the infimum of two ValueSums + pub fn inf(&self, rhs: &Self) -> Self { + let mut comps = BTreeMap::new(); + for (atype, rhs_amount) in rhs.components() { + let lhs_amount = self.get(atype); + if lhs_amount <= *rhs_amount && !lhs_amount.is_zero() { + comps.insert(atype.clone(), lhs_amount); + } else if lhs_amount > *rhs_amount && !rhs_amount.is_zero() { + comps.insert(atype.clone(), *rhs_amount); + } + } + ValueSum(comps) + } + + /// Compute the supremum of two ValueSums + pub fn sup(&self, rhs: &Self) -> Self { + let mut comps = BTreeMap::new(); + for (atype, rhs_amount) in rhs.components() { + let lhs_amount = self.get(atype); + if lhs_amount <= *rhs_amount && !rhs_amount.is_zero() { + comps.insert(atype.clone(), *rhs_amount); + } else if lhs_amount > *rhs_amount && !lhs_amount.is_zero() { + comps.insert(atype.clone(), lhs_amount); + } + } + ValueSum(comps) + } } impl ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { /// Creates an ValueSum from a Value. pub fn from_pair(atype: Unit, amount: Value) -> Self { - if amount == Value::default() { + if amount.is_zero() { Self::zero() } else { let mut ret = BTreeMap::new(); @@ -112,13 +140,13 @@ where /// Filters out everything but the given AssetType from this ValueSum pub fn project(&self, index: Unit) -> Self { - let val = self.0.get(&index).copied().unwrap_or_default(); + let val = self.0.get(&index).copied().unwrap_or(Value::zero()); Self::from_pair(index, val) } /// Get the given AssetType within this ValueSum pub fn get(&self, index: &Unit) -> Value { - *self.0.get(index).unwrap_or(&Value::default()) + *self.0.get(index).unwrap_or(&Value::zero()) } } @@ -160,6 +188,20 @@ where } } +impl Zero for ValueSum +where + Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, + Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy, +{ + fn zero() -> Self { + Self(BTreeMap::new()) + } + + fn is_zero(&self) -> bool { + self.0.is_empty() + } +} + impl BorshSerialize for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, @@ -343,12 +385,12 @@ where impl PartialOrd for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + PartialOrd, + Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + PartialOrd, { /// One ValueSum is more than or equal to another if each corresponding /// coordinate is more than or equal to the other's. fn partial_cmp(&self, other: &Self) -> Option { - let zero = Value::default(); + let zero = Value::zero(); let mut ordering = Some(Ordering::Equal); for k in self.0.keys().chain(other.0.keys()) { let v1 = self.0.get(k).unwrap_or(&zero); @@ -387,7 +429,9 @@ macro_rules! impl_index { type Output = $struct_type; /// Query how much of the given asset this amount contains fn index(&self, index: &Unit) -> &Self::Output { - self.0.get(index).unwrap_or(&0) + self.0 + .get(index) + .unwrap_or(&<$struct_type as ConstZero>::ZERO) } } }; @@ -421,44 +465,44 @@ where + PartialEq + Eq + Copy - + Default + + Zero + CheckedMul, Rhs: Copy, { fn mul_assign(&mut self, rhs: Rhs) { - *self = self.clone() * rhs; + *self = self.clone() * &rhs; } } -impl Mul for ValueSum +impl Mul<&Rhs> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedMul, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedMul, Rhs: Copy, - >::Output: Default + BorshSerialize + BorshDeserialize + Eq, + >::Output: Zero + BorshSerialize + BorshDeserialize + Eq, { type Output = ValueSum>::Output>; - fn mul(self, rhs: Rhs) -> Self::Output { + fn mul(self, rhs: &Rhs) -> Self::Output { self.checked_mul(rhs).expect("overflow detected") } } -impl CheckedMul for ValueSum +impl CheckedMul<&Rhs> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedMul, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedMul, Rhs: Copy, - >::Output: Default + BorshSerialize + BorshDeserialize + Eq, + >::Output: Zero + BorshSerialize + BorshDeserialize + Eq, { type Output = ValueSum>::Output>; - fn checked_mul(self, rhs: Rhs) -> Option { + fn checked_mul(self, rhs: &Rhs) -> Option { let mut comps = BTreeMap::new(); for (atype, amount) in self.0.iter() { - comps.insert(atype.clone(), amount.checked_mul(rhs)?); + comps.insert(atype.clone(), amount.checked_mul(*rhs)?); } - comps.retain(|_, v| *v != >::Output::default()); + comps.retain(|_, v| *v != >::Output::zero()); Some(ValueSum(comps)) } } @@ -471,9 +515,9 @@ where + PartialEq + Eq + Copy - + Default + + Zero + CheckedAdd, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { fn add_assign(&mut self, rhs: &ValueSum) { *self = self.clone() + rhs; @@ -488,9 +532,9 @@ where + PartialEq + Eq + Copy - + Default + + Zero + CheckedAdd, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { fn add_assign(&mut self, rhs: ValueSum) { *self += &rhs @@ -500,9 +544,9 @@ where impl Add<&ValueSum> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedAdd, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedAdd, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; @@ -514,9 +558,9 @@ where impl Add> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedAdd, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedAdd, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; @@ -528,21 +572,21 @@ where impl CheckedAdd<&ValueSum> for &ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedAdd, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedAdd, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; fn checked_add(self, v: &ValueSum) -> Option { let mut comps = BTreeMap::new(); for (atype, amount) in self.components() { - comps.insert(atype.clone(), amount.checked_add(Rhs::default())?); + comps.insert(atype.clone(), amount.checked_add(Rhs::zero())?); } for (atype, amount) in v.components() { comps.insert(atype.clone(), self.get(atype).checked_add(*amount)?); } - comps.retain(|_, v| *v != >::Output::default()); + comps.retain(|_, v| *v != >::Output::zero()); Some(ValueSum(comps)) } } @@ -555,9 +599,9 @@ where + PartialEq + Eq + Copy - + Default + + Zero + CheckedSub, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { fn sub_assign(&mut self, rhs: &ValueSum) { *self = self.clone() - rhs @@ -572,9 +616,9 @@ where + PartialEq + Eq + Copy - + Default + + Zero + CheckedSub, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { fn sub_assign(&mut self, rhs: ValueSum) { *self -= &rhs @@ -584,37 +628,42 @@ where impl Neg for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Value: BorshSerialize - + BorshDeserialize - + PartialEq - + Eq - + Copy - + Default - + PartialOrd - + CheckedNeg, - ::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Value: + BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + PartialOrd + CheckedNeg, + ::Output: BorshSerialize + BorshDeserialize + Eq + Zero, +{ + type Output = ValueSum::Output>; + + fn neg(self) -> Self::Output { + self.checked_neg().expect("overflow detected") + } +} + +impl CheckedNeg for ValueSum +where + Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, + Value: + BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + PartialOrd + CheckedNeg, + ::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum::Output>; - fn neg(mut self) -> Self::Output { + fn checked_neg(mut self) -> Option { let mut comps = BTreeMap::new(); for (atype, amount) in self.0.iter_mut() { - comps.insert( - atype.clone(), - amount.checked_neg().expect("overflow detected"), - ); + comps.insert(atype.clone(), amount.checked_neg()?); } - comps.retain(|_, v| *v != ::Output::default()); - ValueSum(comps) + comps.retain(|_, v| *v != ::Output::zero()); + Some(ValueSum(comps)) } } impl Sub<&ValueSum> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedSub, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedSub, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; @@ -626,9 +675,9 @@ where impl Sub> for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedSub, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedSub, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; @@ -640,21 +689,21 @@ where impl CheckedSub<&ValueSum> for &ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + CheckedSub, - Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, - >::Output: BorshSerialize + BorshDeserialize + Eq + Default, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedSub, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: BorshSerialize + BorshDeserialize + Eq + Zero, { type Output = ValueSum>::Output>; fn checked_sub(self, v: &ValueSum) -> Option { let mut comps = BTreeMap::new(); for (atype, amount) in self.components() { - comps.insert(atype.clone(), amount.checked_sub(Rhs::default())?); + comps.insert(atype.clone(), amount.checked_sub(Rhs::zero())?); } for (atype, amount) in v.components() { comps.insert(atype.clone(), self.get(atype).checked_sub(*amount)?); } - comps.retain(|_, v| *v != >::Output::default()); + comps.retain(|_, v| *v != >::Output::zero()); Some(ValueSum(comps)) } } @@ -662,7 +711,7 @@ where impl Sum for ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default + PartialOrd, + Value: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + PartialOrd, Self: Add, { fn sum>(iter: I) -> Self { @@ -673,7 +722,7 @@ where impl ValueSum where Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, - Output: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Default, + Output: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, { pub fn try_from_sum( x: ValueSum, @@ -686,7 +735,7 @@ where for (atype, amount) in x.0 { comps.insert(atype, amount.try_into()?); } - comps.retain(|_, v| *v != Output::default()); + comps.retain(|_, v| *v != Output::zero()); Ok(Self(comps)) } @@ -699,11 +748,69 @@ where for (atype, amount) in x.0 { comps.insert(atype, amount.into()); } - comps.retain(|_, v| *v != Output::default()); + comps.retain(|_, v| *v != Output::zero()); Self(comps) } } +impl CheckedMul<&ValueSum> for ValueSum +where + Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedMul, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: Zero + + BorshSerialize + + BorshDeserialize + + Eq + + CheckedAdd>::Output>, +{ + type Output = >::Output; + + fn checked_mul(self, rhs: &ValueSum) -> Option { + let mut product = Self::Output::zero(); + for (atype, amount) in rhs.components() { + product = product.checked_add(self.get(atype).checked_mul(*amount)?)?; + } + Some(product) + } +} + +impl Mul<&ValueSum> for ValueSum +where + Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedMul, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: Zero + + BorshSerialize + + BorshDeserialize + + Eq + + CheckedAdd>::Output>, +{ + type Output = >::Output; + + fn mul(self, rhs: &ValueSum) -> Self::Output { + self.checked_mul(rhs).expect("overflow detected") + } +} + +impl Mul> for ValueSum +where + Unit: Hash + Ord + BorshSerialize + BorshDeserialize + Clone, + Lhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero + CheckedMul, + Rhs: BorshSerialize + BorshDeserialize + PartialEq + Eq + Copy + Zero, + >::Output: Zero + + BorshSerialize + + BorshDeserialize + + Eq + + CheckedAdd>::Output>, +{ + type Output = >::Output; + + fn mul(self, rhs: ValueSum) -> Self::Output { + self * &rhs + } +} + /// A type for balance violations in amount addition and subtraction /// (overflow and underflow of allowed ranges) #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/masp_primitives/src/transaction/components/sapling/builder.rs b/masp_primitives/src/transaction/components/sapling/builder.rs index e626493e..76d9ee46 100644 --- a/masp_primitives/src/transaction/components/sapling/builder.rs +++ b/masp_primitives/src/transaction/components/sapling/builder.rs @@ -853,7 +853,7 @@ impl< } let allowed_amt: I128Sum = allowed.clone().into(); - self.value_balance += I128Sum::from_sum(allowed_amt) * (value as i128); + self.value_balance += I128Sum::from_sum(allowed_amt) * &(value as i128); self.converts.push(ConvertDescriptionInfo { allowed,