1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
use alloc::borrow::Cow;
use crate::Opcode;

/// Trap which indicates that an `ExternalOpcode` has to be handled.
pub type Trap = Opcode;

/// Capture represents the result of execution.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Capture<E, T> {
	/// The machine has exited. It cannot be executed again.
	Exit(E),
	/// The machine has trapped. It is waiting for external information, and can
	/// be executed again.
	Trap(T),
}

/// Exit reason.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "with-codec", derive(codec::Encode, codec::Decode))]
#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExitReason {
	/// Machine has succeeded.
	Succeed(ExitSucceed),
	/// Machine returns a normal EVM error.
	Error(ExitError),
	/// Machine encountered an explict revert.
	Revert(ExitRevert),
	/// Machine encountered an error that is not supposed to be normal EVM
	/// errors, such as requiring too much memory to execute.
	Fatal(ExitFatal),
}

impl ExitReason {
	/// Whether the exit is succeeded.
	pub fn is_succeed(&self) -> bool {
		match self {
			Self::Succeed(_) => true,
			_ => false,
		}
	}

	/// Whether the exit is error.
	pub fn is_error(&self) -> bool {
		match self {
			Self::Error(_) => true,
			_ => false,
		}
	}

	/// Whether the exit is revert.
	pub fn is_revert(&self) -> bool {
		match self {
			Self::Revert(_) => true,
			_ => false,
		}
	}

	/// Whether the exit is fatal.
	pub fn is_fatal(&self) -> bool {
		match self {
			Self::Fatal(_) => true,
			_ => false,
		}
	}
}

/// Exit succeed reason.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "with-codec", derive(codec::Encode, codec::Decode))]
#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExitSucceed {
	/// Machine encountered an explict stop.
	Stopped,
	/// Machine encountered an explict return.
	Returned,
	/// Machine encountered an explict suicide.
	Suicided,
}

impl From<ExitSucceed> for ExitReason {
	fn from(s: ExitSucceed) -> Self {
		Self::Succeed(s)
	}
}

/// Exit revert reason.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "with-codec", derive(codec::Encode, codec::Decode))]
#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExitRevert {
	/// Machine encountered an explict revert.
	Reverted,
}

impl From<ExitRevert> for ExitReason {
	fn from(s: ExitRevert) -> Self {
		Self::Revert(s)
	}
}

/// Exit error reason.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "with-codec", derive(codec::Encode, codec::Decode))]
#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExitError {
	/// Trying to pop from an empty stack.
	StackUnderflow,
	/// Trying to push into a stack over stack limit.
	StackOverflow,
	/// Jump destination is invalid.
	InvalidJump,
	/// An opcode accesses memory region, but the region is invalid.
	InvalidRange,
	/// Encountered the designated invalid opcode.
	DesignatedInvalid,
	/// Call stack is too deep (runtime).
	CallTooDeep,
	/// Create opcode encountered collision (runtime).
	CreateCollision,
	/// Create init code exceeds limit (runtime).
	CreateContractLimit,

	///	An opcode accesses external information, but the request is off offset
	///	limit (runtime).
	OutOfOffset,
	/// Execution runs out of gas (runtime).
	OutOfGas,
	/// Not enough fund to start the execution (runtime).
	OutOfFund,

	/// PC underflowed (unused).
	PCUnderflow,
	/// Attempt to create an empty account (runtime, unused).
	CreateEmpty,

	/// Other normal errors.
	Other(Cow<'static, str>),
}

impl From<ExitError> for ExitReason {
	fn from(s: ExitError) -> Self {
		Self::Error(s)
	}
}

/// Exit fatal reason.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "with-codec", derive(codec::Encode, codec::Decode))]
#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExitFatal {
	/// The operation is not supported.
	NotSupported,
	/// The trap (interrupt) is unhandled.
	UnhandledInterrupt,
	/// The environment explictly set call errors as fatal error.
	CallErrorAsFatal(ExitError),

	/// Other fatal errors.
	Other(Cow<'static, str>),
}

impl From<ExitFatal> for ExitReason {
	fn from(s: ExitFatal) -> Self {
		Self::Fatal(s)
	}
}