From 9cf0d556879883fbc6028bcb7e57af6fc787956e Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 27 Jan 2024 11:46:06 -0700 Subject: [PATCH] Move `Amount` and `NonNegativeAmount` types to the `zcash_protocol` crate. --- components/zcash_protocol/src/lib.rs | 1 + .../zcash_protocol/src/value.rs | 44 ++++--------------- zcash_client_backend/src/fees/sapling.rs | 4 +- zcash_client_backend/src/scanning.rs | 2 +- zcash_client_backend/src/wallet.rs | 4 +- zcash_client_sqlite/src/testing.rs | 10 +++-- .../init/migrations/receiving_key_scopes.rs | 2 +- zcash_client_sqlite/src/wallet/sapling.rs | 6 +-- zcash_primitives/Cargo.toml | 1 + .../src/transaction/components.rs | 2 +- 10 files changed, 29 insertions(+), 47 deletions(-) rename zcash_primitives/src/transaction/components/amount.rs => components/zcash_protocol/src/value.rs (93%) diff --git a/components/zcash_protocol/src/lib.rs b/components/zcash_protocol/src/lib.rs index 7a4c918ecb..a15d5e5881 100644 --- a/components/zcash_protocol/src/lib.rs +++ b/components/zcash_protocol/src/lib.rs @@ -17,3 +17,4 @@ pub mod consensus; pub mod constants; +pub mod value; diff --git a/zcash_primitives/src/transaction/components/amount.rs b/components/zcash_protocol/src/value.rs similarity index 93% rename from zcash_primitives/src/transaction/components/amount.rs rename to components/zcash_protocol/src/value.rs index 766368202c..b902c81460 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/components/zcash_protocol/src/value.rs @@ -4,9 +4,6 @@ use std::iter::Sum; use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign}; use memuse::DynamicUsage; -use orchard::value as orchard; - -use crate::sapling; pub const COIN: i64 = 1_0000_0000; pub const MAX_MONEY: i64 = 21_000_000 * COIN; @@ -235,14 +232,6 @@ impl Mul for Amount { } } -impl TryFrom for Amount { - type Error = (); - - fn try_from(v: orchard::ValueSum) -> Result { - i64::try_from(v).map_err(|_| ()).and_then(Amount::try_from) - } -} - /// A type-safe representation of some nonnegative amount of Zcash. /// /// A NonNegativeAmount can only be constructed from an integer that is within the valid monetary @@ -254,6 +243,11 @@ impl NonNegativeAmount { /// Returns the identity `NonNegativeAmount` pub const ZERO: Self = NonNegativeAmount(Amount(0)); + /// Returns this NonNegativeAmount as a u64. + pub fn into_u64(self) -> u64 { + self.0.try_into().unwrap() + } + /// Creates a NonNegativeAmount from a u64. /// /// Returns an error if the amount is outside the range `{0..MAX_MONEY}`. @@ -323,35 +317,15 @@ impl From<&NonNegativeAmount> for Amount { impl From for u64 { fn from(n: NonNegativeAmount) -> Self { - n.0.try_into().unwrap() - } -} - -impl From for sapling::value::NoteValue { - fn from(n: NonNegativeAmount) -> Self { - sapling::value::NoteValue::from_raw(n.into()) - } -} - -impl TryFrom for NonNegativeAmount { - type Error = (); - - fn try_from(value: sapling::value::NoteValue) -> Result { - Self::from_u64(value.inner()) - } -} - -impl From for orchard::NoteValue { - fn from(n: NonNegativeAmount) -> Self { - orchard::NoteValue::from_raw(n.into()) + n.into_u64() } } -impl TryFrom for NonNegativeAmount { +impl TryFrom for NonNegativeAmount { type Error = (); - fn try_from(value: orchard::NoteValue) -> Result { - Self::from_u64(value.inner()) + fn try_from(value: u64) -> Result { + NonNegativeAmount::from_u64(value) } } diff --git a/zcash_client_backend/src/fees/sapling.rs b/zcash_client_backend/src/fees/sapling.rs index 2653310a92..fa7ef6157e 100644 --- a/zcash_client_backend/src/fees/sapling.rs +++ b/zcash_client_backend/src/fees/sapling.rs @@ -67,7 +67,7 @@ impl InputView<()> for SpendInfo { } fn value(&self) -> NonNegativeAmount { - NonNegativeAmount::try_from(self.value()) + NonNegativeAmount::try_from(self.value().inner()) .expect("An existing note to be spent must have a valid amount value.") } } @@ -81,7 +81,7 @@ pub trait OutputView { impl OutputView for OutputInfo { fn value(&self) -> NonNegativeAmount { - NonNegativeAmount::try_from(self.value()) + NonNegativeAmount::try_from(self.value().inner()) .expect("Output values should be checked at construction.") } } diff --git a/zcash_client_backend/src/scanning.rs b/zcash_client_backend/src/scanning.rs index 429d4a336d..86325305f0 100644 --- a/zcash_client_backend/src/scanning.rs +++ b/zcash_client_backend/src/scanning.rs @@ -751,7 +751,7 @@ mod tests { // Create a fake Note for the account let mut rng = OsRng; let rseed = generate_random_rseed(zip212_enforcement, &mut rng); - let note = sapling::Note::from_parts(to, NoteValue::from(value), rseed); + let note = sapling::Note::from_parts(to, NoteValue::from_raw(value.into()), rseed); let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index 8cfb3a48d9..aaaee8ffb4 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -249,7 +249,7 @@ pub enum Note { impl Note { pub fn value(&self) -> NonNegativeAmount { match self { - Note::Sapling(n) => n.value().try_into().expect( + Note::Sapling(n) => n.value().inner().try_into().expect( "Sapling notes must have values in the range of valid non-negative ZEC values.", ), #[cfg(feature = "orchard")] @@ -349,6 +349,7 @@ impl sapling_fees::InputView for ReceivedNote NonNegativeAmount { self.note .value() + .inner() .try_into() .expect("Sapling note values are indirectly checked by consensus.") } @@ -363,6 +364,7 @@ impl orchard_fees::InputView for ReceivedNote NonNegativeAmount { self.note .value() + .inner() .try_into() .expect("Orchard note values are indirectly checked by consensus.") } diff --git a/zcash_client_sqlite/src/testing.rs b/zcash_client_sqlite/src/testing.rs index 82bbbb9c8d..2b6474664f 100644 --- a/zcash_client_sqlite/src/testing.rs +++ b/zcash_client_sqlite/src/testing.rs @@ -765,7 +765,9 @@ pub(crate) fn fake_compact_block( zip212_enforcement(params, height), &mut rng, ); - let note = Note::from_parts(to, NoteValue::from(value), rseed); + let note = Note::from_parts(to, + sapling::value::NoteValue::from_raw(value.into_u64()), + rseed); let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), @@ -874,7 +876,9 @@ pub(crate) fn fake_compact_block_spending( // Create a fake Note for the payment ctx.outputs.push({ - let note = Note::from_parts(to, NoteValue::from(value), rseed); + let note = Note::from_parts(to, + sapling::value::NoteValue::from_raw(value.into_u64()), + rseed); let encryptor = sapling_note_encryption( Some(dfvk.fvk().ovk), note.clone(), @@ -898,7 +902,7 @@ pub(crate) fn fake_compact_block_spending( let rseed = generate_random_rseed(zip212_enforcement, &mut rng); let note = Note::from_parts( change_addr, - NoteValue::from((in_value - value).unwrap()), + NoteValue::from_raw((in_value - value).unwrap().into_u64()), rseed, ); let encryptor = sapling_note_encryption( diff --git a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs index 28b24172c0..c9aca77afb 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs @@ -241,7 +241,7 @@ impl RusqliteMigration for Migration

{ &mut commitment_tree, dfvk, &diversifier, - ¬e_value.try_into().unwrap(), + &sapling::value::NoteValue::from_raw(note_value.into_u64()), &rseed, note_commitment_tree_position, )?; diff --git a/zcash_client_sqlite/src/wallet/sapling.rs b/zcash_client_sqlite/src/wallet/sapling.rs index 0eabe052c9..e7ad49be06 100644 --- a/zcash_client_sqlite/src/wallet/sapling.rs +++ b/zcash_client_sqlite/src/wallet/sapling.rs @@ -10,7 +10,7 @@ use zcash_primitives::{ consensus::{self, BlockHeight}, memo::MemoBytes, transaction::{ - components::{amount::NonNegativeAmount, Amount}, + components::Amount, TxId, }, zip32::{AccountId, Scope}, @@ -116,7 +116,7 @@ fn to_spendable_note( Diversifier(tmp) }; - let note_value = NonNegativeAmount::from_nonnegative_i64(row.get(4)?).map_err(|_e| { + let note_value: u64 = row.get::<_, i64>(4)?.try_into().map_err(|_e| { SqliteClientError::CorruptedData("Note values must be nonnegative".to_string()) })?; @@ -165,7 +165,7 @@ fn to_spendable_note( output_index, Note::Sapling(sapling::Note::from_parts( recipient, - note_value.into(), + sapling::value::NoteValue::from_raw(note_value), rseed, )), spending_key_scope, diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index aaf70cb200..f409c1a633 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -118,6 +118,7 @@ temporary-zcashd = [] ## Exposes APIs that are useful for testing, such as `proptest` strategies. test-dependencies = [ "dep:proptest", + "zcash_protocol/test-dependencies", "orchard/test-dependencies", "sapling/test-dependencies", ] diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 24dfd724b5..f5a530cfe3 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,6 +1,6 @@ //! Structs representing the components within Zcash transactions. -pub mod amount; +pub use zcash_protocol::value as amount; pub mod orchard; pub mod sapling; pub mod sprout;