diff --git a/Cargo.toml b/Cargo.toml index 3cc15387ca..db2ec00905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,6 @@ repository = "https://github.com/iron-fish/ironfish" [patch.crates-io] bellman = { git = "https://github.com/iron-fish/bellman", rev = "1cc52ca33e6db14233f1cbc0c9c5b7c822b229ec" } + +[profile.release] +debug = true \ No newline at end of file diff --git a/ironfish-rust/src/assets/asset.rs b/ironfish-rust/src/assets/asset.rs index 0e0b65c211..ab16a6c261 100644 --- a/ironfish-rust/src/assets/asset.rs +++ b/ironfish-rust/src/assets/asset.rs @@ -1,7 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::{errors::IronfishError, keys::PUBLIC_ADDRESS_SIZE, util::str_to_array, PublicAddress}; +use crate::{errors::{IronfishError, IronfishErrorKind}, keys::PUBLIC_ADDRESS_SIZE, util::str_to_array, PublicAddress}; use byteorder::{ReadBytesExt, WriteBytesExt}; use ironfish_zkp::constants::{ASSET_ID_LENGTH, ASSET_ID_PERSONALIZATION, GH_FIRST_BLOCK}; use jubjub::{ExtendedPoint, SubgroupPoint}; @@ -39,7 +39,7 @@ impl Asset { pub fn new(creator: PublicAddress, name: &str, metadata: &str) -> Result { let trimmed_name = name.trim(); if trimmed_name.is_empty() { - return Err(IronfishError::InvalidData); + return Err(IronfishError::new(IronfishErrorKind::InvalidData)); } let name_bytes = str_to_array(trimmed_name); @@ -50,7 +50,7 @@ impl Asset { if let Ok(asset) = Asset::new_with_nonce(creator, name_bytes, metadata_bytes, nonce) { return Ok(asset); } - nonce = nonce.checked_add(1).ok_or(IronfishError::RandomnessError)?; + nonce = nonce.checked_add(1).ok_or(IronfishError::new(IronfishErrorKind::RandomnessError))?; } } diff --git a/ironfish-rust/src/assets/asset_identifier.rs b/ironfish-rust/src/assets/asset_identifier.rs index 0725c5fdbc..ff6471bcb5 100644 --- a/ironfish-rust/src/assets/asset_identifier.rs +++ b/ironfish-rust/src/assets/asset_identifier.rs @@ -1,7 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; use group::cofactor::CofactorGroup; use ironfish_zkp::{constants::ASSET_ID_LENGTH, util::asset_hash_to_point}; use jubjub::{ExtendedPoint, SubgroupPoint}; @@ -58,7 +58,7 @@ impl TryFrom<[u8; ASSET_ID_LENGTH]> for AssetIdentifier { return Ok(Self(byte_array)); } - Err(IronfishError::InvalidAssetIdentifier) + Err(IronfishError::new(IronfishErrorKind::InvalidAssetIdentifier)) } } diff --git a/ironfish-rust/src/errors.rs b/ironfish-rust/src/errors.rs index cf2e8e18ee..7f542239c0 100644 --- a/ironfish-rust/src/errors.rs +++ b/ironfish-rust/src/errors.rs @@ -2,19 +2,26 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::backtrace::Backtrace; use std::error::Error; use std::fmt; use std::io; use std::num; use std::string; +#[derive(Debug)] +pub struct IronfishError { + pub kind: IronfishErrorKind, + pub backtrace: Backtrace, +} + /// Error type to handle all errors within the code and dependency-raised /// errors. This serves 2 purposes. The first is to keep a consistent error type /// in the code to reduce the cognitive load needed for using Result and Error /// types. The second is to give a singular type to convert into NAPI errors to /// be raised on the Javascript side. #[derive(Debug)] -pub enum IronfishError { +pub enum IronfishErrorKind { BellpersonSynthesis(bellperson::SynthesisError), CryptoBox(crypto_box::aead::Error), IllegalValue, @@ -47,40 +54,58 @@ pub enum IronfishError { VerificationFailed, } +impl IronfishError { + pub fn new(kind: IronfishErrorKind) -> Self { + Self { + kind, + backtrace: Backtrace::capture(), + } + } +} + + impl Error for IronfishError {} impl fmt::Display for IronfishError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) + let backtrace_str = self.backtrace.to_string(); + let has_backtrace = !backtrace_str.contains("disabled"); + write!(f, "{:?}", self.kind)?; + if has_backtrace { + write!(f, "\nBacktrace:\n{:2.}", self.backtrace) + } else { + write!(f, "\nTo enable Rust backtraces, use RUST_BACKTRACE=1") + } } } impl From for IronfishError { fn from(e: io::Error) -> IronfishError { - IronfishError::Io(e) + IronfishError::new(IronfishErrorKind::Io(e)) } } impl From for IronfishError { fn from(e: crypto_box::aead::Error) -> IronfishError { - IronfishError::CryptoBox(e) + IronfishError::new(IronfishErrorKind::CryptoBox(e)) } } impl From for IronfishError { fn from(e: string::FromUtf8Error) -> IronfishError { - IronfishError::Utf8(e) + IronfishError::new(IronfishErrorKind::Utf8(e)) } } impl From for IronfishError { fn from(e: bellperson::SynthesisError) -> IronfishError { - IronfishError::BellpersonSynthesis(e) + IronfishError::new(IronfishErrorKind::BellpersonSynthesis(e)) } } impl From for IronfishError { fn from(e: num::TryFromIntError) -> IronfishError { - IronfishError::TryFromInt(e) + IronfishError::new(IronfishErrorKind::TryFromInt(e)) } } + diff --git a/ironfish-rust/src/keys/mod.rs b/ironfish-rust/src/keys/mod.rs index 23965d6b99..cc8e024a0c 100644 --- a/ironfish-rust/src/keys/mod.rs +++ b/ironfish-rust/src/keys/mod.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; use crate::serializing::{bytes_to_hex, hex_to_bytes, read_scalar}; pub use bip39::Language; @@ -81,7 +81,7 @@ impl SaplingKey { jubjub::Fr::from_bytes_wide(&Self::convert_key(spending_key, 0)); if spend_authorizing_key == jubjub::Fr::zero() { - return Err(IronfishError::IllegalValue); + return Err(IronfishError::new(IronfishErrorKind::IllegalValue)); } let proof_authorizing_key = @@ -123,7 +123,7 @@ impl SaplingKey { /// Load a key from a string of hexadecimal digits pub fn from_hex(value: &str) -> Result { match hex_to_bytes(value) { - Err(_) => Err(IronfishError::InvalidPaymentAddress), + Err(_) => Err(IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)), Ok(bytes) => Self::new(bytes), } } @@ -151,7 +151,7 @@ impl SaplingKey { pub fn write(&self, mut writer: W) -> Result<(), IronfishError> { let num_bytes_written = writer.write(&self.spending_key)?; if num_bytes_written != SPEND_KEY_SIZE { - return Err(IronfishError::InvalidData); + return Err(IronfishError::new(IronfishErrorKind::InvalidData)); } Ok(()) @@ -176,13 +176,13 @@ impl SaplingKey { /// using bip-32 and bip-39 if desired. pub fn to_words(&self, language: Language) -> Result { Mnemonic::from_entropy(&self.spending_key, language) - .map_err(|_| IronfishError::InvalidEntropy) + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidEntropy)) } /// Takes a bip-39 phrase as a string and turns it into a SaplingKey instance pub fn from_words(words: String, language: Language) -> Result { let mnemonic = Mnemonic::from_phrase(&words, language) - .map_err(|_| IronfishError::InvalidMnemonicString)?; + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidMnemonicString))?; let bytes = mnemonic.entropy(); let mut byte_arr = [0; SPEND_KEY_SIZE]; byte_arr.clone_from_slice(&bytes[0..SPEND_KEY_SIZE]); @@ -261,7 +261,7 @@ impl SaplingKey { // Drop the last five bits, so it can be interpreted as a scalar. hash_result[31] &= 0b0000_0111; if hash_result == [0; 32] { - return Err(IronfishError::InvalidViewingKey); + return Err(IronfishError::new(IronfishErrorKind::InvalidViewingKey)); } let scalar = read_scalar(&hash_result[..])?; Ok(scalar) diff --git a/ironfish-rust/src/keys/public_address.rs b/ironfish-rust/src/keys/public_address.rs index 6a2c69d77f..2b28fcfdd4 100644 --- a/ironfish-rust/src/keys/public_address.rs +++ b/ironfish-rust/src/keys/public_address.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::{ - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, serializing::{bytes_to_hex, hex_to_bytes}, }; use group::GroupEncoding; @@ -58,7 +58,7 @@ impl PublicAddress { /// or it fails. pub fn from_hex(value: &str) -> Result { match hex_to_bytes(value) { - Err(_) => Err(IronfishError::InvalidPublicAddress), + Err(_) => Err(IronfishError::new(IronfishErrorKind::InvalidPublicAddress)), Ok(bytes) => Self::new(&bytes), } } @@ -90,7 +90,7 @@ impl PublicAddress { if transmission_key_non_prime.is_some().into() { Ok(transmission_key_non_prime.unwrap()) } else { - Err(IronfishError::InvalidPaymentAddress) + Err(IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) } } } diff --git a/ironfish-rust/src/keys/view_keys.rs b/ironfish-rust/src/keys/view_keys.rs index e26a378a0c..30ccd80c75 100644 --- a/ironfish-rust/src/keys/view_keys.rs +++ b/ironfish-rust/src/keys/view_keys.rs @@ -14,7 +14,7 @@ use super::PublicAddress; use crate::{ - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, serializing::{bytes_to_hex, hex_to_bytes, read_scalar}, }; use bip39::{Language, Mnemonic}; @@ -44,7 +44,7 @@ impl IncomingViewKey { /// Load a key from a string of hexadecimal digits pub fn from_hex(value: &str) -> Result { match hex_to_bytes::<32>(value) { - Err(_) => Err(IronfishError::InvalidViewingKey), + Err(_) => Err(IronfishError::new(IronfishErrorKind::InvalidViewingKey)), Ok(bytes) => Self::read(&mut bytes.as_ref()), } } @@ -52,9 +52,9 @@ impl IncomingViewKey { /// Load a key from a string of words to be decoded into bytes. pub fn from_words(language_code: &str, value: String) -> Result { let language = Language::from_language_code(language_code) - .ok_or(IronfishError::InvalidLanguageEncoding)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidLanguageEncoding))?; let mnemonic = Mnemonic::from_phrase(&value, language) - .map_err(|_| IronfishError::InvalidPaymentAddress)?; + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidPaymentAddress))?; let bytes = mnemonic.entropy(); let mut byte_arr = [0; 32]; byte_arr.clone_from_slice(&bytes[0..32]); @@ -69,7 +69,7 @@ impl IncomingViewKey { /// Even more readable pub fn words_key(&self, language_code: &str) -> Result { let language = Language::from_language_code(language_code) - .ok_or(IronfishError::InvalidLanguageEncoding)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidLanguageEncoding))?; let mnemonic = Mnemonic::from_entropy(&self.view_key.to_bytes(), language).unwrap(); Ok(mnemonic.phrase().to_string()) } @@ -113,10 +113,10 @@ impl ViewKey { nullifier_deriving_key_bytes.clone_from_slice(&bytes[32..]); let authorizing_key = Option::from(SubgroupPoint::from_bytes(&authorizing_key_bytes)) - .ok_or(IronfishError::InvalidAuthorizingKey)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidAuthorizingKey))?; let nullifier_deriving_key = Option::from(SubgroupPoint::from_bytes(&nullifier_deriving_key_bytes)) - .ok_or(IronfishError::InvalidNullifierDerivingKey)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidNullifierDerivingKey))?; Ok(Self { authorizing_key, @@ -149,7 +149,7 @@ impl OutgoingViewKey { /// Load a key from a string of hexadecimal digits pub fn from_hex(value: &str) -> Result { match hex_to_bytes(value) { - Err(_) => Err(IronfishError::InvalidViewingKey), + Err(_) => Err(IronfishError::new(IronfishErrorKind::InvalidViewingKey)), Ok(bytes) => Ok(Self { view_key: bytes }), } } @@ -157,9 +157,9 @@ impl OutgoingViewKey { /// Load a key from a string of words to be decoded into bytes. pub fn from_words(language_code: &str, value: String) -> Result { let language = Language::from_language_code(language_code) - .ok_or(IronfishError::InvalidLanguageEncoding)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidLanguageEncoding))?; let mnemonic = Mnemonic::from_phrase(&value, language) - .map_err(|_| IronfishError::InvalidPaymentAddress)?; + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidPaymentAddress))?; let bytes = mnemonic.entropy(); let mut view_key = [0; 32]; view_key.clone_from_slice(&bytes[0..32]); @@ -174,7 +174,7 @@ impl OutgoingViewKey { /// Even more readable pub fn words_key(&self, language_code: &str) -> Result { let language = Language::from_language_code(language_code) - .ok_or(IronfishError::InvalidLanguageEncoding)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidLanguageEncoding))?; let mnemonic = Mnemonic::from_entropy(&self.view_key, language).unwrap(); Ok(mnemonic.phrase().to_string()) } diff --git a/ironfish-rust/src/nacl.rs b/ironfish-rust/src/nacl.rs index 5d27437276..25116b63bc 100644 --- a/ironfish-rust/src/nacl.rs +++ b/ironfish-rust/src/nacl.rs @@ -9,7 +9,7 @@ use crypto_box::{ }; use rand::RngCore; -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; pub const KEY_LENGTH: usize = crypto_box::KEY_SIZE; pub const NONCE_LENGTH: usize = 24; @@ -57,7 +57,7 @@ pub fn unbox_message( recipient_secret_key: [u8; KEY_LENGTH], ) -> Result { if nonce.len() != NONCE_LENGTH { - return Err(IronfishError::InvalidNonceLength); + return Err(IronfishError::new(IronfishErrorKind::InvalidNonceLength)) } let nonce = GenericArray::from_slice(nonce); diff --git a/ironfish-rust/src/note.rs b/ironfish-rust/src/note.rs index fcd0c23d89..9c9551c845 100644 --- a/ironfish-rust/src/note.rs +++ b/ironfish-rust/src/note.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::{ - assets::asset_identifier::AssetIdentifier, errors::IronfishError, keys::PUBLIC_ADDRESS_SIZE, + assets::asset_identifier::AssetIdentifier, errors::{IronfishError, IronfishErrorKind}, keys::PUBLIC_ADDRESS_SIZE, util::str_to_array, ViewKey, }; @@ -330,7 +330,7 @@ impl<'a> Note { if commitment == self.commitment_point() { Ok(()) } else { - Err(IronfishError::InvalidCommitment) + Err(IronfishError::new(IronfishErrorKind::InvalidCommitment)) } } diff --git a/ironfish-rust/src/serializing/aead.rs b/ironfish-rust/src/serializing/aead.rs index 508a487301..8331c93dd3 100644 --- a/ironfish-rust/src/serializing/aead.rs +++ b/ironfish-rust/src/serializing/aead.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; use chacha20poly1305::aead::{AeadInPlace, NewAead}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; @@ -28,7 +28,7 @@ pub(crate) fn encrypt( &[], &mut encrypted_output[..plaintext.len()], ) - .map_err(|_| IronfishError::InvalidSigningKey)?; + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidSigningKey))?; encrypted_output[plaintext.len()..].copy_from_slice(&tag); Ok(encrypted_output) @@ -53,7 +53,7 @@ pub(crate) fn decrypt( &mut plaintext, ciphertext[SIZE..].into(), ) - .map_err(|_| IronfishError::InvalidDecryptionKey)?; + .map_err(|_| IronfishError::new(IronfishErrorKind::InvalidDecryptionKey))?; Ok(plaintext) } diff --git a/ironfish-rust/src/serializing/mod.rs b/ironfish-rust/src/serializing/mod.rs index 22f2c1e0b0..4d65d948d2 100644 --- a/ironfish-rust/src/serializing/mod.rs +++ b/ironfish-rust/src/serializing/mod.rs @@ -4,7 +4,7 @@ pub mod aead; -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; /// Helper functions to convert pairing parts to bytes /// @@ -22,14 +22,14 @@ pub(crate) fn read_scalar(mut reader: R) -> Result(mut reader: R) -> Result { let mut point_repr = G::Repr::default(); reader.read_exact(point_repr.as_mut())?; - Option::from(G::from_bytes(&point_repr)).ok_or(IronfishError::InvalidData) + Option::from(G::from_bytes(&point_repr)).ok_or(IronfishError::new(IronfishErrorKind::InvalidData)) } /// Output the bytes as a hexadecimal String @@ -47,7 +47,7 @@ pub fn bytes_to_hex(bytes: &[u8]) -> String { /// Output the hexadecimal String as bytes pub fn hex_to_bytes(hex: &str) -> Result<[u8; SIZE], IronfishError> { if hex.len() != SIZE * 2 { - return Err(IronfishError::InvalidData); + return Err(IronfishError::new(IronfishErrorKind::InvalidData)); } let mut bytes = [0; SIZE]; @@ -67,7 +67,7 @@ fn hex_to_u8(char: u8) -> Result { b'0'..=b'9' => Ok(char - b'0'), b'a'..=b'f' => Ok(char - b'a' + 10), b'A'..=b'F' => Ok(char - b'A' + 10), - _ => Err(IronfishError::InvalidData), + _ => Err(IronfishError::new(IronfishErrorKind::InvalidData)), } } diff --git a/ironfish-rust/src/transaction/mints.rs b/ironfish-rust/src/transaction/mints.rs index 21ebb365bb..998c7ba154 100644 --- a/ironfish-rust/src/transaction/mints.rs +++ b/ironfish-rust/src/transaction/mints.rs @@ -18,7 +18,7 @@ use jubjub::ExtendedPoint; use rand::thread_rng; use crate::{ - assets::asset::Asset, errors::IronfishError, sapling_bls12::SAPLING, + assets::asset::Asset, errors::{IronfishError, IronfishErrorKind}, sapling_bls12::SAPLING, transaction::TransactionVersion, PublicAddress, SaplingKey, }; @@ -121,7 +121,7 @@ impl UnsignedMintDescription { .randomize(self.public_key_randomness, *SPENDING_KEY_GENERATOR); if randomized_public_key.0 != transaction_randomized_public_key.0 { - return Err(IronfishError::InvalidSigningKey); + return Err(IronfishError::new(IronfishErrorKind::InvalidSigningKey)); } let mut data_to_be_signed = [0; 64]; @@ -174,7 +174,7 @@ impl MintDescription { randomized_public_key: &redjubjub::PublicKey, ) -> Result<(), IronfishError> { if randomized_public_key.0.is_small_order().into() { - return Err(IronfishError::IsSmallOrder); + return Err(IronfishError::new(IronfishErrorKind::IsSmallOrder)); } let mut data_to_be_signed = [0; 64]; data_to_be_signed[..32].copy_from_slice(&randomized_public_key.0.to_bytes()); @@ -185,7 +185,7 @@ impl MintDescription { &self.authorizing_signature, *SPENDING_KEY_GENERATOR, ) { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) @@ -224,7 +224,7 @@ impl MintDescription { self.asset.nonce, )?; if asset.id != self.asset.id { - return Err(IronfishError::InvalidAssetIdentifier); + return Err(IronfishError::new(IronfishErrorKind::InvalidAssetIdentifier)); } Ok(()) @@ -253,7 +253,7 @@ impl MintDescription { writer.write_u8(0)?; } } else if self.transfer_ownership_to.is_some() { - return Err(IronfishError::InvalidTransactionVersion); + return Err(IronfishError::new(IronfishErrorKind::InvalidTransactionVersion)); } Ok(()) @@ -314,7 +314,7 @@ mod test { use crate::{ assets::asset::Asset, - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, transaction::{ mints::{MintBuilder, MintDescription}, utils::verify_mint_proof, @@ -398,9 +398,10 @@ mod test { let value = 5; let mint = MintBuilder::new(asset, value); + let err = IronfishError::new(IronfishErrorKind::VerificationFailed); assert!(matches!( mint.build(&owner_key, &public_key_randomness, &randomized_public_key), - Err(IronfishError::VerificationFailed) + Err(err) )) } diff --git a/ironfish-rust/src/transaction/mod.rs b/ironfish-rust/src/transaction/mod.rs index 7299ae821a..dee2436c70 100644 --- a/ironfish-rust/src/transaction/mod.rs +++ b/ironfish-rust/src/transaction/mod.rs @@ -13,7 +13,7 @@ use crate::{ asset::Asset, asset_identifier::{AssetIdentifier, NATIVE_ASSET}, }, - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, keys::{PublicAddress, SaplingKey}, note::Note, sapling_bls12::SAPLING, @@ -218,7 +218,7 @@ impl ProposedTransaction { }; if change_amount < 0 { - return Err(IronfishError::InvalidBalance); + return Err(IronfishError::new(IronfishErrorKind::InvalidBalance)); } if change_amount > 0 { let change_address = @@ -253,7 +253,7 @@ impl ProposedTransaction { || !self.mints.is_empty() || !self.burns.is_empty() { - return Err(IronfishError::InvalidMinersFeeTransaction); + return Err(IronfishError::new(IronfishErrorKind::InvalidMinersFeeTransaction)); } self.post_miners_fee_unchecked() } @@ -470,7 +470,7 @@ impl ProposedTransaction { // the final value balance point. The binding verification key is how verifiers // check the consistency of the values in a transaction. if value_balance != public_key.0 { - return Err(IronfishError::InvalidBalance); + return Err(IronfishError::new(IronfishErrorKind::InvalidBalance)); } Ok((private_key, public_key)) @@ -722,7 +722,7 @@ impl Transaction { &self.binding_signature, *VALUE_COMMITMENT_RANDOMNESS_GENERATOR, ) { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) @@ -737,7 +737,7 @@ fn fee_to_point(value: i64) -> Result { let is_negative = value.is_negative(); let abs = match value.checked_abs() { Some(a) => a as u64, - None => return Err(IronfishError::IllegalValue), + None => return Err(IronfishError::new(IronfishErrorKind::IllegalValue)), }; let mut value_balance = *NATIVE_VALUE_COMMITMENT_GENERATOR * jubjub::Fr::from(abs); @@ -861,7 +861,7 @@ fn internal_batch_verify_transactions<'a>( &spend_public_inputs[..], )? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } if !output_proofs.is_empty() && !verify_proofs_batch( @@ -871,7 +871,7 @@ fn internal_batch_verify_transactions<'a>( &output_public_inputs[..], )? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } if !mint_proofs.is_empty() && !verify_proofs_batch( @@ -881,7 +881,7 @@ fn internal_batch_verify_transactions<'a>( &mint_public_inputs[..], )? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) diff --git a/ironfish-rust/src/transaction/outputs.rs b/ironfish-rust/src/transaction/outputs.rs index 21c79adc13..7d7f6ebd55 100644 --- a/ironfish-rust/src/transaction/outputs.rs +++ b/ironfish-rust/src/transaction/outputs.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::{ - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, keys::{EphemeralKeyPair, SaplingKey}, merkle_note::MerkleNote, note::Note, @@ -166,7 +166,7 @@ impl OutputDescription { .is_small_order() .into() { - return Err(IronfishError::IsSmallOrder); + return Err(IronfishError::new(IronfishErrorKind::IsSmallOrder)); } Ok(()) diff --git a/ironfish-rust/src/transaction/spends.rs b/ironfish-rust/src/transaction/spends.rs index b94ba63bf9..777b3ba796 100644 --- a/ironfish-rust/src/transaction/spends.rs +++ b/ironfish-rust/src/transaction/spends.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::{ - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, keys::SaplingKey, merkle_note::{position as witness_position, sapling_auth_path}, note::Note, @@ -171,7 +171,7 @@ impl UnsignedSpendDescription { .randomize(self.public_key_randomness, *SPENDING_KEY_GENERATOR); if randomized_public_key.0 != transaction_randomized_public_key.0 { - return Err(IronfishError::InvalidSigningKey); + return Err(IronfishError::new(IronfishErrorKind::InvalidSigningKey)); } let mut data_to_be_signed = [0; 64]; @@ -275,7 +275,7 @@ impl SpendDescription { randomized_public_key: &redjubjub::PublicKey, ) -> Result<(), IronfishError> { if randomized_public_key.0.is_small_order().into() { - return Err(IronfishError::IsSmallOrder); + return Err(IronfishError::new(IronfishErrorKind::IsSmallOrder)); } let mut data_to_be_signed = [0; 64]; data_to_be_signed[..32].copy_from_slice(&randomized_public_key.0.to_bytes()); @@ -286,7 +286,7 @@ impl SpendDescription { &self.authorizing_signature, *SPENDING_KEY_GENERATOR, ) { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) @@ -305,7 +305,7 @@ impl SpendDescription { fn verify_not_small_order(&self) -> Result<(), IronfishError> { if self.value_commitment.is_small_order().into() { - return Err(IronfishError::IsSmallOrder); + return Err(IronfishError::new(IronfishErrorKind::IsSmallOrder)); } Ok(()) diff --git a/ironfish-rust/src/transaction/tests.rs b/ironfish-rust/src/transaction/tests.rs index 2ee8e61277..d4f6c93cde 100644 --- a/ironfish-rust/src/transaction/tests.rs +++ b/ironfish-rust/src/transaction/tests.rs @@ -7,7 +7,7 @@ use super::internal_batch_verify_transactions; use super::{ProposedTransaction, Transaction}; use crate::{ assets::{asset::Asset, asset_identifier::NATIVE_ASSET}, - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, keys::SaplingKey, merkle_note::NOTE_ENCRYPTION_MINER_KEYS, note::Note, @@ -308,9 +308,10 @@ fn test_transaction_created_with_version_1() { #[test] fn test_transaction_version_is_checked() { fn assert_invalid_version(result: Result) { + let err = IronfishError::new(IronfishErrorKind::InvalidTransactionVersion); match result { Ok(_) => panic!("expected an error"), - Err(IronfishError::InvalidTransactionVersion) => (), + Err(err) => (), Err(ref err) => panic!("expected InvalidTransactionVersion, got {:?} instead", err), } } @@ -581,9 +582,10 @@ fn test_batch_verify() { let mut bad_transaction = transaction1.clone(); bad_transaction.randomized_public_key = other_randomized_public_key; + let err = IronfishError::new(IronfishErrorKind::VerificationFailed); assert!(matches!( batch_verify_transactions([&bad_transaction, &transaction2]), - Err(IronfishError::VerificationFailed) + Err(err) )); let mut bad_transaction = transaction1.clone(); @@ -591,7 +593,7 @@ fn test_batch_verify() { assert!(matches!( batch_verify_transactions([&bad_transaction, &transaction2]), - Err(IronfishError::VerificationFailed) + Err(err) )); let mut bad_transaction = transaction1.clone(); @@ -599,7 +601,7 @@ fn test_batch_verify() { assert!(matches!( batch_verify_transactions([&bad_transaction, &transaction2]), - Err(IronfishError::VerificationFailed) + Err(err) )); let mut bad_transaction = transaction1; @@ -607,6 +609,6 @@ fn test_batch_verify() { assert!(matches!( batch_verify_transactions([&bad_transaction, &transaction2]), - Err(IronfishError::VerificationFailed) + Err(err) )); } diff --git a/ironfish-rust/src/transaction/utils.rs b/ironfish-rust/src/transaction/utils.rs index 8569781455..4ab7903d57 100644 --- a/ironfish-rust/src/transaction/utils.rs +++ b/ironfish-rust/src/transaction/utils.rs @@ -4,7 +4,7 @@ use bellperson::groth16; use blstrs::Bls12; -use crate::{errors::IronfishError, sapling_bls12::SAPLING}; +use crate::{errors::{IronfishError, IronfishErrorKind}, sapling_bls12::SAPLING}; /// Helper function for verifying spend proof internally. Note that this is not /// called by verifiers as part of transaction verification. See @@ -14,7 +14,7 @@ pub(crate) fn verify_spend_proof( inputs: &[blstrs::Scalar], ) -> Result<(), IronfishError> { if !groth16::verify_proof(&SAPLING.spend_verifying_key, proof, inputs)? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) @@ -28,7 +28,7 @@ pub(crate) fn verify_output_proof( inputs: &[blstrs::Scalar], ) -> Result<(), IronfishError> { if !groth16::verify_proof(&SAPLING.output_verifying_key, proof, inputs)? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) @@ -42,7 +42,7 @@ pub(crate) fn verify_mint_proof( inputs: &[blstrs::Scalar], ) -> Result<(), IronfishError> { if !groth16::verify_proof(&SAPLING.mint_verifying_key, proof, inputs)? { - return Err(IronfishError::VerificationFailed); + return Err(IronfishError::new(IronfishErrorKind::VerificationFailed)); } Ok(()) diff --git a/ironfish-rust/src/transaction/value_balances.rs b/ironfish-rust/src/transaction/value_balances.rs index f1cdb26f85..196e99c5c5 100644 --- a/ironfish-rust/src/transaction/value_balances.rs +++ b/ironfish-rust/src/transaction/value_balances.rs @@ -5,7 +5,7 @@ use std::collections::{hash_map, HashMap}; use crate::{ assets::asset_identifier::{AssetIdentifier, NATIVE_ASSET}, - errors::IronfishError, + errors::{IronfishError, IronfishErrorKind}, }; pub struct ValueBalances { @@ -25,7 +25,7 @@ impl ValueBalances { let current_value = self.values.entry(*asset_id).or_insert(0); let new_value = current_value .checked_add(value) - .ok_or(IronfishError::InvalidBalance)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidBalance))?; *current_value = new_value; @@ -40,7 +40,7 @@ impl ValueBalances { let current_value = self.values.entry(*asset_id).or_insert(0); let new_value = current_value .checked_sub(value) - .ok_or(IronfishError::InvalidBalance)?; + .ok_or(IronfishError::new(IronfishErrorKind::InvalidBalance))?; *current_value = new_value; diff --git a/ironfish-rust/src/transaction/version.rs b/ironfish-rust/src/transaction/version.rs index 13054938d2..2122edb002 100644 --- a/ironfish-rust/src/transaction/version.rs +++ b/ironfish-rust/src/transaction/version.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::errors::IronfishError; +use crate::errors::{IronfishError, IronfishErrorKind}; use byteorder::{ReadBytesExt, WriteBytesExt}; use std::io; @@ -60,7 +60,7 @@ impl TryFrom for TransactionVersion { #[inline] fn try_from(value: u8) -> Result { - Self::from_u8(value).ok_or(IronfishError::InvalidTransactionVersion) + Self::from_u8(value).ok_or(IronfishError::new(IronfishErrorKind::InvalidTransactionVersion)) } }