1#![no_std]
7#![warn(missing_docs)]
8#![doc(html_logo_url = "https://gear-tech.io/logo.png")]
9#![doc(html_favicon_url = "https://gear-tech.io/favicon.ico")]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11
12extern crate alloc;
13
14use core::fmt::Debug;
15use enum_iterator::Sequence;
16#[cfg(feature = "codec")]
17use {
18 alloc::vec::Vec,
19 parity_scale_codec::{Decode, Encode, Error, Input},
20};
21
22pub use simple::*;
23
24mod simple;
25
26#[repr(u32)]
28#[non_exhaustive]
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
30pub enum ExecutionError {
31 #[error("Not enough gas for operation")]
33 NotEnoughGas = 100,
34
35 #[error("Not enough value for operation")]
37 NotEnoughValue = 101,
38
39 #[error("Length is overflowed to read payload")]
41 TooBigReadLen = 103,
42
43 #[error("Cannot take data in payload range from message with size")]
45 ReadWrongRange = 104,
46
47 #[error("Not running in reply context")]
49 NoReplyContext = 105,
50
51 #[error("Not running in signal context")]
53 NoSignalContext = 106,
54
55 #[error("No status code in reply/signal context")]
57 NoStatusCodeContext = 107,
58
59 #[error("Reply sending is only allowed in `init` and `handle` functions")]
61 IncorrectEntryForReply = 108,
62}
63
64#[repr(u32)]
66#[non_exhaustive]
67#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
68pub enum MemoryError {
69 #[error("Trying to allocate more memory in block-chain runtime than allowed")]
71 RuntimeAllocOutOfBounds = 200,
72 #[error("Trying to access memory outside wasm program memory")]
74 AccessOutOfBounds = 201,
75}
76
77#[repr(u32)]
79#[non_exhaustive]
80#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
81pub enum MessageError {
82 #[error("Max message size exceed")]
84 MaxMessageSizeExceed = 300,
85
86 #[error("Message limit exceeded")]
90 OutgoingMessagesAmountLimitExceeded = 301,
91
92 #[error("Duplicate reply message")]
94 DuplicateReply = 302,
95
96 #[error("Duplicate waking message")]
99 DuplicateWaking = 303,
100
101 #[error("An attempt to commit or push a payload into an already formed message")]
103 LateAccess = 304,
104
105 #[error("Message with given handle is not found")]
107 OutOfBounds = 305,
108
109 #[error("Duplicated program initialization message")]
112 DuplicateInit = 306,
113
114 #[error("In case of non-zero message value must be greater than existential deposit")]
117 InsufficientValue = 307,
118
119 #[error("In case of non-zero message gas limit must be greater than mailbox threshold")]
124 InsufficientGasLimit = 308,
125
126 #[error("Reply deposit already exists for given message")]
129 DuplicateReplyDeposit = 309,
130
131 #[error(
134 "Reply deposit could be only created for init or handle message sent within the execution"
135 )]
136 IncorrectMessageForReplyDeposit = 310,
137
138 #[error("Outgoing messages bytes limit exceeded")]
141 OutgoingMessagesBytesLimitExceeded = 311,
142
143 #[error("Offset value for the input payload is out of it's size bounds")]
146 OutOfBoundsInputSliceOffset = 312,
147
148 #[error("Too big length value is set to form a slice (range) of the input buffer")]
151 OutOfBoundsInputSliceLength = 313,
152
153 #[error("Not enough gas to hold dispatch message")]
156 InsufficientGasForDelayedSending = 399,
157}
158
159#[repr(u32)]
162#[non_exhaustive]
163#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
164pub enum ReservationError {
165 #[error("Invalid reservation ID")]
167 InvalidReservationId = 500,
168 #[error("Reservation limit has reached")]
170 ReservationsLimitReached = 501,
171 #[error("Reservation duration cannot be zero")]
173 ZeroReservationDuration = 502,
174 #[error("Reservation amount cannot be zero")]
176 ZeroReservationAmount = 503,
177 #[error("Reservation amount cannot be below mailbox threshold")]
179 ReservationBelowMailboxThreshold = 504,
180}
181
182#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
184#[non_exhaustive]
185pub enum ExtError {
186 #[error("Execution error: {0}")]
188 Execution(#[from] ExecutionError),
189
190 #[error("Memory error: {0}")]
192 Memory(#[from] MemoryError),
193
194 #[error("Message error: {0}")]
196 Message(#[from] MessageError),
197
198 #[error("Reservation error: {0}")]
200 Reservation(#[from] ReservationError),
201
202 #[error("Unsupported error")]
204 Unsupported,
205}
206
207impl ExtError {
208 pub fn to_u32(self) -> u32 {
210 match self {
211 ExtError::Execution(err) => err as u32,
212 ExtError::Memory(err) => err as u32,
213 ExtError::Message(err) => err as u32,
214 ExtError::Reservation(err) => err as u32,
215 ExtError::Unsupported => u32::MAX,
216 }
217 }
218
219 pub fn from_u32(code: u32) -> Option<Self> {
221 match code {
222 100 => Some(ExecutionError::NotEnoughGas.into()),
223 101 => Some(ExecutionError::NotEnoughValue.into()),
224 103 => Some(ExecutionError::TooBigReadLen.into()),
225 104 => Some(ExecutionError::ReadWrongRange.into()),
226 105 => Some(ExecutionError::NoReplyContext.into()),
227 106 => Some(ExecutionError::NoSignalContext.into()),
228 107 => Some(ExecutionError::NoStatusCodeContext.into()),
229 108 => Some(ExecutionError::IncorrectEntryForReply.into()),
230 200 => Some(MemoryError::RuntimeAllocOutOfBounds.into()),
232 201 => Some(MemoryError::AccessOutOfBounds.into()),
233 300 => Some(MessageError::MaxMessageSizeExceed.into()),
235 301 => Some(MessageError::OutgoingMessagesAmountLimitExceeded.into()),
236 302 => Some(MessageError::DuplicateReply.into()),
237 303 => Some(MessageError::DuplicateWaking.into()),
238 304 => Some(MessageError::LateAccess.into()),
239 305 => Some(MessageError::OutOfBounds.into()),
240 306 => Some(MessageError::DuplicateInit.into()),
241 307 => Some(MessageError::InsufficientValue.into()),
242 308 => Some(MessageError::InsufficientGasLimit.into()),
243 309 => Some(MessageError::DuplicateReplyDeposit.into()),
244 310 => Some(MessageError::IncorrectMessageForReplyDeposit.into()),
245 311 => Some(MessageError::OutgoingMessagesBytesLimitExceeded.into()),
246 312 => Some(MessageError::OutOfBoundsInputSliceOffset.into()),
247 313 => Some(MessageError::OutOfBoundsInputSliceLength.into()),
248 399 => Some(MessageError::InsufficientGasForDelayedSending.into()),
249 500 => Some(ReservationError::InvalidReservationId.into()),
251 501 => Some(ReservationError::ReservationsLimitReached.into()),
252 502 => Some(ReservationError::ZeroReservationDuration.into()),
253 503 => Some(ReservationError::ZeroReservationAmount.into()),
254 504 => Some(ReservationError::ReservationBelowMailboxThreshold.into()),
255 0xffff |
257 600 |
258 u32::MAX => Some(ExtError::Unsupported),
259 _ => None,
260 }
261 }
262}
263
264#[cfg(feature = "codec")]
265impl Encode for ExtError {
266 fn encode(&self) -> Vec<u8> {
267 ExtError::to_u32(*self).to_le_bytes().to_vec()
268 }
269}
270
271#[cfg(feature = "codec")]
272impl Decode for ExtError {
273 fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
274 let mut code = [0; 4];
275 input.read(&mut code)?;
276 let err =
277 ExtError::from_u32(u32::from_le_bytes(code)).ok_or("Failed to decode error code")?;
278 Ok(err)
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use alloc::collections::BTreeMap;
286
287 #[test]
288 fn error_codes_are_unique() {
289 let mut codes = BTreeMap::new();
290
291 for err in enum_iterator::all::<ExtError>() {
292 let code = err.to_u32();
293 if let Some(same_code_err) = codes.insert(code, err) {
294 panic!("{:?} has same code {:?} as {:?}", same_code_err, code, err);
295 }
296 }
297 }
298
299 #[test]
300 fn encode_decode() {
301 for err in enum_iterator::all::<ExtError>() {
302 let code = err.to_u32();
303 let decoded = ExtError::from_u32(code)
304 .unwrap_or_else(|| unreachable!("failed to decode error code: {}", code));
305 assert_eq!(err, decoded);
306 }
307 }
308
309 #[test]
310 fn error_code_no_specific_value() {
311 for err in enum_iterator::all::<ExtError>() {
312 let code = err.to_u32();
313 assert_ne!(code, 0); }
315 }
316
317 #[test]
327 fn error_codes_forbidden() {
328 let codes = [
329 0xffff, 600, ];
332
333 for code in codes {
335 let err = ExtError::from_u32(code);
336 assert_eq!(err, Some(ExtError::Unsupported));
337 }
338
339 for err in enum_iterator::all::<ExtError>() {
341 let code = err.to_u32();
342 assert!(!codes.contains(&code));
343 }
344 }
345}