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    /// Encountered a host function error.
131    #[error("internal host")]
132    InternalHost,
133}
134
135impl CallError {
136    /// Converts the host error into a u32.
137    #[must_use]
138    pub fn into_u32(self) -> u32 {
139        match self {
140            Self::CalleeReverted => CALLEE_REVERTED,
141            Self::CalleeTrapped(_) => CALLEE_TRAPPED,
142            Self::CalleeGasDepleted => CALLEE_GAS_DEPLETED,
143            Self::NotCallable => CALLEE_NOT_CALLABLE,
144            Self::InternalHost => CALLEE_HOST_ERROR,
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn test_from_u32_not_found() {
155        let error = CommonResult::from(HOST_ERROR_NOT_FOUND);
156        assert_eq!(error, CommonResult::NotFound);
157    }
158
159    #[test]
160    fn test_from_u32_invalid_data() {
161        let error = CommonResult::from(HOST_ERROR_INVALID_DATA);
162        assert_eq!(error, CommonResult::InvalidData);
163    }
164
165    #[test]
166    fn test_from_u32_invalid_input() {
167        let error = CommonResult::from(HOST_ERROR_INVALID_INPUT);
168        assert_eq!(error, CommonResult::InvalidInput);
169    }
170
171    #[test]
172    fn test_from_u32_other() {
173        let error = CommonResult::from(10);
174        assert_eq!(error, CommonResult::Other(10));
175    }
176}