ethereum.dao_fork.vm.interpreter
Ethereum Virtual Machine (EVM) Interpreter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. contents:: Table of Contents :backlinks: none :local:
Introduction
A straightforward interpreter that executes EVM code.
STACK_DEPTH_LIMIT
59 | STACK_DEPTH_LIMIT = Uint(1024) |
---|
MessageCallOutput
Output of a particular message call
Contains the following:
1. `gas_left`: remaining gas after execution.
2. `refund_counter`: gas to refund after execution.
3. `logs`: list of `Log` generated during execution.
4. `accounts_to_delete`: Contracts which have self-destructed.
5. `error`: The error from the execution if any.
62 | @dataclass |
---|
class MessageCallOutput:
gas_left
76 | gas_left: Uint |
---|
refund_counter
77 | refund_counter: U256 |
---|
logs
78 | logs: Tuple[Log, ...] |
---|
accounts_to_delete
79 | accounts_to_delete: Set[Address] |
---|
error
80 | error: Optional[EthereumException] |
---|
process_message_call
If message.current
is empty then it creates a smart contract
else it executes a call from the message.caller
to the message.target
.
Parameters
message : Transaction specific items.
env : External items required for EVM execution.
Returns
output : MessageCallOutput
Output of the message call
def process_message_call(message: Message, env: Environment) -> MessageCallOutput:
86 | """ |
---|---|
87 | If `message.current` is empty then it creates a smart contract |
88 | else it executes a call from the `message.caller` to the `message.target`. |
89 |
|
90 | Parameters |
91 | ---------- |
92 | message : |
93 | Transaction specific items. |
94 |
|
95 | env : |
96 | External items required for EVM execution. |
97 |
|
98 | Returns |
99 | ------- |
100 | output : `MessageCallOutput` |
101 | Output of the message call |
102 | """ |
103 | if message.target == Bytes0(b""): |
104 | is_collision = account_has_code_or_nonce( |
105 | env.state, message.current_target |
106 | ) or account_has_storage(env.state, message.current_target) |
107 | if is_collision: |
108 | return MessageCallOutput( |
109 | Uint(0), U256(0), tuple(), set(), AddressCollision() |
110 | ) |
111 | else: |
112 | evm = process_create_message(message, env) |
113 | else: |
114 | evm = process_message(message, env) |
115 | |
116 | if evm.error: |
117 | logs: Tuple[Log, ...] = () |
118 | accounts_to_delete = set() |
119 | refund_counter = U256(0) |
120 | else: |
121 | logs = evm.logs |
122 | accounts_to_delete = evm.accounts_to_delete |
123 | refund_counter = U256(evm.refund_counter) |
124 | |
125 | tx_end = TransactionEnd( |
126 | int(message.gas) - int(evm.gas_left), evm.output, evm.error |
127 | ) |
128 | evm_trace(evm, tx_end) |
129 | |
130 | return MessageCallOutput( |
131 | gas_left=evm.gas_left, |
132 | refund_counter=refund_counter, |
133 | logs=logs, |
134 | accounts_to_delete=accounts_to_delete, |
135 | error=evm.error, |
136 | ) |
process_create_message
Executes a call to create a smart contract.
Parameters
message : Transaction specific items. env : External items required for EVM execution.
Returns
evm: :py:class:~ethereum.dao_fork.vm.Evm
Items containing execution specific objects.
def process_create_message(message: Message, env: Environment) -> Evm:
140 | """ |
---|---|
141 | Executes a call to create a smart contract. |
142 |
|
143 | Parameters |
144 | ---------- |
145 | message : |
146 | Transaction specific items. |
147 | env : |
148 | External items required for EVM execution. |
149 |
|
150 | Returns |
151 | ------- |
152 | evm: :py:class:`~ethereum.dao_fork.vm.Evm` |
153 | Items containing execution specific objects. |
154 | """ |
155 | # take snapshot of state before processing the message |
156 | begin_transaction(env.state) |
157 | |
158 | # If the address where the account is being created has storage, it is |
159 | # destroyed. This can only happen in the following highly unlikely |
160 | # circumstances: |
161 | # * The address created by two `CREATE` calls collide. |
162 | # * The first `CREATE` left empty code. |
163 | destroy_storage(env.state, message.current_target) |
164 | |
165 | evm = process_message(message, env) |
166 | if not evm.error: |
167 | contract_code = evm.output |
168 | contract_code_gas = Uint(len(contract_code)) * GAS_CODE_DEPOSIT |
169 | try: |
170 | charge_gas(evm, contract_code_gas) |
171 | except ExceptionalHalt as error: |
172 | rollback_transaction(env.state) |
173 | evm.gas_left = Uint(0) |
174 | evm.error = error |
175 | else: |
176 | set_code(env.state, message.current_target, contract_code) |
177 | commit_transaction(env.state) |
178 | else: |
179 | rollback_transaction(env.state) |
180 | return evm |
process_message
Executes a call to create a smart contract.
Parameters
message : Transaction specific items. env : External items required for EVM execution.
Returns
evm: :py:class:~ethereum.dao_fork.vm.Evm
Items containing execution specific objects
def process_message(message: Message, env: Environment) -> Evm:
184 | """ |
---|---|
185 | Executes a call to create a smart contract. |
186 |
|
187 | Parameters |
188 | ---------- |
189 | message : |
190 | Transaction specific items. |
191 | env : |
192 | External items required for EVM execution. |
193 |
|
194 | Returns |
195 | ------- |
196 | evm: :py:class:`~ethereum.dao_fork.vm.Evm` |
197 | Items containing execution specific objects |
198 | """ |
199 | if message.depth > STACK_DEPTH_LIMIT: |
200 | raise StackDepthLimitError("Stack depth limit reached") |
201 | |
202 | # take snapshot of state before processing the message |
203 | begin_transaction(env.state) |
204 | |
205 | touch_account(env.state, message.current_target) |
206 | |
207 | if message.should_transfer_value and message.value != 0: |
208 | move_ether( |
209 | env.state, message.caller, message.current_target, message.value |
210 | ) |
211 | |
212 | evm = execute_code(message, env) |
213 | if evm.error: |
214 | # revert state to the last saved checkpoint |
215 | # since the message call resulted in an error |
216 | rollback_transaction(env.state) |
217 | else: |
218 | commit_transaction(env.state) |
219 | return evm |
execute_code
Executes bytecode present in the message
.
Parameters
message : Transaction specific items. env : External items required for EVM execution.
Returns
evm: ethereum.vm.EVM
Items containing execution specific objects
def execute_code(message: Message, env: Environment) -> Evm:
223 | """ |
---|---|
224 | Executes bytecode present in the `message`. |
225 |
|
226 | Parameters |
227 | ---------- |
228 | message : |
229 | Transaction specific items. |
230 | env : |
231 | External items required for EVM execution. |
232 |
|
233 | Returns |
234 | ------- |
235 | evm: `ethereum.vm.EVM` |
236 | Items containing execution specific objects |
237 | """ |
238 | code = message.code |
239 | valid_jump_destinations = get_valid_jump_destinations(code) |
240 | |
241 | evm = Evm( |
242 | pc=Uint(0), |
243 | stack=[], |
244 | memory=bytearray(), |
245 | code=code, |
246 | gas_left=message.gas, |
247 | env=env, |
248 | valid_jump_destinations=valid_jump_destinations, |
249 | logs=(), |
250 | refund_counter=0, |
251 | running=True, |
252 | message=message, |
253 | output=b"", |
254 | accounts_to_delete=set(), |
255 | error=None, |
256 | ) |
257 | try: |
258 | if evm.message.code_address in PRE_COMPILED_CONTRACTS: |
259 | evm_trace(evm, PrecompileStart(evm.message.code_address)) |
260 | PRE_COMPILED_CONTRACTS[evm.message.code_address](evm) |
261 | evm_trace(evm, PrecompileEnd()) |
262 | return evm |
263 |
|
264 | while evm.running and evm.pc < ulen(evm.code): |
265 | try: |
266 | op = Ops(evm.code[evm.pc]) |
267 | except ValueError: |
268 | raise InvalidOpcode(evm.code[evm.pc]) |
269 |
|
270 | evm_trace(evm, OpStart(op)) |
271 | op_implementation[op](evm) |
272 | evm_trace(evm, OpEnd()) |
273 |
|
274 | evm_trace(evm, EvmStop(Ops.STOP)) |
275 |
|
276 | except ExceptionalHalt as error: |
277 | evm_trace(evm, OpException(error)) |
278 | evm.gas_left = Uint(0) |
279 | evm.error = error |
280 | return evm |