/
common.rs
283 lines (235 loc) · 7.83 KB
/
common.rs
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
use bytes::Bytes;
use ethereum_types::{Address, H256, U256};
use serde::Serialize;
use strum_macros::Display;
/// EVM revision.
#[derive(Clone, Copy, Debug, Display, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
pub enum Revision {
/// The Frontier revision.
/// The one Ethereum launched with.
Frontier = 0,
/// [The Homestead revision.](https://eips.ethereum.org/EIPS/eip-606)
Homestead = 1,
/// [The Tangerine Whistle revision.](https://eips.ethereum.org/EIPS/eip-608)
Tangerine = 2,
/// [The Spurious Dragon revision.](https://eips.ethereum.org/EIPS/eip-607)
Spurious = 3,
/// [The Byzantium revision.](https://eips.ethereum.org/EIPS/eip-609)
Byzantium = 4,
/// [The Constantinople revision.](https://eips.ethereum.org/EIPS/eip-1013)
Constantinople = 5,
/// [The Petersburg revision.](https://eips.ethereum.org/EIPS/eip-1716)
Petersburg = 6,
/// [The Istanbul revision.](https://eips.ethereum.org/EIPS/eip-1679)
Istanbul = 7,
/// [The Berlin revision.](https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/berlin.md)
Berlin = 8,
/// [The London revision.](https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/london.md)
London = 9,
/// The Shanghai revision.
Shanghai = 10,
}
impl Revision {
pub fn iter() -> impl IntoIterator<Item = Self> {
[
Self::Frontier,
Self::Homestead,
Self::Tangerine,
Self::Spurious,
Self::Byzantium,
Self::Constantinople,
Self::Petersburg,
Self::Istanbul,
Self::Berlin,
Self::London,
Self::Shanghai,
]
}
pub const fn latest() -> Self {
Self::Shanghai
}
pub const fn len() -> usize {
Self::latest() as usize + 1
}
}
/// Message status code.
#[must_use]
#[derive(Clone, Debug, Display, PartialEq)]
pub enum StatusCode {
/// Execution finished with success.
#[strum(serialize = "success")]
Success,
/// Generic execution failure.
#[strum(serialize = "failure")]
Failure,
/// Execution terminated with REVERT opcode.
///
/// In this case the amount of gas left MAY be non-zero and additional output
/// data MAY be provided in ::evmc_result.
#[strum(serialize = "revert")]
Revert,
/// The execution has run out of gas.
#[strum(serialize = "out of gas")]
OutOfGas,
/// The designated INVALID instruction has been hit during execution.
///
/// [EIP-141](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-141.md)
/// defines the instruction 0xfe as INVALID instruction to indicate execution
/// abortion coming from high-level languages. This status code is reported
/// in case this INVALID instruction has been encountered.
#[strum(serialize = "invalid instruction")]
InvalidInstruction,
/// An undefined instruction has been encountered.
#[strum(serialize = "undefined instruction")]
UndefinedInstruction,
/// The execution has attempted to put more items on the EVM stack
/// than the specified limit.
#[strum(serialize = "stack overflow")]
StackOverflow,
/// Execution of an opcode has required more items on the EVM stack.
#[strum(serialize = "stack underflow")]
StackUnderflow,
/// Execution has violated the jump destination restrictions.
#[strum(serialize = "bad jump destination")]
BadJumpDestination,
/// Tried to read outside memory bounds.
///
/// An example is RETURNDATACOPY reading past the available buffer.
#[strum(serialize = "invalid memory access")]
InvalidMemoryAccess,
/// Call depth has exceeded the limit (if any)
#[strum(serialize = "call depth exceeded")]
CallDepthExceeded,
/// Tried to execute an operation which is restricted in static mode.
#[strum(serialize = "static mode violation")]
StaticModeViolation,
/// A call to a precompiled or system contract has ended with a failure.
///
/// An example: elliptic curve functions handed invalid EC points.
#[strum(serialize = "precompile failure")]
PrecompileFailure,
/// Contract validation has failed.
#[strum(serialize = "contract validation failure")]
ContractValidationFailure,
/// An argument to a state accessing method has a value outside of the
/// accepted range of values.
#[strum(serialize = "argument out of range")]
ArgumentOutOfRange,
/// The caller does not have enough funds for value transfer.
#[strum(serialize = "insufficient balance")]
InsufficientBalance,
/// EVM implementation generic internal error.
#[strum(serialize = "internal error")]
InternalError(String),
}
/// The kind of call-like instruction.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CallKind {
Call,
DelegateCall,
CallCode,
Create,
Create2 { salt: H256 },
}
/// The message describing an EVM call,
/// including a zero-depth call from transaction origin.
#[derive(Clone, Debug, PartialEq)]
pub struct Message {
/// The kind of the call. For zero-depth calls `CallKind::Call` SHOULD be used.
pub kind: CallKind,
/// Static call mode.
pub is_static: bool,
/// The call depth.
pub depth: i32,
/// The amount of gas for message execution.
pub gas: i64,
/// The destination (recipient) of the message.
pub recipient: Address,
/// The sender of the message.
pub sender: Address,
/// Message input data.
pub input_data: Bytes,
/// The amount of Ether transferred with the message.
pub value: U256,
/// The address of the code to be executed.
///
/// May be different from the evmc_message::destination (recipient)
/// in case of `CallKind::CallCode` or `CallKind::DelegateCall`.
pub code_address: Address,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CreateMessage {
pub salt: Option<H256>,
pub gas: i64,
pub depth: i32,
pub initcode: Bytes,
pub sender: Address,
pub endowment: U256,
}
impl From<CreateMessage> for Message {
fn from(msg: CreateMessage) -> Self {
Self {
kind: if let Some(salt) = msg.salt {
CallKind::Create2 { salt }
} else {
CallKind::Create
},
is_static: false,
depth: msg.depth,
gas: msg.gas,
recipient: Address::zero(),
code_address: Address::zero(),
sender: msg.sender,
input_data: msg.initcode,
value: msg.endowment,
}
}
}
/// Output of EVM execution.
#[derive(Clone, Debug, PartialEq)]
pub struct Output {
/// EVM exited with this status code.
pub status_code: StatusCode,
/// How much gas was left after execution
pub gas_left: i64,
/// Output data returned.
pub output_data: Bytes,
/// Contract creation address.
pub create_address: Option<Address>,
}
/// EVM execution output if no error has occurred.
#[derive(Clone, Debug, PartialEq)]
pub struct SuccessfulOutput {
/// Indicates if revert was requested.
pub reverted: bool,
/// How much gas was left after execution.
pub gas_left: i64,
/// Output data returned.
pub output_data: Bytes,
}
impl From<SuccessfulOutput> for Output {
fn from(
SuccessfulOutput {
reverted,
gas_left,
output_data,
}: SuccessfulOutput,
) -> Self {
Self {
status_code: if reverted {
StatusCode::Revert
} else {
StatusCode::Success
},
gas_left,
output_data,
create_address: None,
}
}
}
pub(crate) fn u256_to_address(v: U256) -> Address {
H256(v.into()).into()
}
pub(crate) fn address_to_u256(v: Address) -> U256 {
U256::from_big_endian(&v.0)
}