odra_core/
error.rs

1use casper_types::bytesrepr::Error as BytesReprError;
2use casper_types::{CLType, CLValueError};
3use core::any::Any;
4
5use crate::arithmetic::ArithmeticsError;
6use crate::prelude::*;
7use crate::VmError::Serialization;
8
9/// General error type in Odra framework
10#[repr(u16)]
11#[derive(Clone, Debug, PartialEq)]
12pub enum OdraError {
13    /// An error that can occur during smart contract execution
14    ExecutionError(ExecutionError),
15    /// An internal virtual machine error
16    VmError(VmError)
17}
18
19impl OdraError {
20    /// Returns the error code.
21    pub fn code(&self) -> u16 {
22        match self {
23            OdraError::ExecutionError(e) => e.code(),
24            OdraError::VmError(_e) => 0
25        }
26    }
27
28    /// Creates a new user error with a given code.
29    pub fn user(code: u16) -> Self {
30        if code >= ExecutionError::UserErrorTooHigh.code() {
31            ExecutionError::UserErrorTooHigh.into()
32        } else {
33            ExecutionError::User(code).into()
34        }
35    }
36}
37
38impl From<ArithmeticsError> for ExecutionError {
39    fn from(error: ArithmeticsError) -> Self {
40        match error {
41            ArithmeticsError::AdditionOverflow => Self::AdditionOverflow,
42            ArithmeticsError::SubtractingOverflow => Self::SubtractionOverflow,
43            ArithmeticsError::ConversionError => Self::ConversionError
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    /// MainPurse error
141    MainPurseError = 125,
142    /// Conversion error
143    ConversionError = 126,
144    /// Couldn't deploy the contract
145    ContractDeploymentError = 127,
146    /// Couldn't extract caller info
147    CannotExtractCallerInfo = 128,
148    /// Maximum code for user errors
149    MaxUserError = 64535,
150    /// User error too high. The code should be in range 0..32767.
151    UserErrorTooHigh = 64536,
152    /// User error
153    User(u16)
154}
155
156impl ExecutionError {
157    /// Returns the error code.
158    pub fn code(&self) -> u16 {
159        unsafe {
160            match self {
161                ExecutionError::User(code) => *code,
162                ExecutionError::MaxUserError => 64535,
163                ExecutionError::UserErrorTooHigh => 64536,
164                _ => ExecutionError::UserErrorTooHigh.code() + *(self as *const Self as *const u16)
165            }
166        }
167    }
168}
169
170impl From<ExecutionError> for OdraError {
171    fn from(error: ExecutionError) -> Self {
172        Self::ExecutionError(error)
173    }
174}
175
176/// An internal virtual machine error
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub enum VmError {
179    /// Failed to serialize a value.
180    Serialization,
181    /// Failed to deserialize a value.
182    Deserialization,
183    /// Exceeded the account balance
184    BalanceExceeded,
185    /// Non existing host entrypoint was called.
186    NoSuchMethod(String),
187    /// Accessing a contract with an invalid address.
188    InvalidContractAddress,
189    /// Error calling a host function in a wrong context.
190    InvalidContext,
191    /// Calling a contract with a wrong argument type.
192    TypeMismatch {
193        /// Expected type.
194        expected: CLType,
195        /// Found type.
196        found: CLType
197    },
198    /// Non-specified error with a custom message.
199    Other(String),
200    /// Unspecified error.
201    Panic
202}
203
204/// Error that can occur while operating on a collection.
205pub enum CollectionError {
206    /// The requested index is bigger than the max collection index.
207    IndexOutOfBounds
208}
209
210impl From<CollectionError> for ExecutionError {
211    fn from(error: CollectionError) -> Self {
212        match error {
213            CollectionError::IndexOutOfBounds => Self::IndexOutOfBounds
214        }
215    }
216}
217
218impl From<CollectionError> for OdraError {
219    fn from(error: CollectionError) -> Self {
220        Into::<ExecutionError>::into(error).into()
221    }
222}
223
224/// Error that can occur while operating on an Address.
225#[derive(Clone, Debug, PartialEq)]
226pub enum AddressError {
227    /// Tried to construct a zero address.
228    ZeroAddress,
229    /// Tried to construct an address and failed.
230    AddressCreationError
231}
232
233impl From<AddressError> for ExecutionError {
234    fn from(error: AddressError) -> Self {
235        match error {
236            AddressError::ZeroAddress => Self::ZeroAddress,
237            AddressError::AddressCreationError => Self::AddressCreationFailed
238        }
239    }
240}
241
242impl From<AddressError> for OdraError {
243    fn from(error: AddressError) -> Self {
244        Into::<ExecutionError>::into(error).into()
245    }
246}
247
248/// Event-related errors.
249#[derive(Debug, PartialEq, Eq, PartialOrd)]
250pub enum EventError {
251    /// The type of event is different from expected.
252    UnexpectedType(String),
253    /// Index of the event is out of bounds.
254    IndexOutOfBounds,
255    /// Formatting error while deserializing.
256    Formatting,
257    /// Unexpected error while deserializing.
258    Parsing,
259    /// Could not extract event name.
260    CouldntExtractName,
261    /// Could not extract event data.
262    CouldntExtractEventData,
263    /// Contract doesn't support CES events.
264    ContractDoesntSupportEvents,
265    /// Tried to query event for a non-contract entity.
266    TriedToQueryEventForNonContract
267}
268
269/// Represents the result of a contract call.
270pub type OdraResult<T> = Result<T, OdraError>;
271
272impl From<CLValueError> for OdraError {
273    fn from(error: CLValueError) -> Self {
274        match error {
275            CLValueError::Serialization(_) => OdraError::VmError(Serialization),
276            CLValueError::Type(cl_type_mismatch) => OdraError::VmError(VmError::TypeMismatch {
277                expected: cl_type_mismatch.expected.clone(),
278                found: cl_type_mismatch.found.clone()
279            })
280        }
281    }
282}
283
284impl From<BytesReprError> for OdraError {
285    fn from(error: BytesReprError) -> Self {
286        match error {
287            BytesReprError::EarlyEndOfStream => ExecutionError::EarlyEndOfStream,
288            BytesReprError::Formatting => ExecutionError::Formatting,
289            BytesReprError::LeftOverBytes => ExecutionError::LeftOverBytes,
290            BytesReprError::OutOfMemory => ExecutionError::OutOfMemory,
291            BytesReprError::NotRepresentable => ExecutionError::NotRepresentable,
292            BytesReprError::ExceededRecursionDepth => ExecutionError::ExceededRecursionDepth,
293            _ => ExecutionError::Formatting
294        }
295        .into()
296    }
297}
298
299impl From<anyhow::Error> for OdraError {
300    fn from(value: anyhow::Error) -> Self {
301        OdraError::VmError(VmError::Other(value.to_string()))
302    }
303}