1use enum_iterator::Sequence;
20#[cfg(feature = "serde")]
21use serde::{Deserialize, Serialize};
22#[cfg(feature = "codec")]
23use {
24 parity_scale_codec::{Decode, Encode},
25 scale_decode::DecodeAsType,
26 scale_encode::EncodeAsType,
27 scale_info::TypeInfo,
28};
29
30#[repr(u8)]
32#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
33#[cfg_attr(
34 feature = "codec",
35 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
36)]
37#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
38pub enum ReplyCode {
39 #[error("Success reply sent due to {0}")]
41 Success(#[from] SuccessReplyReason) = 0,
42
43 #[error("Error reply sent due to {0}")]
45 Error(#[from] ErrorReplyReason) = 1,
46
47 #[error("<unsupported reply code>")]
50 Unsupported = 255,
51}
52
53impl ReplyCode {
54 fn discriminant(&self) -> u8 {
55 unsafe { *<*const _>::from(self).cast::<u8>() }
59 }
60
61 pub fn to_bytes(self) -> [u8; 4] {
63 let mut bytes = [self.discriminant(), 0, 0, 0];
64
65 match self {
66 Self::Success(reason) => bytes[1..].copy_from_slice(&reason.to_bytes()),
67 Self::Error(reason) => bytes[1..].copy_from_slice(&reason.to_bytes()),
68 Self::Unsupported => {}
69 }
70
71 bytes
72 }
73
74 pub fn from_bytes(bytes: [u8; 4]) -> Self {
76 match bytes[0] {
77 b if Self::Success(SuccessReplyReason::Unsupported).discriminant() == b => {
78 let reason_bytes = bytes[1..].try_into().unwrap_or_else(|_| unreachable!());
79 Self::Success(SuccessReplyReason::from_bytes(reason_bytes))
80 }
81 b if Self::Error(ErrorReplyReason::Unsupported).discriminant() == b => {
82 let reason_bytes = bytes[1..].try_into().unwrap_or_else(|_| unreachable!());
83 Self::Error(ErrorReplyReason::from_bytes(reason_bytes))
84 }
85 _ => Self::Unsupported,
86 }
87 }
88
89 pub fn error(reason: impl Into<ErrorReplyReason>) -> Self {
91 Self::Error(reason.into())
92 }
93
94 pub fn is_success(&self) -> bool {
96 matches!(self, Self::Success(_))
97 }
98
99 pub fn is_error(&self) -> bool {
101 matches!(self, Self::Error(_))
102 }
103
104 pub fn is_unsupported(&self) -> bool {
106 matches!(self, Self::Unsupported)
107 }
108}
109
110#[repr(u8)]
112#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
113#[cfg_attr(
114 feature = "codec",
115 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
116)]
117#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
118pub enum SuccessReplyReason {
119 #[error("automatic sending")]
121 Auto = 0,
122
123 #[error("manual sending")]
125 Manual = 1,
126
127 #[error("<unsupported reason>")]
130 Unsupported = 255,
131}
132
133impl SuccessReplyReason {
134 fn to_bytes(self) -> [u8; 3] {
135 [self as u8, 0, 0]
136 }
137
138 fn from_bytes(bytes: [u8; 3]) -> Self {
139 match bytes[0] {
140 b if Self::Auto as u8 == b => Self::Auto,
141 b if Self::Manual as u8 == b => Self::Manual,
142 _ => Self::Unsupported,
143 }
144 }
145}
146
147#[repr(u8)]
151#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
152#[cfg_attr(
153 feature = "codec",
154 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
155)]
156#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
157pub enum ErrorReplyReason {
158 #[error("execution error ({0})")]
160 Execution(#[from] SimpleExecutionError) = 0,
161
162 #[error("destination actor is unavailable ({0})")]
164 UnavailableActor(#[from] SimpleUnavailableActorError) = 2,
165
166 #[error("removal from waitlist")]
168 RemovedFromWaitlist = 3,
169
170 #[error("<unsupported reason>")]
173 Unsupported = 255,
174}
175
176impl ErrorReplyReason {
177 pub fn is_exited(&self) -> bool {
179 matches!(
180 self,
181 Self::UnavailableActor(SimpleUnavailableActorError::ProgramExited)
182 )
183 }
184
185 pub fn is_userspace_panic(&self) -> bool {
187 matches!(self, Self::Execution(SimpleExecutionError::UserspacePanic))
188 }
189
190 fn discriminant(&self) -> u8 {
191 unsafe { *<*const _>::from(self).cast::<u8>() }
195 }
196
197 fn to_bytes(self) -> [u8; 3] {
198 let mut bytes = [self.discriminant(), 0, 0];
199
200 match self {
201 Self::Execution(error) => bytes[1..].copy_from_slice(&error.to_bytes()),
202 Self::UnavailableActor(error) => bytes[1..].copy_from_slice(&error.to_bytes()),
203 Self::RemovedFromWaitlist | Self::Unsupported => {}
204 }
205
206 bytes
207 }
208
209 fn from_bytes(bytes: [u8; 3]) -> Self {
210 match bytes[0] {
211 1 |
212 4 => Self::Unsupported,
213 b if Self::Execution(SimpleExecutionError::Unsupported).discriminant() == b => {
214 let err_bytes = bytes[1..].try_into().unwrap_or_else(|_| unreachable!());
215 Self::Execution(SimpleExecutionError::from_bytes(err_bytes))
216 }
217 b if Self::UnavailableActor(SimpleUnavailableActorError::Unsupported).discriminant() == b => {
218 let err_bytes = bytes[1..].try_into().unwrap_or_else(|_| unreachable!());
219 Self::UnavailableActor(SimpleUnavailableActorError::from_bytes(err_bytes))
220 }
221 b if Self::RemovedFromWaitlist.discriminant() == b => Self::RemovedFromWaitlist,
222 _ => Self::Unsupported,
223 }
224 }
225}
226
227#[repr(u8)]
229#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
230#[cfg_attr(
231 feature = "codec",
232 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
233)]
234#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
235pub enum SimpleExecutionError {
236 #[error("Message ran out of gas")]
238 RanOutOfGas = 0,
239
240 #[error("Program reached memory limit")]
242 MemoryOverflow = 1,
243
244 #[error("Message ran into uncatchable error")]
246 BackendError = 2,
247
248 #[error("Message panicked")]
252 UserspacePanic = 3,
253
254 #[error("Program called WASM `unreachable` instruction")]
256 UnreachableInstruction = 4,
257
258 #[error("Program reached stack limit")]
260 StackLimitExceeded = 5,
261
262 #[error("<unsupported error>")]
265 Unsupported = 255,
266}
267
268impl SimpleExecutionError {
269 fn to_bytes(self) -> [u8; 2] {
270 [self as u8, 0]
271 }
272
273 fn from_bytes(bytes: [u8; 2]) -> Self {
274 match bytes[0] {
275 b if Self::RanOutOfGas as u8 == b => Self::RanOutOfGas,
276 b if Self::MemoryOverflow as u8 == b => Self::MemoryOverflow,
277 b if Self::BackendError as u8 == b => Self::BackendError,
278 b if Self::UserspacePanic as u8 == b => Self::UserspacePanic,
279 b if Self::UnreachableInstruction as u8 == b => Self::UnreachableInstruction,
280 b if Self::StackLimitExceeded as u8 == b => Self::StackLimitExceeded,
281 _ => Self::Unsupported,
282 }
283 }
284}
285
286#[repr(u8)]
288#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
289#[cfg_attr(
290 feature = "codec",
291 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
292)]
293#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
294pub enum SimpleUnavailableActorError {
295 #[error("Program exited")]
299 ProgramExited = 0,
300
301 #[error("Program was terminated due failed initialization")]
303 InitializationFailure = 1,
304
305 #[error("Program is not initialized yet")]
307 Uninitialized = 2,
308
309 #[error("Program was not created")]
311 ProgramNotCreated = 3,
312
313 #[error("Program re-instrumentation failed")]
315 ReinstrumentationFailure = 4,
316
317 #[error("<unsupported error>")]
320 Unsupported = 255,
321}
322
323impl SimpleUnavailableActorError {
324 fn to_bytes(self) -> [u8; 2] {
325 [self as u8, 0]
326 }
327
328 fn from_bytes(bytes: [u8; 2]) -> Self {
329 match bytes[0] {
330 b if Self::ProgramExited as u8 == b => Self::ProgramExited,
331 b if Self::InitializationFailure as u8 == b => Self::InitializationFailure,
332 b if Self::Uninitialized as u8 == b => Self::Uninitialized,
333 b if Self::ProgramNotCreated as u8 == b => Self::ProgramNotCreated,
334 b if Self::ReinstrumentationFailure as u8 == b => Self::ReinstrumentationFailure,
335 _ => Self::Unsupported,
336 }
337 }
338}
339
340#[repr(u8)]
345#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Sequence, thiserror::Error)]
346#[cfg_attr(
347 feature = "codec",
348 derive(Encode, EncodeAsType, Decode, DecodeAsType, TypeInfo)
349)]
350#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
351pub enum SignalCode {
352 #[error("Signal message sent due to execution error ({0})")]
354 Execution(#[from] SimpleExecutionError),
355
356 #[error("Signal message sent due to removal from waitlist")]
358 RemovedFromWaitlist,
359}
360
361impl SignalCode {
362 pub const fn to_u32(self) -> u32 {
364 match self {
365 Self::Execution(SimpleExecutionError::UserspacePanic) => 100,
366 Self::Execution(SimpleExecutionError::RanOutOfGas) => 101,
367 Self::Execution(SimpleExecutionError::BackendError) => 102,
368 Self::Execution(SimpleExecutionError::MemoryOverflow) => 103,
369 Self::Execution(SimpleExecutionError::UnreachableInstruction) => 104,
370 Self::Execution(SimpleExecutionError::StackLimitExceeded) => 105,
371 Self::RemovedFromWaitlist => 200,
372 Self::Execution(SimpleExecutionError::Unsupported) => u32::MAX,
374 }
375 }
376
377 pub const fn from_u32(num: u32) -> Option<Self> {
379 let res = match num {
380 v if Self::Execution(SimpleExecutionError::UserspacePanic).to_u32() == v => {
381 Self::Execution(SimpleExecutionError::UserspacePanic)
382 }
383 v if Self::Execution(SimpleExecutionError::RanOutOfGas).to_u32() == v => {
384 Self::Execution(SimpleExecutionError::RanOutOfGas)
385 }
386 v if Self::Execution(SimpleExecutionError::BackendError).to_u32() == v => {
387 Self::Execution(SimpleExecutionError::BackendError)
388 }
389 v if Self::Execution(SimpleExecutionError::MemoryOverflow).to_u32() == v => {
390 Self::Execution(SimpleExecutionError::MemoryOverflow)
391 }
392 v if Self::Execution(SimpleExecutionError::UnreachableInstruction).to_u32() == v => {
393 Self::Execution(SimpleExecutionError::UnreachableInstruction)
394 }
395 v if Self::Execution(SimpleExecutionError::StackLimitExceeded).to_u32() == v => {
396 Self::Execution(SimpleExecutionError::StackLimitExceeded)
397 }
398 v if Self::Execution(SimpleExecutionError::Unsupported).to_u32() == v => {
399 Self::Execution(SimpleExecutionError::Unsupported)
400 }
401 v if Self::RemovedFromWaitlist.to_u32() == v => Self::RemovedFromWaitlist,
402 _ => return None,
403 };
404
405 Some(res)
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412
413 #[test]
414 fn test_forbidden_codes() {
415 let codes = [
416 1, 4, ];
419
420 for code in codes {
422 let err = ErrorReplyReason::from_bytes([code, 0, 0]);
423 assert_eq!(err, ErrorReplyReason::Unsupported);
424 }
425
426 for code in enum_iterator::all::<ErrorReplyReason>() {
428 let bytes = code.to_bytes();
429 assert!(!codes.contains(&bytes[0]));
430 }
431 }
432
433 #[test]
434 fn test_reply_code_encode_decode() {
435 for code in enum_iterator::all::<ReplyCode>() {
436 let bytes = code.to_bytes();
437 assert_eq!(code, ReplyCode::from_bytes(bytes));
438 }
439 }
440
441 #[test]
442 fn test_signal_code_encode_decode() {
443 for signal in enum_iterator::all::<SignalCode>() {
444 let code = signal.to_u32();
445 assert_eq!(signal, SignalCode::from_u32(code).unwrap());
446 }
447 }
448}