From d5e5007ca4480b3e3163a3107b584dfffa16fafa Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 1 Apr 2021 10:52:09 +0200 Subject: [PATCH] Move backtraces into StdError --- contracts/staking/src/contract.rs | 4 +- packages/std/src/errors/std_error.rs | 137 ++++++++++++++++++++------- packages/storage/src/singleton.rs | 2 +- 3 files changed, 105 insertions(+), 38 deletions(-) diff --git a/contracts/staking/src/contract.rs b/contracts/staking/src/contract.rs index c3511ed833..e389cef94a 100644 --- a/contracts/staking/src/contract.rs +++ b/contracts/staking/src/contract.rs @@ -361,7 +361,7 @@ pub fn _bond_all_tokens( }) { Ok(_) => {} // if it is below the minimum, we do a no-op (do not revert other state from withdrawal) - Err(StdError::Overflow(_)) => return Ok(Response::default()), + Err(StdError::Overflow { .. }) => return Ok(Response::default()), Err(e) => return Err(e.into()), } @@ -739,7 +739,7 @@ mod tests { let res = execute(deps.as_mut(), mock_env(), info, unbond_msg); match res.unwrap_err() { StakingError::Std { - original: StdError::Overflow(_), + original: StdError::Overflow { .. }, } => {} err => panic!("Unexpected error: {:?}", err), } diff --git a/packages/std/src/errors/std_error.rs b/packages/std/src/errors/std_error.rs index 6856de1eae..ba61a0532c 100644 --- a/packages/std/src/errors/std_error.rs +++ b/packages/std/src/errors/std_error.rs @@ -83,10 +83,18 @@ pub enum StdError { #[cfg(feature = "backtraces")] backtrace: Backtrace, }, - #[error(transparent)] - Overflow(#[from] OverflowError), - #[error(transparent)] - DivideByZero(#[from] DivideByZeroError), + #[error("Overflow: {source}")] + Overflow { + source: OverflowError, + #[cfg(feature = "backtraces")] + backtrace: Backtrace, + }, + #[error("Divide by zero: {source}")] + DivideByZero { + source: DivideByZeroError, + #[cfg(feature = "backtraces")] + backtrace: Backtrace, + }, } impl StdError { @@ -165,6 +173,22 @@ impl StdError { backtrace: Backtrace::capture(), } } + + pub fn overflow(source: OverflowError) -> Self { + StdError::Overflow { + source, + #[cfg(feature = "backtraces")] + backtrace: Backtrace::capture(), + } + } + + pub fn divide_by_zero(source: DivideByZeroError) -> Self { + StdError::DivideByZero { + source, + #[cfg(feature = "backtraces")] + backtrace: Backtrace::capture(), + } + } } impl PartialEq for StdError { @@ -320,16 +344,34 @@ impl PartialEq for StdError { false } } - StdError::Overflow(err) => { - if let StdError::Overflow(rhs_err) = rhs { - err == rhs_err + StdError::Overflow { + source, + #[cfg(feature = "backtraces")] + backtrace: _, + } => { + if let StdError::Overflow { + source: rhs_source, + #[cfg(feature = "backtraces")] + backtrace: _, + } = rhs + { + source == rhs_source } else { false } } - StdError::DivideByZero(err) => { - if let StdError::DivideByZero(rhs_err) = rhs { - err == rhs_err + StdError::DivideByZero { + source, + #[cfg(feature = "backtraces")] + backtrace: _, + } => { + if let StdError::DivideByZero { + source: rhs_source, + #[cfg(feature = "backtraces")] + backtrace: _, + } = rhs + { + source == rhs_source } else { false } @@ -362,6 +404,18 @@ impl From for StdError { } } +impl From for StdError { + fn from(source: OverflowError) -> Self { + Self::overflow(source) + } +} + +impl From for StdError { + fn from(source: DivideByZeroError) -> Self { + Self::divide_by_zero(source) + } +} + /// The return type for init, execute and query. Since the error type cannot be serialized to JSON, /// this is only available within the contract and its unit tests. /// @@ -389,8 +443,6 @@ pub struct OverflowError { pub operation: OverflowOperation, pub operand1: String, pub operand2: String, - #[cfg(feature = "backtraces")] - backtrace: Backtrace, } impl OverflowError { @@ -399,8 +451,6 @@ impl OverflowError { operation, operand1: operand1.to_string(), operand2: operand2.to_string(), - #[cfg(feature = "backtraces")] - backtrace: Backtrace::capture(), } } } @@ -409,16 +459,12 @@ impl OverflowError { #[error("Cannot devide {operand} by zero")] pub struct DivideByZeroError { pub operand: String, - #[cfg(feature = "backtraces")] - backtrace: Backtrace, } impl DivideByZeroError { pub fn new(operand: U) -> Self { Self { operand: operand.to_string(), - #[cfg(feature = "backtraces")] - backtrace: Backtrace::capture(), } } } @@ -552,14 +598,19 @@ mod tests { #[test] fn underflow_works_for_u128() { - let error = StdError::from(OverflowError::new(OverflowOperation::Sub, 123u128, 456u128)); + let error = + StdError::overflow(OverflowError::new(OverflowOperation::Sub, 123u128, 456u128)); match error { - StdError::Overflow(OverflowError { - operation: OverflowOperation::Sub, - operand1, - operand2, + StdError::Overflow { + source: + OverflowError { + operation, + operand1, + operand2, + }, .. - }) => { + } => { + assert_eq!(operation, OverflowOperation::Sub); assert_eq!(operand1, "123"); assert_eq!(operand2, "456"); } @@ -568,15 +619,19 @@ mod tests { } #[test] - fn underflow_works_for_i64() { - let error = StdError::from(OverflowError::new(OverflowOperation::Sub, 777i64, 1234i64)); + fn overflow_works_for_i64() { + let error = StdError::overflow(OverflowError::new(OverflowOperation::Sub, 777i64, 1234i64)); match error { - StdError::Overflow(OverflowError { - operation: OverflowOperation::Sub, - operand1, - operand2, + StdError::Overflow { + source: + OverflowError { + operation, + operand1, + operand2, + }, .. - }) => { + } => { + assert_eq!(operation, OverflowOperation::Sub); assert_eq!(operand1, "777"); assert_eq!(operand2, "1234"); } @@ -584,21 +639,33 @@ mod tests { } } + #[test] + fn divide_by_zero_works() { + let error = StdError::divide_by_zero(DivideByZeroError::new(123u128)); + match error { + StdError::DivideByZero { + source: DivideByZeroError { operand }, + .. + } => assert_eq!(operand, "123"), + _ => panic!("expect different error"), + } + } + #[test] fn implements_debug() { let error: StdError = StdError::from(OverflowError::new(OverflowOperation::Sub, 3, 5)); - let embedded = format!("Debug message: {:?}", error); + let embedded = format!("Debug: {:?}", error); assert_eq!( embedded, - r#"Debug message: Overflow(OverflowError { operation: Sub, operand1: "3", operand2: "5" })"# + r#"Debug: Overflow { source: OverflowError { operation: Sub, operand1: "3", operand2: "5" } }"# ); } #[test] fn implements_display() { let error: StdError = StdError::from(OverflowError::new(OverflowOperation::Sub, 3, 5)); - let embedded = format!("Display message: {}", error); - assert_eq!(embedded, "Display message: Cannot Sub with 3 and 5"); + let embedded = format!("Display: {}", error); + assert_eq!(embedded, "Display: Overflow: Cannot Sub with 3 and 5"); } #[test] diff --git a/packages/storage/src/singleton.rs b/packages/storage/src/singleton.rs index f2a9573988..6d3fce6cad 100644 --- a/packages/storage/src/singleton.rs +++ b/packages/storage/src/singleton.rs @@ -259,7 +259,7 @@ mod tests { ))) }); match output.unwrap_err() { - StdError::Overflow(_) => {} + StdError::Overflow { .. } => {} err => panic!("Unexpected error: {:?}", err), } assert_eq!(writer.load().unwrap(), cfg);