diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcb04b345..e5ae3aa9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,12 +52,12 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update ${{ matrix.channel }} && rustup default ${{ matrix.channel }} && rustup component add clippy - - run: cargo install cargo-hakari + - run: cargo install cargo-hakari --locked - run: cargo hakari init workspace-hack --yes - run: cargo hakari generate - run: cargo hakari manage-deps --yes - run: cargo hakari verify - - run: cargo install cargo-hack + - run: cargo install cargo-hack --locked - run: cargo hack clippy --workspace --feature-powerset - run: cargo hack clippy --workspace --feature-powerset --bins - run: cargo hack clippy --workspace --feature-powerset --examples @@ -79,7 +79,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update ${{ matrix.channel }} && rustup default ${{ matrix.channel }} - - run: cargo install cargo-nextest + - run: cargo install cargo-nextest --locked - run: cargo nextest run --workspace --release --all-features compile-bench: name: Compile Benchmarks (${{ matrix.os }} + ${{ matrix.channel }}) diff --git a/CHANGELOG.md b/CHANGELOG.md index d81285ec8..edf94f61d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Fixed - [\#296](https://github.com/Manta-Network/manta-rs/pull/296) Fix AssetMetadata display for values less than 1 +- [\#294](https://github.com/Manta-Network/manta-rs/pull/294) Distinguish between panic-errors and possible-fix-errors ### Security @@ -24,7 +25,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed - [\#283](https://github.com/Manta-Network/manta-rs/pull/283) Upgrade asset system. -- [\#284](https://github.com/Manta-Network/manta-rs/pull/284) Moved `R1CS` implementation to `manta-crypto` +- [\#284](https://github.com/Manta-Network/manta-rs/pull/284) Moved `R1CS` implementation to `manta-crypto` - [\#282](https://github.com/Manta-Network/manta-rs/pull/282) Upgrade key system. ## [0.5.7] - 2022-11-04 @@ -53,7 +54,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - [\#197](https://github.com/Manta-Network/manta-rs/pull/197) Add ECLAIR utilities for next circuit upgrade - [\#196](https://github.com/Manta-Network/manta-rs/pull/172) Add fixed base scalar multiplication using precomputed bases - [\#193](https://github.com/Manta-Network/manta-rs/pull/193) Add Bn254 curve backend for Groth16 trusted setup -- [\#172](https://github.com/Manta-Network/manta-rs/pull/172) Add abstract Phase 2 for Groth16 trusted setup +- [\#172](https://github.com/Manta-Network/manta-rs/pull/172) Add abstract Phase 2 for Groth16 trusted setup ### Changed - [\#247](https://github.com/Manta-Network/manta-rs/pull/247) Moved BLS12-381 and BN254 curves (and Edwards counterparts) to `manta-crypto` diff --git a/manta-accounting/src/transfer/mod.rs b/manta-accounting/src/transfer/mod.rs index 03aa97bf2..d238f4e9c 100644 --- a/manta-accounting/src/transfer/mod.rs +++ b/manta-accounting/src/transfer/mod.rs @@ -970,19 +970,13 @@ where asset_id: has_public_participants(SOURCES, SINKS) .then(|| compiler.allocate_unknown::()), sources: (0..SOURCES) - .into_iter() .map(|_| compiler.allocate_unknown::()) .collect(), - senders: (0..SENDERS) - .into_iter() - .map(|_| compiler.allocate_unknown()) - .collect(), + senders: (0..SENDERS).map(|_| compiler.allocate_unknown()).collect(), receivers: (0..RECEIVERS) - .into_iter() .map(|_| compiler.allocate_unknown()) .collect(), sinks: (0..SINKS) - .into_iter() .map(|_| compiler.allocate_unknown::()) .collect(), } @@ -1052,13 +1046,6 @@ where /// Ledger Event type Event; - /// State Update Error - /// - /// This error type is used if the ledger can fail when updating the public state. The - /// [`update_public_balances`](Self::update_public_balances) method uses this error type to - /// track this condition. - type UpdateError; - /// Valid [`AssetValue`](Configuration::AssetValue) for [`TransferPost`] Source /// /// # Safety @@ -1086,6 +1073,19 @@ where /// [`check_sink_accounts`](Self::check_sink_accounts) and [`is_valid`](Self::is_valid). type ValidProof: Copy; + /// Error Type + type Error: From<>>::Error> + + From<>>::Error> + + Into< + TransferPostError< + C, + Self::AccountId, + >>::Error, + >>::Error, + >::Error, + >, + >; + /// Checks that the balances associated to the source accounts are sufficient to withdraw the /// amount given in `sources`. fn check_source_accounts( @@ -1109,7 +1109,7 @@ where fn is_valid( &self, posting_key: TransferPostingKeyRef, - ) -> Option<(Self::ValidProof, Self::Event)>; + ) -> Result<(Self::ValidProof, Self::Event), >::Error>; /// Updates the public balances in the ledger, finishing the transaction. /// @@ -1125,7 +1125,7 @@ where sources: Vec>, sinks: Vec>, proof: Self::ValidProof, - ) -> Result<(), Self::UpdateError>; + ) -> Result<(), >::Error>; } /// Transfer Source Posting Key Type @@ -1225,6 +1225,15 @@ where pub deposit: C::AssetValue, } +/// Transfer Ledger Post Error +pub type TransferLedgerPostError = TransferPostError< + C, + >::AccountId, + >>::Error, + >>::Error, + >::Error, +>; + /// Transfer Post Error /// /// This `enum` is the error state of the [`TransferPost::validate`] method. See its documentation @@ -1236,12 +1245,16 @@ where bound( deserialize = r" AccountId: Deserialize<'de>, - UpdateError: Deserialize<'de>, + SenderError: Deserialize<'de>, + ReceiverError: Deserialize<'de>, + Error: Deserialize<'de>, C::AssetId: Deserialize<'de>, C::AssetValue: Deserialize<'de>", serialize = r" AccountId: Serialize, - UpdateError: Serialize, + SenderError: Serialize, + ReceiverError: Serialize, + Error: Serialize, C::AssetId: Serialize, C::AssetValue: Serialize", ), @@ -1251,16 +1264,26 @@ where )] #[derive(derivative::Derivative)] #[derivative( - Clone(bound = "AccountId: Clone, UpdateError: Clone, C::AssetId: Clone, C::AssetValue: Clone"), - Copy(bound = "AccountId: Copy, UpdateError: Copy, C::AssetId: Copy, C::AssetValue: Copy"), - Debug(bound = "AccountId: Debug, UpdateError: Debug, C::AssetId: Debug, C::AssetValue: Debug"), - Eq(bound = "AccountId: Eq, UpdateError: Eq, C::AssetId: Eq, C::AssetValue: Eq"), - Hash(bound = "AccountId: Hash, UpdateError: Hash, C::AssetId: Hash, C::AssetValue: Hash"), + Clone( + bound = "AccountId: Clone, SenderError: Clone, ReceiverError: Clone, Error: Clone, C::AssetId: Clone, C::AssetValue: Clone" + ), + Copy( + bound = "AccountId: Copy, SenderError: Copy, ReceiverError: Copy, Error: Copy, C::AssetId: Copy, C::AssetValue: Copy" + ), + Debug( + bound = "AccountId: Debug, SenderError: Debug, ReceiverError: Debug, Error: Debug, C::AssetId: Debug, C::AssetValue: Debug" + ), + Eq( + bound = "AccountId: Eq, SenderError: Eq, ReceiverError: Eq, Error: Eq, C::AssetId: Eq, C::AssetValue: Eq" + ), + Hash( + bound = "AccountId: Hash, SenderError: Hash, ReceiverError: Hash, Error: Hash, C::AssetId: Hash, C::AssetValue: Hash" + ), PartialEq( - bound = "AccountId: PartialEq, UpdateError: PartialEq, C::AssetId: PartialEq, C::AssetValue: PartialEq" + bound = "AccountId: PartialEq, SenderError: PartialEq, ReceiverError: PartialEq, Error: PartialEq, C::AssetId: PartialEq, C::AssetValue: PartialEq" ) )] -pub enum TransferPostError +pub enum TransferPostError where C: Configuration + ?Sized, { @@ -1279,10 +1302,10 @@ where InvalidSinkAccount(InvalidSinkAccount), /// Sender Post Error - Sender(SenderPostError), + Sender(SenderPostError), /// Receiver Post Error - Receiver(ReceiverPostError), + Receiver(ReceiverPostError), /// Duplicate Spend Error DuplicateSpend, @@ -1295,14 +1318,14 @@ where /// Validity of the transfer could not be proved by the ledger. InvalidProof, - /// Update Error + /// Unexpected Error /// - /// An error occured while updating the ledger state. - UpdateError(UpdateError), + /// An unexpected error occured. + UnexpectedError(Error), } -impl From - for TransferPostError +impl From + for TransferPostError where C: Configuration + ?Sized, { @@ -1312,8 +1335,8 @@ where } } -impl From> - for TransferPostError +impl From> + for TransferPostError where C: Configuration + ?Sized, { @@ -1323,8 +1346,8 @@ where } } -impl From> - for TransferPostError +impl From> + for TransferPostError where C: Configuration + ?Sized, { @@ -1334,24 +1357,24 @@ where } } -impl From - for TransferPostError +impl From> + for TransferPostError where C: Configuration + ?Sized, { #[inline] - fn from(err: SenderPostError) -> Self { + fn from(err: SenderPostError) -> Self { Self::Sender(err) } } -impl From - for TransferPostError +impl From> + for TransferPostError where C: Configuration + ?Sized, { #[inline] - fn from(err: ReceiverPostError) -> Self { + fn from(err: ReceiverPostError) -> Self { Self::Receiver(err) } } @@ -1683,10 +1706,7 @@ where sink_accounts: Vec, sink_values: Vec, ledger: &L, - ) -> Result< - (Vec, Vec), - TransferPostError, - > + ) -> Result<(Vec, Vec), TransferLedgerPostError> where L: TransferLedger, { @@ -1729,7 +1749,7 @@ where ledger: &L, source_accounts: Vec, sink_accounts: Vec, - ) -> Result, TransferPostError> + ) -> Result, TransferLedgerPostError> where L: TransferLedger, { @@ -1762,18 +1782,17 @@ where .into_iter() .map(move |r| r.validate(ledger)) .collect::, _>>()?; - let (proof, event) = match ledger.is_valid(TransferPostingKeyRef { - authorization_key: &self.authorization_signature.map(|s| s.authorization_key), - asset_id: &self.body.asset_id, - sources: &source_posting_keys, - senders: &sender_posting_keys, - receivers: &receiver_posting_keys, - sinks: &sink_posting_keys, - proof: self.body.proof, - }) { - Some((proof, event)) => (proof, event), - _ => return Err(TransferPostError::InvalidProof), - }; + let (proof, event) = ledger + .is_valid(TransferPostingKeyRef { + authorization_key: &self.authorization_signature.map(|s| s.authorization_key), + asset_id: &self.body.asset_id, + sources: &source_posting_keys, + senders: &sender_posting_keys, + receivers: &receiver_posting_keys, + sinks: &sink_posting_keys, + proof: self.body.proof, + }) + .map_err(|x| x.into())?; Ok(TransferPostingKey { asset_id: self.body.asset_id, source_posting_keys, @@ -1795,13 +1814,13 @@ where super_key: &TransferLedgerSuperPostingKey, source_accounts: Vec, sink_accounts: Vec, - ) -> Result> + ) -> Result> where L: TransferLedger, { self.validate(parameters, ledger, source_accounts, sink_accounts)? .post(ledger, super_key) - .map_err(TransferPostError::UpdateError) + .map_err(TransferPostError::UnexpectedError) } } @@ -1957,14 +1976,14 @@ where self, ledger: &mut L, super_key: &TransferLedgerSuperPostingKey, - ) -> Result { + ) -> Result>::Error> { let proof = self.proof; - SenderPostingKey::::post_all(self.sender_posting_keys, ledger, &(proof, *super_key)); + SenderPostingKey::::post_all(self.sender_posting_keys, ledger, &(proof, *super_key))?; ReceiverPostingKey::::post_all( self.receiver_posting_keys, ledger, &(proof, *super_key), - ); + )?; if let Some(asset_id) = self.asset_id { ledger.update_public_balances( super_key, diff --git a/manta-accounting/src/transfer/receiver.rs b/manta-accounting/src/transfer/receiver.rs index 44f85c65d..edb3b2557 100644 --- a/manta-accounting/src/transfer/receiver.rs +++ b/manta-accounting/src/transfer/receiver.rs @@ -203,10 +203,16 @@ where /// [`Utxo`]: crate::transfer::utxo::UtxoType::Utxo type ValidUtxo: AsRef; + /// Error Type + /// + /// This error describes situations in which ledger invariants have been broken but the system + /// must be able to handle them gracefully instead of crashing. + type Error: Into>; + /// Checks if the ledger already contains the `utxo` in its set of UTXOs. /// /// Existence of such a UTXO could indicate a possible double-spend. - fn is_not_registered(&self, utxo: M::Utxo) -> Option; + fn is_not_registered(&self, utxo: M::Utxo) -> Result; /// Posts the `utxo` and `note` to the ledger, registering the asset. /// @@ -229,7 +235,7 @@ where super_key: &Self::SuperPostingKey, utxo: Self::ValidUtxo, note: M::Note, - ) { + ) -> Result<(), Self::Error> { self.register_all(super_key, iter::once((utxo, note))) } @@ -251,13 +257,18 @@ where /// [`register`]: Self::register /// [`register_all`]: Self::register_all #[inline] - fn register_all(&mut self, super_key: &Self::SuperPostingKey, iter: I) + fn register_all( + &mut self, + super_key: &Self::SuperPostingKey, + iter: I, + ) -> Result<(), Self::Error> where I: IntoIterator, { for (utxo, note) in iter { - self.register(super_key, utxo, note) + self.register(super_key, utxo, note)?; } + Ok(()) } } @@ -265,15 +276,25 @@ where #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), - serde(crate = "manta_util::serde", deny_unknown_fields) + serde( + bound( + deserialize = "Error: Deserialize<'de>", + serialize = "Error: Serialize" + ), + crate = "manta_util::serde", + deny_unknown_fields + ) )] -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub enum ReceiverPostError { +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ReceiverPostError { /// Asset Registered Error /// /// The asset has already been registered with the ledger. - #[default] AssetRegistered, + + /// Unexpected Error + UnexpectedError(Error), } /// Receiver Post @@ -330,14 +351,15 @@ where /// Validates `self` on the receiver `ledger`. #[inline] - pub fn validate(self, ledger: &L) -> Result, ReceiverPostError> + pub fn validate( + self, + ledger: &L, + ) -> Result, ReceiverPostError> where L: ReceiverLedger, { Ok(ReceiverPostingKey { - utxo: ledger - .is_not_registered(self.utxo) - .ok_or(ReceiverPostError::AssetRegistered)?, + utxo: ledger.is_not_registered(self.utxo).map_err(|x| x.into())?, note: self.note, }) } @@ -414,13 +436,17 @@ where { /// Posts `self` to the receiver `ledger`. #[inline] - pub fn post(self, ledger: &mut L, super_key: &L::SuperPostingKey) { - ledger.register(super_key, self.utxo, self.note); + pub fn post(self, ledger: &mut L, super_key: &L::SuperPostingKey) -> Result<(), L::Error> { + ledger.register(super_key, self.utxo, self.note) } /// Posts all the of the [`ReceiverPostingKey`]s in `iter` to the receiver `ledger`. #[inline] - pub fn post_all(iter: I, ledger: &mut L, super_key: &L::SuperPostingKey) + pub fn post_all( + iter: I, + ledger: &mut L, + super_key: &L::SuperPostingKey, + ) -> Result<(), L::Error> where I: IntoIterator, { diff --git a/manta-accounting/src/transfer/sender.rs b/manta-accounting/src/transfer/sender.rs index 44a04ff44..9a741e39c 100644 --- a/manta-accounting/src/transfer/sender.rs +++ b/manta-accounting/src/transfer/sender.rs @@ -41,12 +41,12 @@ use manta_util::serde::{Deserialize, Serialize}; serde( bound( deserialize = r" - S::Secret: Deserialize<'de>, - S::Utxo: Deserialize<'de>, + S::Secret: Deserialize<'de>, + S::Utxo: Deserialize<'de>, S::Nullifier: Deserialize<'de>", serialize = r" - S::Secret: Serialize, - S::Utxo: Serialize, + S::Secret: Serialize, + S::Utxo: Serialize, S::Nullifier: Serialize", ), crate = "manta_util::serde", @@ -253,14 +253,14 @@ where serde( bound( deserialize = r" - S::Secret: Deserialize<'de>, - S::Utxo: Deserialize<'de>, - UtxoMembershipProof: Deserialize<'de>, + S::Secret: Deserialize<'de>, + S::Utxo: Deserialize<'de>, + UtxoMembershipProof: Deserialize<'de>, S::Nullifier: Deserialize<'de>", serialize = r" - S::Secret: Serialize, - S::Utxo: Serialize, - UtxoMembershipProof: Serialize, + S::Secret: Serialize, + S::Utxo: Serialize, + UtxoMembershipProof: Serialize, S::Nullifier: Serialize", ), crate = "manta_util::serde", @@ -270,39 +270,39 @@ where #[derive(derivative::Derivative)] #[derivative( Clone(bound = r" - S::Secret: Clone, - S::Utxo: Clone, - UtxoMembershipProof: Clone, + S::Secret: Clone, + S::Utxo: Clone, + UtxoMembershipProof: Clone, S::Nullifier: Clone"), Copy(bound = r" - S::Secret: Copy, - S::Utxo: Copy, - UtxoMembershipProof: Copy, + S::Secret: Copy, + S::Utxo: Copy, + UtxoMembershipProof: Copy, S::Nullifier: Copy"), Debug(bound = r" S::Secret: Debug, - S::Utxo: Debug, - UtxoMembershipProof: Debug, + S::Utxo: Debug, + UtxoMembershipProof: Debug, S::Nullifier: Debug"), Default(bound = r" S::Secret: Default, - S::Utxo: Default, - UtxoMembershipProof: Default, + S::Utxo: Default, + UtxoMembershipProof: Default, S::Nullifier: Default"), Eq(bound = r" S::Secret: Eq, - S::Utxo: Eq, - UtxoMembershipProof: Eq, + S::Utxo: Eq, + UtxoMembershipProof: Eq, S::Nullifier: Eq"), Hash(bound = r" S::Secret: Hash, - S::Utxo: Hash, - UtxoMembershipProof: Hash, + S::Utxo: Hash, + UtxoMembershipProof: Hash, S::Nullifier: Hash"), PartialEq(bound = r" S::Secret: PartialEq, - S::Utxo: PartialEq, - UtxoMembershipProof: PartialEq, + S::Utxo: PartialEq, + UtxoMembershipProof: PartialEq, S::Nullifier: PartialEq") )] pub struct Sender @@ -478,11 +478,17 @@ where /// [`has_matching_utxo_accumulator_output`]: Self::has_matching_utxo_accumulator_output type ValidNullifier: AsRef; + /// Error Type + /// + /// This error describes situations in which ledger invariants have been broken but the system + /// must be able to handle them gracefully instead of crashing. + type Error: Into>; + /// Checks if the ledger already contains the `nullifier` in its set of nullifiers. /// /// Existence of such a nullifier could indicate a possible double-spend and so the ledger does /// not accept duplicates. - fn is_unspent(&self, nullifier: S::Nullifier) -> Option; + fn is_unspent(&self, nullifier: S::Nullifier) -> Result; /// Checks if `output` matches the current accumulated value of the UTXO accumulator that is /// stored on the ledger. @@ -492,7 +498,7 @@ where fn has_matching_utxo_accumulator_output( &self, output: UtxoAccumulatorOutput, - ) -> Option; + ) -> Result; /// Posts the `nullifier` to the ledger, spending the asset. /// @@ -515,7 +521,7 @@ where super_key: &Self::SuperPostingKey, utxo_accumulator_output: Self::ValidUtxoAccumulatorOutput, nullifier: Self::ValidNullifier, - ) { + ) -> Result<(), Self::Error> { self.spend_all(super_key, iter::once((utxo_accumulator_output, nullifier))) } @@ -536,13 +542,18 @@ where /// [`spend`]: Self::spend /// [`spend_all`]: Self::spend_all #[inline] - fn spend_all(&mut self, super_key: &Self::SuperPostingKey, iter: I) + fn spend_all( + &mut self, + super_key: &Self::SuperPostingKey, + iter: I, + ) -> Result<(), Self::Error> where I: IntoIterator, { for (utxo_accumulator_output, nullifier) in iter { - self.spend(super_key, utxo_accumulator_output, nullifier) + self.spend(super_key, utxo_accumulator_output, nullifier)?; } + Ok(()) } } @@ -550,10 +561,25 @@ where #[cfg_attr( feature = "serde", derive(Deserialize, Serialize), - serde(crate = "manta_util::serde", deny_unknown_fields) + serde( + bound( + deserialize = "Error: Deserialize<'de>", + serialize = "Error: Serialize" + ), + crate = "manta_util::serde", + deny_unknown_fields + ) +)] +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = "Error: Clone"), + Copy(bound = "Error: Copy"), + Debug(bound = "Error: Debug"), + Eq(bound = "Error: Eq"), + Hash(bound = "Error: Hash"), + PartialEq(bound = "Error: PartialEq") )] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SenderPostError { +pub enum SenderPostError { /// Invalid UTXO Accumulator Output Error /// /// The sender was not constructed under the current state of the UTXO accumulator. @@ -563,6 +589,9 @@ pub enum SenderPostError { /// /// The asset has already been spent. AssetSpent, + + /// Unexpected Error + UnexpectedError(Error), } /// Sender Post @@ -581,10 +610,10 @@ pub enum SenderPostError { serde( bound( deserialize = r" - UtxoAccumulatorOutput: Deserialize<'de>, + UtxoAccumulatorOutput: Deserialize<'de>, S::Nullifier: Deserialize<'de>", serialize = r" - UtxoAccumulatorOutput: Serialize, + UtxoAccumulatorOutput: Serialize, S::Nullifier: Serialize", ), crate = "manta_util::serde", @@ -626,17 +655,18 @@ where /// Validates `self` on the sender `ledger`. #[inline] - pub fn validate(self, ledger: &L) -> Result, SenderPostError> + pub fn validate( + self, + ledger: &L, + ) -> Result, SenderPostError> where L: SenderLedger, { Ok(SenderPostingKey { utxo_accumulator_output: ledger .has_matching_utxo_accumulator_output(self.utxo_accumulator_output) - .ok_or(SenderPostError::InvalidUtxoAccumulatorOutput)?, - nullifier: ledger - .is_unspent(self.nullifier) - .ok_or(SenderPostError::AssetSpent)?, + .map_err(|x| x.into())?, + nullifier: ledger.is_unspent(self.nullifier).map_err(|x| x.into())?, }) } } @@ -677,10 +707,10 @@ where serde( bound( deserialize = r" - L::ValidUtxoAccumulatorOutput: Deserialize<'de>, + L::ValidUtxoAccumulatorOutput: Deserialize<'de>, L::ValidNullifier: Deserialize<'de>", serialize = r" - L::ValidUtxoAccumulatorOutput: Serialize, + L::ValidUtxoAccumulatorOutput: Serialize, L::ValidNullifier: Serialize", ), crate = "manta_util::serde", @@ -716,13 +746,17 @@ where { /// Posts `self` to the sender `ledger`. #[inline] - pub fn post(self, ledger: &mut L, super_key: &L::SuperPostingKey) { - ledger.spend(super_key, self.utxo_accumulator_output, self.nullifier); + pub fn post(self, ledger: &mut L, super_key: &L::SuperPostingKey) -> Result<(), L::Error> { + ledger.spend(super_key, self.utxo_accumulator_output, self.nullifier) } /// Posts all of the [`SenderPostingKey`] in `iter` to the sender `ledger`. #[inline] - pub fn post_all(iter: I, ledger: &mut L, super_key: &L::SuperPostingKey) + pub fn post_all( + iter: I, + ledger: &mut L, + super_key: &L::SuperPostingKey, + ) -> Result<(), L::Error> where I: IntoIterator, { diff --git a/manta-crypto/src/merkle_tree/forest.rs b/manta-crypto/src/merkle_tree/forest.rs index 975dce3b0..378a6fce6 100644 --- a/manta-crypto/src/merkle_tree/forest.rs +++ b/manta-crypto/src/merkle_tree/forest.rs @@ -544,7 +544,6 @@ where fn default() -> Self { Self::new(BoxArray::from_unchecked( (0..N) - .into_iter() .map(move |_| Default::default()) .collect::>() .into_boxed_slice(), @@ -564,7 +563,6 @@ where fn new(parameters: &Parameters) -> Self { Self::new(BoxArray::from_unchecked( (0..N) - .into_iter() .map(move |_| T::new(parameters)) .collect::>() .into_boxed_slice(), diff --git a/manta-pay/src/simulation/ledger/mod.rs b/manta-pay/src/simulation/ledger/mod.rs index 0a2d68681..983d88601 100644 --- a/manta-pay/src/simulation/ledger/mod.rs +++ b/manta-pay/src/simulation/ledger/mod.rs @@ -32,9 +32,12 @@ use indexmap::IndexSet; use manta_accounting::{ asset::{Asset, AssetList}, transfer::{ - canonical::TransferShape, receiver::ReceiverLedger, sender::SenderLedger, - InvalidSinkAccount, InvalidSourceAccount, SinkPostingKey, SourcePostingKey, TransferLedger, - TransferLedgerSuperPostingKey, TransferPostingKeyRef, UtxoAccumulatorOutput, + canonical::TransferShape, + receiver::{ReceiverLedger, ReceiverPostError}, + sender::{SenderLedger, SenderPostError}, + InvalidAuthorizationSignature, InvalidSinkAccount, InvalidSourceAccount, SinkPostingKey, + SourcePostingKey, TransferLedger, TransferLedgerSuperPostingKey, TransferPostError, + TransferPostingKeyRef, UtxoAccumulatorOutput, }, wallet::{ ledger::{self, ReadResponse}, @@ -222,17 +225,174 @@ impl Ledger { } } +/// Sender Ledger Error +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(crate = "manta_util::serde", deny_unknown_fields) +)] +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SenderLedgerError { + /// Invalid UTXO Accumulator Output Error + /// + /// The sender was not constructed under the current state of the UTXO accumulator. + InvalidUtxoAccumulatorOutput, + + /// Asset Spent Error + /// + /// The asset has already been spent. + AssetSpent, + + /// Unexpected Error + UnexpectedError, +} + +impl From for SenderPostError { + #[inline] + fn from(value: SenderLedgerError) -> Self { + match value { + SenderLedgerError::AssetSpent => Self::AssetSpent, + SenderLedgerError::InvalidUtxoAccumulatorOutput => Self::InvalidUtxoAccumulatorOutput, + SenderLedgerError::UnexpectedError => { + Self::UnexpectedError(SenderLedgerError::UnexpectedError) + } + } + } +} + +/// Receiver Ledger Error +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(crate = "manta_util::serde", deny_unknown_fields) +)] +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ReceiverLedgerError { + /// Asset Registered Error + /// + /// The asset has already been registered with the ledger. + AssetRegistered, + + /// Unexpected Error + UnexpectedError, +} + +impl From for ReceiverPostError { + #[inline] + fn from(value: ReceiverLedgerError) -> Self { + match value { + ReceiverLedgerError::AssetRegistered => Self::AssetRegistered, + ReceiverLedgerError::UnexpectedError => { + Self::UnexpectedError(ReceiverLedgerError::UnexpectedError) + } + } + } +} + +/// Transfer Ledger Error +#[cfg_attr( + feature = "serde", + derive(Deserialize, Serialize), + serde(crate = "manta_util::serde", deny_unknown_fields) +)] +#[derive(derivative::Derivative)] +#[derivative(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum TransferLedgerError { + /// Invalid Transfer Post Shape + InvalidShape, + + /// Invalid Authorization Signature + /// + /// The authorization signature for the [`TransferPost`] was not valid. + InvalidAuthorizationSignature(InvalidAuthorizationSignature), + + /// Invalid Source Accounts + InvalidSourceAccount(InvalidSourceAccount), + + /// Invalid Sink Accounts + InvalidSinkAccount(InvalidSinkAccount), + + /// Sender Ledger Error + Sender(SenderLedgerError), + + /// Receiver Ledger Error + Receiver(ReceiverLedgerError), + + /// Duplicate Spend Error + DuplicateSpend, + + /// Duplicate Mint Error + DuplicateMint, + + /// Invalid Transfer Proof Error + /// + /// Validity of the transfer could not be proved by the ledger. + InvalidProof, + + /// Unexpected Error + /// + /// An unexpected error occured. + UnexpectedError, +} + +impl From + for TransferPostError< + Config, + AccountId, + SenderLedgerError, + ReceiverLedgerError, + TransferLedgerError, + > +{ + #[inline] + fn from(value: TransferLedgerError) -> Self { + match value { + TransferLedgerError::InvalidShape => Self::InvalidShape, + TransferLedgerError::InvalidAuthorizationSignature(err) => { + Self::InvalidAuthorizationSignature(err) + } + TransferLedgerError::InvalidSourceAccount(err) => Self::InvalidSourceAccount(err), + TransferLedgerError::InvalidSinkAccount(err) => Self::InvalidSinkAccount(err), + TransferLedgerError::Sender(err) => Self::Sender(err.into()), + TransferLedgerError::Receiver(err) => Self::Receiver(err.into()), + TransferLedgerError::DuplicateSpend => Self::DuplicateSpend, + TransferLedgerError::DuplicateMint => Self::DuplicateMint, + TransferLedgerError::InvalidProof => Self::InvalidProof, + TransferLedgerError::UnexpectedError => { + Self::UnexpectedError(TransferLedgerError::UnexpectedError) + } + } + } +} + +impl From for TransferLedgerError { + #[inline] + fn from(value: ReceiverLedgerError) -> Self { + Self::Receiver(value) + } +} + +impl From for TransferLedgerError { + #[inline] + fn from(value: SenderLedgerError) -> Self { + Self::Sender(value) + } +} + impl SenderLedger for Ledger { type ValidNullifier = Wrap; type ValidUtxoAccumulatorOutput = Wrap>; type SuperPostingKey = (Wrap<()>, ()); + type Error = SenderLedgerError; #[inline] - fn is_unspent(&self, nullifier: Nullifier) -> Option { + fn is_unspent(&self, nullifier: Nullifier) -> Result { if self.nullifiers.contains(&nullifier) { - None + Err(SenderLedgerError::AssetSpent) } else { - Some(Wrap(nullifier)) + Ok(Wrap(nullifier)) } } @@ -240,16 +400,16 @@ impl SenderLedger for Ledger { fn has_matching_utxo_accumulator_output( &self, output: UtxoAccumulatorOutput, - ) -> Option { + ) -> Result { if output == Default::default() { - return Some(Wrap(output)); + return Ok(Wrap(output)); } for tree in self.utxo_forest.forest.as_ref() { if tree.root() == &output { - return Some(Wrap(output)); + return Ok(Wrap(output)); } } - None + Err(SenderLedgerError::InvalidUtxoAccumulatorOutput) } #[inline] @@ -258,22 +418,24 @@ impl SenderLedger for Ledger { super_key: &Self::SuperPostingKey, utxo_accumulator_output: Self::ValidUtxoAccumulatorOutput, nullifier: Self::ValidNullifier, - ) { + ) -> Result<(), Self::Error> { let _ = (utxo_accumulator_output, super_key); self.nullifiers.insert(nullifier.0); + Ok(()) } } impl ReceiverLedger for Ledger { type ValidUtxo = Wrap; type SuperPostingKey = (Wrap<()>, ()); + type Error = ReceiverLedgerError; #[inline] - fn is_not_registered(&self, utxo: Utxo) -> Option { + fn is_not_registered(&self, utxo: Utxo) -> Result { if self.utxos.contains(&utxo) { - None + Err(ReceiverLedgerError::AssetRegistered) } else { - Some(Wrap(utxo)) + Ok(Wrap(utxo)) } } @@ -283,15 +445,16 @@ impl ReceiverLedger for Ledger { super_key: &Self::SuperPostingKey, utxo: Self::ValidUtxo, note: FullIncomingNote, - ) { + ) -> Result<(), Self::Error> { let _ = super_key; let utxo_hash = self.parameters.item_hash(&utxo.0, &mut ()); self.shards .get_mut(&MerkleTreeConfiguration::tree_index(&utxo_hash)) - .expect("All shards exist when the ledger is constructed.") + .ok_or(ReceiverLedgerError::UnexpectedError)? .insert((utxo.0, note)); self.utxos.insert(utxo.0); self.utxo_forest.push(&utxo_hash); + Ok(()) } } @@ -302,7 +465,7 @@ impl TransferLedger for Ledger { type ValidSinkAccount = WrapPair; type ValidProof = Wrap<()>; type SuperPostingKey = (); - type UpdateError = Infallible; + type Error = TransferLedgerError; #[inline] fn check_source_accounts( @@ -375,22 +538,28 @@ impl TransferLedger for Ledger { fn is_valid( &self, posting_key: TransferPostingKeyRef, - ) -> Option<(Self::ValidProof, Self::Event)> { - let verifying_context = self.verifying_context.select(TransferShape::select( + ) -> Result<(Self::ValidProof, Self::Event), >::Error> { + let transfershape = TransferShape::select( posting_key.authorization_key.is_some(), posting_key.asset_id.is_some(), posting_key.sources.len(), posting_key.senders.len(), posting_key.receivers.len(), posting_key.sinks.len(), - )?); + ); + if transfershape.is_none() { + return Err(TransferLedgerError::InvalidShape); + } + let verifying_context = self + .verifying_context + .select(transfershape.expect("This never fails because of the check above.")); ProofSystem::verify( verifying_context, &posting_key.generate_proof_input(), &posting_key.proof, ) - .ok()? - .then_some((Wrap(()), ())) + .map_err(|_| TransferLedgerError::InvalidProof)?; + Ok((Wrap(()), ())) } #[inline] @@ -401,21 +570,39 @@ impl TransferLedger for Ledger { sources: Vec>, sinks: Vec>, proof: Self::ValidProof, - ) -> Result<(), Self::UpdateError> { + ) -> Result<(), >::Error> { let _ = (proof, super_key); for WrapPair(account_id, withdraw) in sources { *self .accounts .get_mut(&account_id) - .expect("We checked that this account exists.") + .ok_or(TransferLedgerError::InvalidSourceAccount( + InvalidSourceAccount { + account_id, + asset_id, + withdraw, + }, + ))? .get_mut(&asset_id) - .expect("We checked that this account has enough balance to withdraw.") -= withdraw; + .ok_or(TransferLedgerError::InvalidSourceAccount( + InvalidSourceAccount { + account_id, + asset_id, + withdraw, + }, + ))? -= withdraw; } for WrapPair(account_id, deposit) in sinks { *self .accounts .get_mut(&account_id) - .expect("We checked that this account exists.") + .ok_or(TransferLedgerError::InvalidSinkAccount( + InvalidSinkAccount { + account_id, + asset_id, + deposit, + }, + ))? .entry(asset_id) .or_default() += deposit; } diff --git a/manta-trusted-setup/src/groth16/ppot/serialization.rs b/manta-trusted-setup/src/groth16/ppot/serialization.rs index f2d827257..39794c596 100644 --- a/manta-trusted-setup/src/groth16/ppot/serialization.rs +++ b/manta-trusted-setup/src/groth16/ppot/serialization.rs @@ -253,10 +253,10 @@ impl Serializer for PpotSerializer { // Final result will be reversed, so this is like modifying first byte res[31] |= 1 << 6; } else { - let mut temp_writer = &mut res[..]; + let temp_writer = &mut res[..]; // Write x coordinate - point.x.write(&mut temp_writer)?; + point.x.write(temp_writer)?; // Check whether y-coordinate is lexicographically greatest // Final result will be reversed, so this is like modifying first byte