ethereum.forks.frontier.vm.instructions.system
Ethereum Virtual Machine (EVM) System Instructions.
.. contents:: Table of Contents :backlinks: none :local:
Introduction
Implementations of the EVM system related instructions.
create
Creates a new account with associated code.
Parameters
evm : The current EVM frame.
def create(evm: Evm) -> None:
45 | """ |
---|---|
46 | Creates a new account with associated code. |
47 |
|
48 | Parameters |
49 | ---------- |
50 | evm : |
51 | The current EVM frame. |
52 |
|
53 | """ |
54 | # This import causes a circular import error |
55 | # if it's not moved inside this method |
56 | from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message |
57 | |
58 | # STACK |
59 | endowment = pop(evm.stack) |
60 | memory_start_position = pop(evm.stack) |
61 | memory_size = pop(evm.stack) |
62 | |
63 | # GAS |
64 | extend_memory = calculate_gas_extend_memory( |
65 | evm.memory, [(memory_start_position, memory_size)] |
66 | ) |
67 | |
68 | charge_gas(evm, GAS_CREATE + extend_memory.cost) |
69 | |
70 | create_message_gas = evm.gas_left |
71 | evm.gas_left = Uint(0) |
72 | |
73 | # OPERATION |
74 | evm.memory += b"\x00" * extend_memory.expand_by |
75 | sender_address = evm.message.current_target |
76 | sender = get_account(evm.message.block_env.state, sender_address) |
77 | |
78 | contract_address = compute_contract_address( |
79 | evm.message.current_target, |
80 | get_account( |
81 | evm.message.block_env.state, evm.message.current_target |
82 | ).nonce, |
83 | ) |
84 | |
85 | if ( |
86 | sender.balance < endowment |
87 | or sender.nonce == Uint(2**64 - 1) |
88 | or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT |
89 | ): |
90 | push(evm.stack, U256(0)) |
91 | evm.gas_left += create_message_gas |
92 | elif account_has_code_or_nonce( |
93 | evm.message.block_env.state, contract_address |
94 | ) or account_has_storage(evm.message.block_env.state, contract_address): |
95 | increment_nonce( |
96 | evm.message.block_env.state, evm.message.current_target |
97 | ) |
98 | push(evm.stack, U256(0)) |
99 | else: |
100 | call_data = memory_read_bytes( |
101 | evm.memory, memory_start_position, memory_size |
102 | ) |
103 |
|
104 | increment_nonce( |
105 | evm.message.block_env.state, evm.message.current_target |
106 | ) |
107 |
|
108 | child_message = Message( |
109 | block_env=evm.message.block_env, |
110 | tx_env=evm.message.tx_env, |
111 | caller=evm.message.current_target, |
112 | target=Bytes0(), |
113 | gas=create_message_gas, |
114 | value=endowment, |
115 | data=b"", |
116 | code=call_data, |
117 | current_target=contract_address, |
118 | depth=evm.message.depth + Uint(1), |
119 | code_address=None, |
120 | parent_evm=evm, |
121 | ) |
122 | child_evm = process_create_message(child_message) |
123 |
|
124 | if child_evm.error: |
125 | incorporate_child_on_error(evm, child_evm) |
126 | push(evm.stack, U256(0)) |
127 | else: |
128 | incorporate_child_on_success(evm, child_evm) |
129 | push( |
130 | evm.stack, U256.from_be_bytes(child_evm.message.current_target) |
131 | ) |
132 | |
133 | # PROGRAM COUNTER |
134 | evm.pc += Uint(1) |
return_
Halts execution returning output data.
Parameters
evm : The current EVM frame.
def return_(evm: Evm) -> None:
138 | """ |
---|---|
139 | Halts execution returning output data. |
140 |
|
141 | Parameters |
142 | ---------- |
143 | evm : |
144 | The current EVM frame. |
145 |
|
146 | """ |
147 | # STACK |
148 | memory_start_position = pop(evm.stack) |
149 | memory_size = pop(evm.stack) |
150 | |
151 | # GAS |
152 | extend_memory = calculate_gas_extend_memory( |
153 | evm.memory, [(memory_start_position, memory_size)] |
154 | ) |
155 | |
156 | charge_gas(evm, GAS_ZERO + extend_memory.cost) |
157 | |
158 | # OPERATION |
159 | evm.memory += b"\x00" * extend_memory.expand_by |
160 | evm.output = memory_read_bytes( |
161 | evm.memory, memory_start_position, memory_size |
162 | ) |
163 | |
164 | evm.running = False |
165 | |
166 | # PROGRAM COUNTER |
167 | pass |
generic_call
Perform the core logic of the CALL*
family of opcodes.
def generic_call(evm: Evm, gas: Uint, value: U256, caller: Address, to: Address, code_address: Address, memory_input_start_position: U256, memory_input_size: U256, memory_output_start_position: U256, memory_output_size: U256) -> None:
182 | """ |
---|---|
183 | Perform the core logic of the `CALL*` family of opcodes. |
184 | """ |
185 | from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message |
186 | |
187 | if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT: |
188 | evm.gas_left += gas |
189 | push(evm.stack, U256(0)) |
190 | return |
191 | |
192 | call_data = memory_read_bytes( |
193 | evm.memory, memory_input_start_position, memory_input_size |
194 | ) |
195 | code = get_account(evm.message.block_env.state, code_address).code |
196 | child_message = Message( |
197 | block_env=evm.message.block_env, |
198 | tx_env=evm.message.tx_env, |
199 | caller=caller, |
200 | target=to, |
201 | gas=gas, |
202 | value=value, |
203 | data=call_data, |
204 | code=code, |
205 | current_target=to, |
206 | depth=evm.message.depth + Uint(1), |
207 | code_address=code_address, |
208 | parent_evm=evm, |
209 | ) |
210 | child_evm = process_message(child_message) |
211 | |
212 | if child_evm.error: |
213 | incorporate_child_on_error(evm, child_evm) |
214 | push(evm.stack, U256(0)) |
215 | else: |
216 | incorporate_child_on_success(evm, child_evm) |
217 | push(evm.stack, U256(1)) |
218 | |
219 | actual_output_size = min(memory_output_size, U256(len(child_evm.output))) |
220 | memory_write( |
221 | evm.memory, |
222 | memory_output_start_position, |
223 | child_evm.output[:actual_output_size], |
224 | ) |
call
Message-call into an account.
Parameters
evm : The current EVM frame.
def call(evm: Evm) -> None:
228 | """ |
---|---|
229 | Message-call into an account. |
230 |
|
231 | Parameters |
232 | ---------- |
233 | evm : |
234 | The current EVM frame. |
235 |
|
236 | """ |
237 | # STACK |
238 | gas = Uint(pop(evm.stack)) |
239 | to = to_address_masked(pop(evm.stack)) |
240 | value = pop(evm.stack) |
241 | memory_input_start_position = pop(evm.stack) |
242 | memory_input_size = pop(evm.stack) |
243 | memory_output_start_position = pop(evm.stack) |
244 | memory_output_size = pop(evm.stack) |
245 | |
246 | # GAS |
247 | extend_memory = calculate_gas_extend_memory( |
248 | evm.memory, |
249 | [ |
250 | (memory_input_start_position, memory_input_size), |
251 | (memory_output_start_position, memory_output_size), |
252 | ], |
253 | ) |
254 | |
255 | code_address = to |
256 | |
257 | message_call_gas = calculate_message_call_gas( |
258 | evm.message.block_env.state, gas, to, value |
259 | ) |
260 | charge_gas(evm, message_call_gas.cost + extend_memory.cost) |
261 | |
262 | # OPERATION |
263 | evm.memory += b"\x00" * extend_memory.expand_by |
264 | sender_balance = get_account( |
265 | evm.message.block_env.state, evm.message.current_target |
266 | ).balance |
267 | if sender_balance < value: |
268 | push(evm.stack, U256(0)) |
269 | evm.gas_left += message_call_gas.sub_call |
270 | else: |
271 | generic_call( |
272 | evm, |
273 | message_call_gas.sub_call, |
274 | value, |
275 | evm.message.current_target, |
276 | to, |
277 | code_address, |
278 | memory_input_start_position, |
279 | memory_input_size, |
280 | memory_output_start_position, |
281 | memory_output_size, |
282 | ) |
283 | |
284 | # PROGRAM COUNTER |
285 | evm.pc += Uint(1) |
callcode
Message-call into this account with alternative account’s code.
Parameters
evm : The current EVM frame.
def callcode(evm: Evm) -> None:
289 | """ |
---|---|
290 | Message-call into this account with alternative account’s code. |
291 |
|
292 | Parameters |
293 | ---------- |
294 | evm : |
295 | The current EVM frame. |
296 |
|
297 | """ |
298 | # STACK |
299 | gas = Uint(pop(evm.stack)) |
300 | code_address = to_address_masked(pop(evm.stack)) |
301 | value = pop(evm.stack) |
302 | memory_input_start_position = pop(evm.stack) |
303 | memory_input_size = pop(evm.stack) |
304 | memory_output_start_position = pop(evm.stack) |
305 | memory_output_size = pop(evm.stack) |
306 | |
307 | # GAS |
308 | to = evm.message.current_target |
309 | |
310 | extend_memory = calculate_gas_extend_memory( |
311 | evm.memory, |
312 | [ |
313 | (memory_input_start_position, memory_input_size), |
314 | (memory_output_start_position, memory_output_size), |
315 | ], |
316 | ) |
317 | message_call_gas = calculate_message_call_gas( |
318 | evm.message.block_env.state, gas, to, value |
319 | ) |
320 | charge_gas(evm, message_call_gas.cost + extend_memory.cost) |
321 | |
322 | # OPERATION |
323 | evm.memory += b"\x00" * extend_memory.expand_by |
324 | sender_balance = get_account( |
325 | evm.message.block_env.state, evm.message.current_target |
326 | ).balance |
327 | if sender_balance < value: |
328 | push(evm.stack, U256(0)) |
329 | evm.gas_left += message_call_gas.sub_call |
330 | else: |
331 | generic_call( |
332 | evm, |
333 | message_call_gas.sub_call, |
334 | value, |
335 | evm.message.current_target, |
336 | to, |
337 | code_address, |
338 | memory_input_start_position, |
339 | memory_input_size, |
340 | memory_output_start_position, |
341 | memory_output_size, |
342 | ) |
343 | |
344 | # PROGRAM COUNTER |
345 | evm.pc += Uint(1) |
selfdestruct
Halt execution and register account for later deletion.
Parameters
evm : The current EVM frame.
def selfdestruct(evm: Evm) -> None:
349 | """ |
---|---|
350 | Halt execution and register account for later deletion. |
351 |
|
352 | Parameters |
353 | ---------- |
354 | evm : |
355 | The current EVM frame. |
356 |
|
357 | """ |
358 | # STACK |
359 | beneficiary = to_address_masked(pop(evm.stack)) |
360 | |
361 | # GAS |
362 | gas_cost = GAS_ZERO |
363 | |
364 | originator = evm.message.current_target |
365 | |
366 | refunded_accounts = evm.accounts_to_delete |
367 | parent_evm = evm.message.parent_evm |
368 | while parent_evm is not None: |
369 | refunded_accounts.update(parent_evm.accounts_to_delete) |
370 | parent_evm = parent_evm.message.parent_evm |
371 | |
372 | if originator not in refunded_accounts: |
373 | evm.refund_counter += int(REFUND_SELF_DESTRUCT) |
374 | |
375 | charge_gas(evm, gas_cost) |
376 | |
377 | # OPERATION |
378 | beneficiary_balance = get_account( |
379 | evm.message.block_env.state, beneficiary |
380 | ).balance |
381 | originator_balance = get_account( |
382 | evm.message.block_env.state, originator |
383 | ).balance |
384 | |
385 | # First Transfer to beneficiary |
386 | set_account_balance( |
387 | evm.message.block_env.state, |
388 | beneficiary, |
389 | beneficiary_balance + originator_balance, |
390 | ) |
391 | # Next, Zero the balance of the address being deleted (must come after |
392 | # sending to beneficiary in case the contract named itself as the |
393 | # beneficiary). |
394 | set_account_balance(evm.message.block_env.state, originator, U256(0)) |
395 | |
396 | # register account for deletion |
397 | evm.accounts_to_delete.add(originator) |
398 | |
399 | # HALT the execution |
400 | evm.running = False |
401 | |
402 | # PROGRAM COUNTER |
403 | pass |