ethereum.frontier.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

54
STACK_DEPTH_LIMIT = U256(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.
57
@dataclass
class MessageCallOutput:

gas_left

71
    gas_left: Uint

refund_counter

72
    refund_counter: U256

logs

73
    logs: Tuple[Log, ...]

accounts_to_delete

74
    accounts_to_delete: Set[Address]

error

75
    error: Optional[Exception]

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:
81
    """
82
    If `message.current` is empty then it creates a smart contract
83
    else it executes a call from the `message.caller` to the `message.target`.
84
85
    Parameters
86
    ----------
87
    message :
88
        Transaction specific items.
89
90
    env :
91
        External items required for EVM execution.
92
93
    Returns
94
    -------
95
    output : `MessageCallOutput`
96
        Output of the message call
97
    """
98
    if message.target == Bytes0(b""):
99
        is_collision = account_has_code_or_nonce(
100
            env.state, message.current_target
101
        )
102
        if is_collision:
103
            return MessageCallOutput(
104
                Uint(0), U256(0), tuple(), set(), AddressCollision()
105
            )
106
        else:
107
            evm = process_create_message(message, env)
108
    else:
109
        evm = process_message(message, env)
110
111
    if evm.error:
112
        logs: Tuple[Log, ...] = ()
113
        accounts_to_delete = set()
114
        refund_counter = U256(0)
115
    else:
116
        logs = evm.logs
117
        accounts_to_delete = evm.accounts_to_delete
118
        refund_counter = U256(evm.refund_counter)
119
120
    tx_end = TransactionEnd(message.gas - evm.gas_left, evm.output, evm.error)
121
    evm_trace(evm, tx_end)
122
123
    return MessageCallOutput(
124
        gas_left=evm.gas_left,
125
        refund_counter=refund_counter,
126
        logs=logs,
127
        accounts_to_delete=accounts_to_delete,
128
        error=evm.error,
129
    )

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.frontier.vm.Evm Items containing execution specific objects.

def process_create_message(message: Message, ​​env: Environment) -> Evm:
133
    """
134
    Executes a call to create a smart contract.
135
136
    Parameters
137
    ----------
138
    message :
139
        Transaction specific items.
140
    env :
141
        External items required for EVM execution.
142
143
    Returns
144
    -------
145
    evm: :py:class:`~ethereum.frontier.vm.Evm`
146
        Items containing execution specific objects.
147
    """
148
    # take snapshot of state before processing the message
149
    begin_transaction(env.state)
150
151
    # If the address where the account is being created has storage, it is
152
    # destroyed. This can only happen in the following highly unlikely
153
    # circumstances:
154
    # * The address created by two `CREATE` calls collide.
155
    # * The first `CREATE` left empty code.
156
    destroy_storage(env.state, message.current_target)
157
158
    evm = process_message(message, env)
159
    if not evm.error:
160
        contract_code = evm.output
161
        contract_code_gas = len(contract_code) * GAS_CODE_DEPOSIT
162
        try:
163
            charge_gas(evm, contract_code_gas)
164
        except ExceptionalHalt:
165
            evm.output = b""
166
        else:
167
            set_code(env.state, message.current_target, contract_code)
168
        commit_transaction(env.state)
169
    else:
170
        rollback_transaction(env.state)
171
    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.frontier.vm.Evm Items containing execution specific objects

def process_message(message: Message, ​​env: Environment) -> Evm:
175
    """
176
    Executes a call to create a smart contract.
177
178
    Parameters
179
    ----------
180
    message :
181
        Transaction specific items.
182
    env :
183
        External items required for EVM execution.
184
185
    Returns
186
    -------
187
    evm: :py:class:`~ethereum.frontier.vm.Evm`
188
        Items containing execution specific objects
189
    """
190
    if message.depth > STACK_DEPTH_LIMIT:
191
        raise StackDepthLimitError("Stack depth limit reached")
192
193
    # take snapshot of state before processing the message
194
    begin_transaction(env.state)
195
196
    touch_account(env.state, message.current_target)
197
198
    if message.value != 0:
199
        move_ether(
200
            env.state, message.caller, message.current_target, message.value
201
        )
202
203
    evm = execute_code(message, env)
204
    if evm.error:
205
        # revert state to the last saved checkpoint
206
        # since the message call resulted in an error
207
        rollback_transaction(env.state)
208
    else:
209
        commit_transaction(env.state)
210
    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:
214
    """
215
    Executes bytecode present in the `message`.
216
217
    Parameters
218
    ----------
219
    message :
220
        Transaction specific items.
221
    env :
222
        External items required for EVM execution.
223
224
    Returns
225
    -------
226
    evm: `ethereum.vm.EVM`
227
        Items containing execution specific objects
228
    """
229
    code = message.code
230
    valid_jump_destinations = get_valid_jump_destinations(code)
231
232
    evm = Evm(
233
        pc=Uint(0),
234
        stack=[],
235
        memory=bytearray(),
236
        code=code,
237
        gas_left=message.gas,
238
        env=env,
239
        valid_jump_destinations=valid_jump_destinations,
240
        logs=(),
241
        refund_counter=U256(0),
242
        running=True,
243
        message=message,
244
        output=b"",
245
        accounts_to_delete=set(),
246
        error=None,
247
    )
248
    try:
249
        if evm.message.code_address in PRE_COMPILED_CONTRACTS:
250
            evm_trace(evm, PrecompileStart(evm.message.code_address))
251
            PRE_COMPILED_CONTRACTS[evm.message.code_address](evm)
252
            evm_trace(evm, PrecompileEnd())
253
            return evm
254
255
        while evm.running and evm.pc < len(evm.code):
256
            try:
257
                op = Ops(evm.code[evm.pc])
258
            except ValueError:
259
                raise InvalidOpcode(evm.code[evm.pc])
260
261
            evm_trace(evm, OpStart(op))
262
            op_implementation[op](evm)
263
            evm_trace(evm, OpEnd())
264
265
        evm_trace(evm, EvmStop(Ops.STOP))
266
267
    except ExceptionalHalt as error:
268
        evm_trace(evm, OpException(error))
269
        evm.gas_left = Uint(0)
270
        evm.error = error
271
    return evm