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