use actor_system_error::actor_system_error;
use codec::{Decode, Encode};
use gear_core::{
gas::{ChargeError, CounterType},
ids::ProgramId,
message::MessageWaitedType,
str::LimitedStr,
};
use gear_core_errors::ExtError as FallibleExtError;
actor_system_error! {
pub type TerminationReason = ActorSystemError<ActorTerminationReason, SystemTerminationReason>;
}
#[derive(Debug, Clone, Eq, PartialEq, derive_more::From)]
pub enum UndefinedTerminationReason {
Actor(ActorTerminationReason),
System(SystemTerminationReason),
ProcessAccessErrorResourcesExceed,
}
impl UndefinedTerminationReason {
pub fn define(self, current_counter: CounterType) -> TerminationReason {
match self {
Self::Actor(r) => r.into(),
Self::System(r) => r.into(),
Self::ProcessAccessErrorResourcesExceed => {
ActorTerminationReason::from(current_counter).into()
}
}
}
}
impl From<ChargeError> for UndefinedTerminationReason {
fn from(err: ChargeError) -> Self {
match err {
ChargeError::GasLimitExceeded => {
ActorTerminationReason::Trap(TrapExplanation::GasLimitExceeded).into()
}
ChargeError::GasAllowanceExceeded => {
ActorTerminationReason::GasAllowanceExceeded.into()
}
}
}
}
impl From<TrapExplanation> for UndefinedTerminationReason {
fn from(trap: TrapExplanation) -> Self {
ActorTerminationReason::Trap(trap).into()
}
}
impl<E: BackendSyscallError> From<E> for UndefinedTerminationReason {
fn from(err: E) -> Self {
err.into_termination_reason()
}
}
#[derive(Decode, Encode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, derive_more::From)]
#[codec(crate = codec)]
pub enum ActorTerminationReason {
Exit(ProgramId),
Leave,
Success,
Wait(Option<u32>, MessageWaitedType),
GasAllowanceExceeded,
#[from]
Trap(TrapExplanation),
}
impl From<CounterType> for ActorTerminationReason {
fn from(counter_type: CounterType) -> Self {
match counter_type {
CounterType::GasLimit => Self::Trap(TrapExplanation::GasLimitExceeded),
CounterType::GasAllowance => Self::GasAllowanceExceeded,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, derive_more::Display)]
pub struct SystemTerminationReason;
#[derive(
Decode,
Encode,
Debug,
Clone,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::Display,
derive_more::From,
)]
#[codec(crate = codec)]
pub enum UnrecoverableExecutionError {
#[display(fmt = "Invalid debug string passed in `gr_debug` syscall")]
InvalidDebugString,
#[display(fmt = "Not enough gas for operation")]
NotEnoughGas,
#[display(fmt = "Length is overflowed to read payload")]
TooBigReadLen,
#[display(fmt = "Cannot take data in payload range from message with size")]
ReadWrongRange,
#[display(fmt = "Unsupported version of environment variables encountered")]
UnsupportedEnvVarsVersion,
}
#[derive(
Decode,
Encode,
Debug,
Clone,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::Display,
derive_more::From,
)]
#[codec(crate = codec)]
pub enum UnrecoverableMemoryError {
#[display(fmt = "Trying to access memory outside wasm program memory")]
AccessOutOfBounds,
#[display(fmt = "Trying to allocate more memory in block-chain runtime than allowed")]
RuntimeAllocOutOfBounds,
}
#[derive(
Decode,
Encode,
Debug,
Clone,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::Display,
derive_more::From,
)]
#[codec(crate = codec)]
pub enum UnrecoverableWaitError {
#[display(fmt = "Waiting duration cannot be zero")]
ZeroDuration,
#[display(fmt = "`wait()` is not allowed after reply sent")]
WaitAfterReply,
}
#[derive(
Decode,
Encode,
Debug,
Clone,
Eq,
PartialEq,
PartialOrd,
Ord,
derive_more::Display,
derive_more::From,
)]
#[codec(crate = codec)]
pub enum UnrecoverableExtError {
#[display(fmt = "Execution error: {_0}")]
Execution(UnrecoverableExecutionError),
#[display(fmt = "Memory error: {_0}")]
Memory(UnrecoverableMemoryError),
#[display(fmt = "Waiting error: {_0}")]
Wait(UnrecoverableWaitError),
}
#[derive(
Decode,
Encode,
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
derive_more::Display,
derive_more::From,
)]
#[codec(crate = codec)]
pub enum TrapExplanation {
#[display(fmt = "Not enough gas to continue execution")]
GasLimitExceeded,
#[display(fmt = "Unable to call a forbidden function")]
ForbiddenFunction,
#[display(fmt = "Trying to allocate more wasm program memory than allowed")]
ProgramAllocOutOfBounds,
#[display(fmt = "Syscall unrecoverable error: {_0}")]
UnrecoverableExt(UnrecoverableExtError),
#[display(fmt = "Panic occurred: {_0}")]
Panic(LimitedStr<'static>),
#[display(fmt = "Stack limit exceeded")]
StackLimitExceeded,
#[display(fmt = "Reason is unknown. Possibly `unreachable` instruction is occurred")]
Unknown,
}
#[derive(Debug, Clone)]
pub enum RunFallibleError {
UndefinedTerminationReason(UndefinedTerminationReason),
FallibleExt(FallibleExtError),
}
impl<E> From<E> for RunFallibleError
where
E: BackendSyscallError,
{
fn from(err: E) -> Self {
err.into_run_fallible_error()
}
}
pub trait BackendSyscallError: Sized {
fn into_termination_reason(self) -> UndefinedTerminationReason;
fn into_run_fallible_error(self) -> RunFallibleError;
}
pub trait BackendAllocSyscallError: Sized {
type ExtError: BackendSyscallError;
fn into_backend_error(self) -> Result<Self::ExtError, Self>;
}