odra_core/
error.rs

1use core::any::Any;
2
3use casper_types::bytesrepr::Error as BytesReprError;
4use casper_types::{CLType, CLValueError};
5
6use crate::arithmetic::ArithmeticsError;
7use crate::prelude::*;
8use crate::VmError::Serialization;
9
10/// General error type in Odra framework
11#[repr(u16)]
12#[derive(Clone, Debug, PartialEq)]
13pub enum OdraError {
14    /// An error that can occur during smart contract execution
15    ExecutionError(ExecutionError),
16    /// An internal virtual machine error
17    VmError(VmError)
18}
19
20impl OdraError {
21    /// Returns the error code.
22    pub fn code(&self) -> u16 {
23        match self {
24            OdraError::ExecutionError(e) => e.code(),
25            OdraError::VmError(_e) => 0
26        }
27    }
28
29    /// Creates a new user error with a given code.
30    pub fn user(code: u16) -> Self {
31        if code >= ExecutionError::UserErrorTooHigh.code() {
32            ExecutionError::UserErrorTooHigh.into()
33        } else {
34            ExecutionError::User(code).into()
35        }
36    }
37}
38
39impl From<ArithmeticsError> for ExecutionError {
40    fn from(error: ArithmeticsError) -> Self {
41        match error {
42            ArithmeticsError::AdditionOverflow => Self::AdditionOverflow,
43            ArithmeticsError::SubtractingOverflow => Self::SubtractionOverflow
44        }
45    }
46}
47
48impl From<ArithmeticsError> for OdraError {
49    fn from(error: ArithmeticsError) -> Self {
50        Into::<ExecutionError>::into(error).into()
51    }
52}
53
54impl From<Box<dyn Any + Send>> for OdraError {
55    fn from(_: Box<dyn Any + Send>) -> Self {
56        OdraError::VmError(VmError::Panic)
57    }
58}
59
60impl From<casper_types::bytesrepr::Error> for ExecutionError {
61    fn from(error: casper_types::bytesrepr::Error) -> Self {
62        match error {
63            casper_types::bytesrepr::Error::EarlyEndOfStream => Self::EarlyEndOfStream,
64            casper_types::bytesrepr::Error::Formatting => Self::Formatting,
65            casper_types::bytesrepr::Error::LeftOverBytes => Self::LeftOverBytes,
66            casper_types::bytesrepr::Error::OutOfMemory => Self::OutOfMemory,
67            casper_types::bytesrepr::Error::NotRepresentable => Self::NotRepresentable,
68            casper_types::bytesrepr::Error::ExceededRecursionDepth => Self::ExceededRecursionDepth,
69            _ => Self::Formatting
70        }
71    }
72}
73
74/// An error that can occur during smart contract execution
75///
76/// It is represented by an error code and a human-readable message.
77///
78/// Errors codes 0..32767 are available for the user to define custom error
79/// in smart contracts.
80/// 32768 code is a special code representing a violation of the custom error code space.
81///
82/// The rest of codes 32769..[u16::MAX](u16::MAX), are used internally by the framework.
83#[repr(u16)]
84#[derive(Clone, Copy, Debug, PartialEq)]
85pub enum ExecutionError {
86    /// Unwrap error.
87    UnwrapError = 1,
88    /// Something unexpected happened.
89    UnexpectedError = 2,
90    /// Addition overflow
91    AdditionOverflow = 100,
92    /// Subtraction overflow
93    SubtractionOverflow = 101,
94    /// Method does not accept deposit
95    NonPayable = 102,
96    /// Can't transfer tokens to contract.
97    TransferToContract = 103,
98    /// Reentrant call detected
99    ReentrantCall = 104,
100    /// Contract already installed
101    ContractAlreadyInstalled = 105,
102    /// Unknown constructor
103    UnknownConstructor = 106,
104    /// Native transfer error
105    NativeTransferError = 107,
106    /// Index out of bounds
107    IndexOutOfBounds = 108,
108    /// Tried to construct a zero address.
109    ZeroAddress = 109,
110    /// Address creation failed
111    AddressCreationFailed = 110,
112    /// Early end of stream - deserialization error
113    EarlyEndOfStream = 111,
114    /// Formatting error - deserialization error
115    Formatting = 112,
116    /// Left over bytes - deserialization error
117    LeftOverBytes = 113,
118    /// Out of memory
119    OutOfMemory = 114,
120    /// Not representable
121    NotRepresentable = 115,
122    /// Exceeded recursion depth
123    ExceededRecursionDepth = 116,
124    /// Key not found
125    KeyNotFound = 117,
126    /// Could not deserialize signature
127    CouldNotDeserializeSignature = 118,
128    /// Type mismatch
129    TypeMismatch = 119,
130    /// Could not sign message
131    CouldNotSignMessage = 120,
132    /// Empty dictionary name
133    EmptyDictionaryName = 121,
134    /// Calling a contract with missing entrypoint arguments.
135    MissingArg = 122,
136    /// Reading the address from the storage failed.
137    MissingAddress = 123,
138    /// Out of gas error
139    OutOfGas = 124,
140    /// Maximum code for user errors
141    MaxUserError = 64535,
142    /// User error too high. The code should be in range 0..32767.
143    UserErrorTooHigh = 64536,
144    /// User error
145    User(u16)
146}
147
148impl ExecutionError {
149    /// Returns the error code.
150    pub fn code(&self) -> u16 {
151        unsafe {
152            match self {
153                ExecutionError::User(code) => *code,
154                ExecutionError::MaxUserError => 64535,
155                ExecutionError::UserErrorTooHigh => 64536,
156                _ => ExecutionError::UserErrorTooHigh.code() + *(self as *const Self as *const u16)
157            }
158        }
159    }
160}
161
162impl From<ExecutionError> for OdraError {
163    fn from(error: ExecutionError) -> Self {
164        Self::ExecutionError(error)
165    }
166}
167
168/// An internal virtual machine error
169#[derive(Clone, Debug, PartialEq, Eq)]
170pub enum VmError {
171    /// Failed to serialize a value.
172    Serialization,
173    /// Failed to deserialize a value.
174    Deserialization,
175    /// Exceeded the account balance
176    BalanceExceeded,
177    /// Non existing host entrypoint was called.
178    NoSuchMethod(String),
179    /// Accessing a contract with an invalid address.
180    InvalidContractAddress,
181    /// Error calling a host function in a wrong context.
182    InvalidContext,
183    /// Calling a contract with a wrong argument type.
184    TypeMismatch {
185        /// Expected type.
186        expected: CLType,
187        /// Found type.
188        found: CLType
189    },
190    /// Non-specified error with a custom message.
191    Other(String),
192    /// Unspecified error.
193    Panic
194}
195
196/// Error that can occur while operating on a collection.
197pub enum CollectionError {
198    /// The requested index is bigger than the max collection index.
199    IndexOutOfBounds
200}
201
202impl From<CollectionError> for ExecutionError {
203    fn from(error: CollectionError) -> Self {
204        match error {
205            CollectionError::IndexOutOfBounds => Self::IndexOutOfBounds
206        }
207    }
208}
209
210impl From<CollectionError> for OdraError {
211    fn from(error: CollectionError) -> Self {
212        Into::<ExecutionError>::into(error).into()
213    }
214}
215
216/// Error that can occur while operating on an Address.
217#[derive(Clone, Debug, PartialEq)]
218pub enum AddressError {
219    /// Tried to construct a zero address.
220    ZeroAddress,
221    /// Tried to construct an address and failed.
222    AddressCreationError
223}
224
225impl From<AddressError> for ExecutionError {
226    fn from(error: AddressError) -> Self {
227        match error {
228            AddressError::ZeroAddress => Self::ZeroAddress,
229            AddressError::AddressCreationError => Self::AddressCreationFailed
230        }
231    }
232}
233
234impl From<AddressError> for OdraError {
235    fn from(error: AddressError) -> Self {
236        Into::<ExecutionError>::into(error).into()
237    }
238}
239
240/// Event-related errors.
241#[derive(Debug, PartialEq, Eq, PartialOrd)]
242pub enum EventError {
243    /// The type of event is different than expected.
244    UnexpectedType(String),
245    /// Index of the event is out of bounds.
246    IndexOutOfBounds,
247    /// Formatting error while deserializing.
248    Formatting,
249    /// Unexpected error while deserializing.
250    Parsing,
251    /// Could not extract event name.
252    CouldntExtractName,
253    /// Could not extract event data.
254    CouldntExtractEventData
255}
256
257/// Represents the result of a contract call.
258pub type OdraResult<T> = Result<T, OdraError>;
259
260impl From<CLValueError> for OdraError {
261    fn from(error: CLValueError) -> Self {
262        match error {
263            CLValueError::Serialization(_) => OdraError::VmError(Serialization),
264            CLValueError::Type(cl_type_mismatch) => OdraError::VmError(VmError::TypeMismatch {
265                expected: cl_type_mismatch.expected.clone(),
266                found: cl_type_mismatch.found.clone()
267            })
268        }
269    }
270}
271
272impl From<BytesReprError> for OdraError {
273    fn from(error: BytesReprError) -> Self {
274        match error {
275            BytesReprError::EarlyEndOfStream => ExecutionError::EarlyEndOfStream,
276            BytesReprError::Formatting => ExecutionError::Formatting,
277            BytesReprError::LeftOverBytes => ExecutionError::LeftOverBytes,
278            BytesReprError::OutOfMemory => ExecutionError::OutOfMemory,
279            BytesReprError::NotRepresentable => ExecutionError::NotRepresentable,
280            BytesReprError::ExceededRecursionDepth => ExecutionError::ExceededRecursionDepth,
281            _ => ExecutionError::Formatting
282        }
283        .into()
284    }
285}