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