casper_executor_wasm_common/
error.rs

1//! Error code for signaling error while processing a host function.
2//!
3//! API inspired by `std::io::Error` and `std::io::ErrorKind` but somewhat more memory efficient.
4
5use thiserror::Error;
6
7#[derive(Debug, Default, PartialEq)]
8#[non_exhaustive]
9#[repr(u32)]
10pub enum CommonResult {
11    #[default]
12    Success = 0,
13    /// An entity was not found, often a missing key in the global state.
14    NotFound = 1,
15    /// Data not valid for the operation were encountered.
16    ///
17    /// As an example this could be a malformed parameter that does not contain a valid UTF-8.
18    InvalidData = 2,
19    /// The input to the host function was invalid.
20    InvalidInput = 3,
21    /// The topic is too long.
22    TopicTooLong = 4,
23    /// Too many topics.
24    TooManyTopics = 5,
25    /// The payload is too long.
26    PayloadTooLong = 6,
27    /// The message topic is full and cannot accept new messages.
28    MessageTopicFull = 7,
29    /// The maximum number of messages emitted per block was exceeded when trying to emit a
30    /// message.
31    MaxMessagesPerBlockExceeded = 8,
32    /// Internal error (for example, failed to acquire a lock)
33    Internal = 9,
34    /// An error code not covered by the other variants.
35    Other(u32),
36}
37
38pub const HOST_ERROR_SUCCESS: u32 = 0;
39pub const HOST_ERROR_NOT_FOUND: u32 = 1;
40pub const HOST_ERROR_INVALID_DATA: u32 = 2;
41pub const HOST_ERROR_INVALID_INPUT: u32 = 3;
42pub const HOST_ERROR_TOPIC_TOO_LONG: u32 = 4;
43pub const HOST_ERROR_TOO_MANY_TOPICS: u32 = 5;
44pub const HOST_ERROR_PAYLOAD_TOO_LONG: u32 = 6;
45pub const HOST_ERROR_MESSAGE_TOPIC_FULL: u32 = 7;
46pub const HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED: u32 = 8;
47pub const HOST_ERROR_INTERNAL: u32 = 9;
48
49impl From<u32> for CommonResult {
50    fn from(value: u32) -> Self {
51        match value {
52            HOST_ERROR_SUCCESS => Self::Success,
53            HOST_ERROR_NOT_FOUND => Self::NotFound,
54            HOST_ERROR_INVALID_DATA => Self::InvalidData,
55            HOST_ERROR_INVALID_INPUT => Self::InvalidInput,
56            HOST_ERROR_TOPIC_TOO_LONG => Self::TopicTooLong,
57            HOST_ERROR_TOO_MANY_TOPICS => Self::TooManyTopics,
58            HOST_ERROR_PAYLOAD_TOO_LONG => Self::PayloadTooLong,
59            HOST_ERROR_MESSAGE_TOPIC_FULL => Self::MessageTopicFull,
60            HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED => Self::MaxMessagesPerBlockExceeded,
61            HOST_ERROR_INTERNAL => Self::Internal,
62            other => Self::Other(other),
63        }
64    }
65}
66
67pub fn result_from_code(code: u32) -> Result<(), CommonResult> {
68    match code {
69        HOST_ERROR_SUCCESS => Ok(()),
70        other => Err(CommonResult::from(other)),
71    }
72}
73
74/// Wasm trap code.
75#[derive(Debug, Error)]
76pub enum TrapCode {
77    /// Trap code for out of bounds memory access.
78    #[error("call stack exhausted")]
79    StackOverflow,
80    /// Trap code for out of bounds memory access.
81    #[error("out of bounds memory access")]
82    MemoryOutOfBounds,
83    /// Trap code for out of bounds table access.
84    #[error("undefined element: out of bounds table access")]
85    TableAccessOutOfBounds,
86    /// Trap code for indirect call to null.
87    #[error("uninitialized element")]
88    IndirectCallToNull,
89    /// Trap code for indirect call type mismatch.
90    #[error("indirect call type mismatch")]
91    BadSignature,
92    /// Trap code for integer overflow.
93    #[error("integer overflow")]
94    IntegerOverflow,
95    /// Trap code for division by zero.
96    #[error("integer divide by zero")]
97    IntegerDivisionByZero,
98    /// Trap code for invalid conversion to integer.
99    #[error("invalid conversion to integer")]
100    BadConversionToInteger,
101    /// Trap code for unreachable code reached triggered by unreachable instruction.
102    #[error("unreachable")]
103    UnreachableCodeReached,
104}
105
106pub const CALLEE_SUCCEEDED: u32 = 0;
107pub const CALLEE_REVERTED: u32 = 1;
108pub const CALLEE_TRAPPED: u32 = 2;
109pub const CALLEE_GAS_DEPLETED: u32 = 3;
110pub const CALLEE_NOT_CALLABLE: u32 = 4;
111pub const CALLEE_HOST_ERROR: u32 = 5;
112
113/// Represents the result of a host function call.
114///
115/// 0 is used as a success.
116#[derive(Debug, Error)]
117pub enum CallError {
118    /// Callee contract reverted.
119    #[error("callee reverted")]
120    CalleeReverted,
121    /// Called contract trapped.
122    #[error("callee trapped: {0}")]
123    CalleeTrapped(TrapCode),
124    /// Called contract reached gas limit.
125    #[error("callee gas depleted")]
126    CalleeGasDepleted,
127    /// Called contract is not callable.
128    #[error("not callable")]
129    NotCallable,
130}
131
132impl CallError {
133    /// Converts the host error into a u32.
134    #[must_use]
135    pub fn into_u32(self) -> u32 {
136        match self {
137            Self::CalleeReverted => CALLEE_REVERTED,
138            Self::CalleeTrapped(_) => CALLEE_TRAPPED,
139            Self::CalleeGasDepleted => CALLEE_GAS_DEPLETED,
140            Self::NotCallable => CALLEE_NOT_CALLABLE,
141        }
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_from_u32_not_found() {
151        let error = CommonResult::from(HOST_ERROR_NOT_FOUND);
152        assert_eq!(error, CommonResult::NotFound);
153    }
154
155    #[test]
156    fn test_from_u32_invalid_data() {
157        let error = CommonResult::from(HOST_ERROR_INVALID_DATA);
158        assert_eq!(error, CommonResult::InvalidData);
159    }
160
161    #[test]
162    fn test_from_u32_invalid_input() {
163        let error = CommonResult::from(HOST_ERROR_INVALID_INPUT);
164        assert_eq!(error, CommonResult::InvalidInput);
165    }
166
167    #[test]
168    fn test_from_u32_other() {
169        let error = CommonResult::from(10);
170        assert_eq!(error, CommonResult::Other(10));
171    }
172}