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;
111
112/// Represents the result of a host function call.
113///
114/// 0 is used as a success.
115#[derive(Debug, Error)]
116pub enum CallError {
117    /// Callee contract reverted.
118    #[error("callee reverted")]
119    CalleeReverted,
120    /// Called contract trapped.
121    #[error("callee trapped: {0}")]
122    CalleeTrapped(TrapCode),
123    /// Called contract reached gas limit.
124    #[error("callee gas depleted")]
125    CalleeGasDepleted,
126    /// Called contract is not callable.
127    #[error("not callable")]
128    NotCallable,
129}
130
131impl CallError {
132    /// Converts the host error into a u32.
133    #[must_use]
134    pub fn into_u32(self) -> u32 {
135        match self {
136            Self::CalleeReverted => CALLEE_REVERTED,
137            Self::CalleeTrapped(_) => CALLEE_TRAPPED,
138            Self::CalleeGasDepleted => CALLEE_GAS_DEPLETED,
139            Self::NotCallable => CALLEE_NOT_CALLABLE,
140        }
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_from_u32_not_found() {
150        let error = CommonResult::from(HOST_ERROR_NOT_FOUND);
151        assert_eq!(error, CommonResult::NotFound);
152    }
153
154    #[test]
155    fn test_from_u32_invalid_data() {
156        let error = CommonResult::from(HOST_ERROR_INVALID_DATA);
157        assert_eq!(error, CommonResult::InvalidData);
158    }
159
160    #[test]
161    fn test_from_u32_invalid_input() {
162        let error = CommonResult::from(HOST_ERROR_INVALID_INPUT);
163        assert_eq!(error, CommonResult::InvalidInput);
164    }
165
166    #[test]
167    fn test_from_u32_other() {
168        let error = CommonResult::from(10);
169        assert_eq!(error, CommonResult::Other(10));
170    }
171}