1use actor_system_error::actor_system_error;
20use codec::{Decode, Encode};
21use gear_core::{
22 gas::{ChargeError, CounterType},
23 ids::ProgramId,
24 message::MessageWaitedType,
25 str::LimitedStr,
26};
27use gear_core_errors::ExtError as FallibleExtError;
28
29actor_system_error! {
30 pub type TerminationReason = ActorSystemError<ActorTerminationReason, SystemTerminationReason>;
31}
32
33#[derive(Debug, Clone, Eq, PartialEq, derive_more::From)]
34pub enum UndefinedTerminationReason {
35 Actor(ActorTerminationReason),
36 System(SystemTerminationReason),
37 ProcessAccessErrorResourcesExceed,
39}
40
41impl UndefinedTerminationReason {
42 pub fn define(self, current_counter: CounterType) -> TerminationReason {
43 match self {
44 Self::Actor(r) => r.into(),
45 Self::System(r) => r.into(),
46 Self::ProcessAccessErrorResourcesExceed => {
47 ActorTerminationReason::from(current_counter).into()
48 }
49 }
50 }
51}
52
53impl From<ChargeError> for UndefinedTerminationReason {
54 fn from(err: ChargeError) -> Self {
55 match err {
56 ChargeError::GasLimitExceeded => {
57 ActorTerminationReason::Trap(TrapExplanation::GasLimitExceeded).into()
58 }
59 ChargeError::GasAllowanceExceeded => {
60 ActorTerminationReason::GasAllowanceExceeded.into()
61 }
62 }
63 }
64}
65
66impl From<TrapExplanation> for UndefinedTerminationReason {
67 fn from(trap: TrapExplanation) -> Self {
68 ActorTerminationReason::Trap(trap).into()
69 }
70}
71
72impl<E: BackendSyscallError> From<E> for UndefinedTerminationReason {
73 fn from(err: E) -> Self {
74 err.into_termination_reason()
75 }
76}
77
78#[derive(Decode, Encode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, derive_more::From)]
79#[codec(crate = codec)]
80pub enum ActorTerminationReason {
81 Exit(ProgramId),
82 Leave,
83 Success,
84 Wait(Option<u32>, MessageWaitedType),
85 GasAllowanceExceeded,
86 #[from]
87 Trap(TrapExplanation),
88}
89
90impl From<CounterType> for ActorTerminationReason {
91 fn from(counter_type: CounterType) -> Self {
92 match counter_type {
93 CounterType::GasLimit => Self::Trap(TrapExplanation::GasLimitExceeded),
94 CounterType::GasAllowance => Self::GasAllowanceExceeded,
95 }
96 }
97}
98
99#[derive(Debug, Clone, Eq, PartialEq, derive_more::Display)]
105pub struct SystemTerminationReason;
106
107#[derive(
109 Decode,
110 Encode,
111 Debug,
112 Clone,
113 Eq,
114 PartialEq,
115 PartialOrd,
116 Ord,
117 derive_more::Display,
118 derive_more::From,
119)]
120#[codec(crate = codec)]
121pub enum UnrecoverableExecutionError {
122 #[display(fmt = "Invalid debug string passed in `gr_debug` syscall")]
123 InvalidDebugString,
124 #[display(fmt = "Not enough gas for operation")]
125 NotEnoughGas,
126 #[display(fmt = "Length is overflowed to read payload")]
127 TooBigReadLen,
128 #[display(fmt = "Cannot take data in payload range from message with size")]
129 ReadWrongRange,
130 #[display(fmt = "Unsupported version of environment variables encountered")]
131 UnsupportedEnvVarsVersion,
132}
133
134#[derive(
136 Decode,
137 Encode,
138 Debug,
139 Clone,
140 Eq,
141 PartialEq,
142 PartialOrd,
143 Ord,
144 derive_more::Display,
145 derive_more::From,
146)]
147#[codec(crate = codec)]
148pub enum UnrecoverableMemoryError {
149 #[display(fmt = "Trying to access memory outside wasm program memory")]
151 AccessOutOfBounds,
152 #[display(fmt = "Trying to allocate more memory in block-chain runtime than allowed")]
154 RuntimeAllocOutOfBounds,
155}
156
157#[derive(
159 Decode,
160 Encode,
161 Debug,
162 Clone,
163 Eq,
164 PartialEq,
165 PartialOrd,
166 Ord,
167 derive_more::Display,
168 derive_more::From,
169)]
170#[codec(crate = codec)]
171pub enum UnrecoverableWaitError {
172 #[display(fmt = "Waiting duration cannot be zero")]
174 ZeroDuration,
175 #[display(fmt = "`wait()` is not allowed after reply sent")]
177 WaitAfterReply,
178}
179
180#[derive(
181 Decode,
182 Encode,
183 Debug,
184 Clone,
185 Eq,
186 PartialEq,
187 PartialOrd,
188 Ord,
189 derive_more::Display,
190 derive_more::From,
191)]
192#[codec(crate = codec)]
193pub enum UnrecoverableExtError {
194 #[display(fmt = "Execution error: {_0}")]
195 Execution(UnrecoverableExecutionError),
196 #[display(fmt = "Memory error: {_0}")]
197 Memory(UnrecoverableMemoryError),
198 #[display(fmt = "Waiting error: {_0}")]
199 Wait(UnrecoverableWaitError),
200}
201
202#[derive(
203 Decode,
204 Encode,
205 Debug,
206 Clone,
207 PartialEq,
208 Eq,
209 PartialOrd,
210 Ord,
211 derive_more::Display,
212 derive_more::From,
213)]
214#[codec(crate = codec)]
215pub enum TrapExplanation {
216 #[display(fmt = "Not enough gas to continue execution")]
218 GasLimitExceeded,
219 #[display(fmt = "Unable to call a forbidden function")]
221 ForbiddenFunction,
222 #[display(fmt = "Trying to allocate more wasm program memory than allowed")]
225 ProgramAllocOutOfBounds,
226 #[display(fmt = "Syscall unrecoverable error: {_0}")]
227 UnrecoverableExt(UnrecoverableExtError),
228 #[display(fmt = "Panic occurred: {_0}")]
229 Panic(LimitedStr<'static>),
230 #[display(fmt = "Stack limit exceeded")]
231 StackLimitExceeded,
232 #[display(fmt = "Reason is unknown. Possibly `unreachable` instruction is occurred")]
233 Unknown,
234}
235
236#[derive(Debug, Clone)]
238pub enum RunFallibleError {
239 UndefinedTerminationReason(UndefinedTerminationReason),
240 FallibleExt(FallibleExtError),
241}
242
243impl<E> From<E> for RunFallibleError
244where
245 E: BackendSyscallError,
246{
247 fn from(err: E) -> Self {
248 err.into_run_fallible_error()
249 }
250}
251
252pub trait BackendSyscallError: Sized {
255 fn into_termination_reason(self) -> UndefinedTerminationReason;
256
257 fn into_run_fallible_error(self) -> RunFallibleError;
258}
259
260pub trait BackendAllocSyscallError: Sized {
265 type ExtError: BackendSyscallError;
266
267 fn into_backend_error(self) -> Result<Self::ExtError, Self>;
268}