ethereum.forks.bpo5.vmethereum.forks.amsterdam.vm
Ethereum Virtual Machine (EVM).
.. contents:: Table of Contents :backlinks: none :local:
Introduction
The abstract computer which runs the code stored in an
.fork_types.Account.
__all__¶
| 33 | __all__ = ("Environment", "Evm", "Message") |
|---|
TRANSFER_TOPIC¶
| 34 | TRANSFER_TOPIC = keccak256(b"Transfer(address,address,uint256)") |
|---|
BURN_TOPIC¶
| 35 | BURN_TOPIC = keccak256(b"Burn(address,uint256)") |
|---|
SYSTEM_ADDRESS¶
| 36 | SYSTEM_ADDRESS = Address( |
|---|---|
| 37 | bytes.fromhex("fffffffffffffffffffffffffffffffffffffffe") |
| 38 | ) |
CALL_SUCCESS¶
| 39 | CALL_SUCCESS = U256(1) |
|---|
BlockEnvironment ¶
Items external to the virtual machine itself, provided by the environment.
| 42 | @dataclass |
|---|
class BlockEnvironment:
chain_id¶
| 48 | chain_id: U64 |
|---|
state¶
| 41 | state: State |
|---|---|
| 49 | state: BlockState |
block_gas_limit¶
| 50 | block_gas_limit: Uint |
|---|
block_hashes¶
| 51 | block_hashes: List[Hash32] |
|---|
coinbase¶
| 52 | coinbase: Address |
|---|
number¶
| 53 | number: Uint |
|---|
base_fee_per_gas¶
| 54 | base_fee_per_gas: Uint |
|---|
time¶
| 55 | time: U256 |
|---|
prev_randao¶
| 56 | prev_randao: Bytes32 |
|---|
excess_blob_gas¶
| 57 | excess_blob_gas: U64 |
|---|
parent_beacon_block_root¶
| 58 | parent_beacon_block_root: Hash32 |
|---|
block_access_list_builder¶
| 59 | block_access_list_builder: BlockAccessListBuilder |
|---|
slot_number¶
| 60 | slot_number: U64 |
|---|
BlockOutput ¶
Output from applying the block body to the present state.
Contains the following:
block_gas_used : ethereum.base_types.Uint
Gas used for executing all transactions.
block_state_gas_used : ethereum.base_types.Uint
State gas used for executing all transactions.
cumulative_gas_used : ethereum.base_types.Uint
Cumulative gas paid by users (post-refund, post-floor).
transactions_trie : ethereum.fork_types.Root
Trie of all the transactions in the block.
receipts_trie : ethereum.fork_types.Root
Trie root of all the receipts in the block.
receipt_keys :
Keys of all the receipts in the block.
block_logs : Bloom
Logs bloom of all the logs included in all the transactions of the
block.
withdrawals_trie : ethereum.fork_types.Root
Trie root of all the withdrawals in the block.
blob_gas_used : ethereum.base_types.U64
Total blob gas used in the block.
requests : Bytes
Hash of all the requests in the block.
block_access_list: BlockAccessList
The block access list for the block.
| 63 | @dataclass |
|---|
class BlockOutput:
block_gas_used¶
| 95 | block_gas_used: Uint = Uint(0) |
|---|
block_state_gas_used¶
| 96 | block_state_gas_used: Uint = Uint(0) |
|---|
cumulative_gas_used¶
| 97 | cumulative_gas_used: Uint = Uint(0) |
|---|
transactions_trie¶
| 80 | transactions_trie: Trie[Bytes, Optional[Bytes | LegacyTransaction]] = ( |
|---|---|
| 81 | field(default_factory=lambda: Trie(secured=False, default=None)) |
| 98 | transactions_trie: Trie[Bytes, Optional[Bytes | LegacyTransaction]] = ( |
| 99 | field(default_factory=lambda: Trie(secured=False, default=None)) |
| 100 | ) |
receipts_trie¶
| 83 | receipts_trie: Trie[Bytes, Optional[Bytes | Receipt]] = field( |
|---|---|
| 84 | default_factory=lambda: Trie(secured=False, default=None) |
| 101 | receipts_trie: Trie[Bytes, Optional[Bytes | Receipt]] = field( |
| 102 | default_factory=lambda: Trie(secured=False, default=None) |
| 103 | ) |
receipt_keys¶
| 104 | receipt_keys: Tuple[Bytes, ...] = field(default_factory=tuple) |
|---|
block_logs¶
| 105 | block_logs: Tuple[Log, ...] = field(default_factory=tuple) |
|---|
withdrawals_trie¶
| 88 | withdrawals_trie: Trie[Bytes, Optional[Bytes | Withdrawal]] = field( |
|---|---|
| 89 | default_factory=lambda: Trie(secured=False, default=None) |
| 106 | withdrawals_trie: Trie[Bytes, Optional[Bytes | Withdrawal]] = field( |
| 107 | default_factory=lambda: Trie(secured=False, default=None) |
| 108 | ) |
blob_gas_used¶
| 109 | blob_gas_used: U64 = U64(0) |
|---|
requests¶
| 110 | requests: List[Bytes] = field(default_factory=list) |
|---|
block_access_list¶
| 111 | block_access_list: BlockAccessList = field(default_factory=list) |
|---|
TransactionEnvironment ¶
Items that are used by contract creation or message call.
| 114 | @dataclass |
|---|
class TransactionEnvironment:
origin¶
| 120 | origin: Address |
|---|
gas_price¶
| 121 | gas_price: Uint |
|---|
gas¶
| 122 | gas: Uint |
|---|
state_gas_reservoir¶
| 123 | state_gas_reservoir: Uint |
|---|
access_list_addresses¶
| 124 | access_list_addresses: Set[Address] |
|---|
access_list_storage_keys¶
| 125 | access_list_storage_keys: Set[Tuple[Address, Bytes32]] |
|---|
transient_storage¶
| 106 | transient_storage: TransientStorage |
|---|
state¶
| 126 | state: TransactionState |
|---|
blob_versioned_hashes¶
| 127 | blob_versioned_hashes: Tuple[VersionedHash, ...] |
|---|
index_in_block¶
| 129 | index_in_block: Optional[Uint] |
|---|
tx_hash¶
| 130 | tx_hash: Optional[Hash32] |
|---|
intrinsic_regular_gas¶
| 131 | intrinsic_regular_gas: Uint |
|---|
intrinsic_state_gas¶
| 132 | intrinsic_state_gas: Uint |
|---|
Message ¶
Items that are used by contract creation or message call.
| 135 | @dataclass |
|---|
class Message:
block_env¶
| 141 | block_env: BlockEnvironment |
|---|
tx_env¶
| 142 | tx_env: TransactionEnvironment |
|---|
caller¶
| 143 | caller: Address |
|---|
target¶
| 144 | target: Bytes0 | Address |
|---|
current_target¶
| 145 | current_target: Address |
|---|
gas¶
| 146 | gas: Uint |
|---|
state_gas_reservoir¶
| 147 | state_gas_reservoir: Uint |
|---|
value¶
| 148 | value: U256 |
|---|
data¶
| 149 | data: Bytes |
|---|
code_address¶
| 150 | code_address: Optional[Address] |
|---|
code¶
| 151 | code: Bytes |
|---|
depth¶
| 152 | depth: Uint |
|---|
should_transfer_value¶
| 153 | should_transfer_value: bool |
|---|
is_static¶
| 154 | is_static: bool |
|---|
accessed_addresses¶
| 155 | accessed_addresses: Set[Address] |
|---|
accessed_storage_keys¶
| 156 | accessed_storage_keys: Set[Tuple[Address, Bytes32]] |
|---|
disable_precompiles¶
| 157 | disable_precompiles: bool |
|---|
parent_evm¶
| 158 | parent_evm: Optional["Evm"] |
|---|
Evm ¶
The internal state of the virtual machine.
| 161 | @dataclass |
|---|
class Evm:
pc¶
| 165 | pc: Uint |
|---|
stack¶
| 166 | stack: List[U256] |
|---|
memory¶
| 167 | memory: bytearray |
|---|
code¶
| 168 | code: Bytes |
|---|
gas_left¶
| 169 | gas_left: Uint |
|---|
state_gas_left¶
| 170 | state_gas_left: Uint |
|---|
valid_jump_destinations¶
| 171 | valid_jump_destinations: Set[Uint] |
|---|
logs¶
| 172 | logs: Tuple[Log, ...] |
|---|
refund_counter¶
| 173 | refund_counter: int |
|---|
running¶
| 174 | running: bool |
|---|
message¶
| 175 | message: Message |
|---|
output¶
| 176 | output: Bytes |
|---|
accounts_to_delete¶
| 177 | accounts_to_delete: Set[Address] |
|---|
return_data¶
| 178 | return_data: Bytes |
|---|
error¶
| 179 | error: Optional[EthereumException] |
|---|
accessed_addresses¶
| 180 | accessed_addresses: Set[Address] |
|---|
accessed_storage_keys¶
| 181 | accessed_storage_keys: Set[Tuple[Address, Bytes32]] |
|---|
regular_gas_used¶
| 182 | regular_gas_used: Uint = Uint(0) |
|---|
state_gas_used¶
| 183 | state_gas_used: Uint = Uint(0) |
|---|
state_gas_refund¶
| 184 | state_gas_refund: Uint = Uint(0) |
|---|
state_gas_refund_pending¶
| 185 | state_gas_refund_pending: Uint = Uint(0) |
|---|
credit_state_gas_refund ¶
Credit an inline state gas refund to evm.state_gas_left.
Clamp the applied portion to this frame's state_gas_used — the
matching charge may sit in an ancestor sharing storage via
CALLCODE/DELEGATECALL. Track it in state_gas_refund so
incorporate_child_on_error can undo the inflation, and defer the
unapplied remainder in state_gas_refund_pending for propagation
on success.
Parameters
evm : The frame crediting the refund. amount : The refund amount to credit.
def credit_state_gas_refund(evm: Evm, amount: Uint) -> None:
| 189 | """ |
|---|---|
| 190 | Credit an inline state gas refund to `evm.state_gas_left`. |
| 191 | |
| 192 | Clamp the applied portion to this frame's `state_gas_used` — the |
| 193 | matching charge may sit in an ancestor sharing storage via |
| 194 | CALLCODE/DELEGATECALL. Track it in `state_gas_refund` so |
| 195 | `incorporate_child_on_error` can undo the inflation, and defer the |
| 196 | unapplied remainder in `state_gas_refund_pending` for propagation |
| 197 | on success. |
| 198 | |
| 199 | Parameters |
| 200 | ---------- |
| 201 | evm : |
| 202 | The frame crediting the refund. |
| 203 | amount : |
| 204 | The refund amount to credit. |
| 205 | |
| 206 | """ |
| 207 | applied = min(amount, evm.state_gas_used) |
| 208 | evm.state_gas_left += applied |
| 209 | evm.state_gas_used -= applied |
| 210 | evm.state_gas_refund += applied |
| 211 | evm.state_gas_refund_pending += amount - applied |
incorporate_child_on_success ¶
Incorporate the state of a successful child_evm into the parent evm.
Propagate state_gas_refund (inline credits the child applied) so
an ancestor revert can undo the inflation, and apply
state_gas_refund_pending (the unapplied remainder) to the parent
via credit_state_gas_refund; any leftover propagates further up.
Parameters
evm :
The parent EVM.
child_evm :
The child evm to incorporate.
def incorporate_child_on_success(evm: Evm, child_evm: Evm) -> None:
| 215 | """ |
|---|---|
| 216 | Incorporate the state of a successful `child_evm` into the parent `evm`. |
| 217 | |
| 218 | Propagate `state_gas_refund` (inline credits the child applied) so |
| 219 | an ancestor revert can undo the inflation, and apply |
| 220 | `state_gas_refund_pending` (the unapplied remainder) to the parent |
| 221 | via `credit_state_gas_refund`; any leftover propagates further up. |
| 222 | |
| 223 | Parameters |
| 224 | ---------- |
| 225 | evm : |
| 226 | The parent `EVM`. |
| 227 | child_evm : |
| 228 | The child evm to incorporate. |
| 229 | |
| 230 | """ |
| 231 | evm.gas_left += child_evm.gas_left |
| 232 | evm.state_gas_left += child_evm.state_gas_left |
| 233 | evm.logs += child_evm.logs |
| 234 | evm.refund_counter += child_evm.refund_counter |
| 235 | evm.accounts_to_delete.update(child_evm.accounts_to_delete) |
| 236 | evm.accessed_addresses.update(child_evm.accessed_addresses) |
| 177 | evm.accessed_storage_keys.update(child_evm.accessed_storage_keys) |
| 237 | evm.accessed_storage_keys.update(child_evm.accessed_storage_keys) |
| 238 | evm.regular_gas_used += child_evm.regular_gas_used |
| 239 | evm.state_gas_used += child_evm.state_gas_used |
| 240 | evm.state_gas_refund += child_evm.state_gas_refund |
| 241 | credit_state_gas_refund(evm, child_evm.state_gas_refund_pending) |
incorporate_child_on_error ¶
Incorporate the state of an unsuccessful child_evm into the parent evm.
On failure (revert or exceptional halt) state changes are rolled back,
so no state was actually grown. All state gas, both reservoir and any
that spilled into gas_left, is restored to the parent's reservoir and
the child's state_gas_used is not accumulated.
Inline state-gas refunds (SSTORE 0 to x to 0, CREATE silent failure)
credited by the child inflated its state_gas_left; subtract
state_gas_refund from the amount returned to the parent's
reservoir so the inflation does not leak across the error boundary.
state_gas_refund_pending is discarded with the child frame.
Parameters
evm :
The parent EVM.
child_evm :
The child evm to incorporate.
def incorporate_child_on_error(evm: Evm, child_evm: Evm) -> None:
| 248 | """ |
|---|---|
| 249 | Incorporate the state of an unsuccessful `child_evm` into the parent `evm`. |
| 250 | |
| 251 | On failure (revert or exceptional halt) state changes are rolled back, |
| 252 | so no state was actually grown. All state gas, both reservoir and any |
| 253 | that spilled into `gas_left`, is restored to the parent's reservoir and |
| 254 | the child's `state_gas_used` is not accumulated. |
| 255 | |
| 256 | Inline state-gas refunds (SSTORE 0 to x to 0, CREATE silent failure) |
| 257 | credited by the child inflated its `state_gas_left`; subtract |
| 258 | `state_gas_refund` from the amount returned to the parent's |
| 259 | reservoir so the inflation does not leak across the error boundary. |
| 260 | `state_gas_refund_pending` is discarded with the child frame. |
| 261 | |
| 262 | Parameters |
| 263 | ---------- |
| 264 | evm : |
| 265 | The parent `EVM`. |
| 266 | child_evm : |
| 267 | The child evm to incorporate. |
| 268 | |
| 269 | """ |
| 192 | evm.gas_left += child_evm.gas_left |
| 270 | evm.gas_left += child_evm.gas_left |
| 271 | evm.state_gas_left += ( |
| 272 | child_evm.state_gas_used |
| 273 | + child_evm.state_gas_left |
| 274 | - child_evm.state_gas_refund |
| 275 | ) |
| 276 | evm.regular_gas_used += child_evm.regular_gas_used |
emit_transfer_log ¶
Emit a LOG3 for all ETH transfers satisfying EIP-7708.
Parameters
evm : The state of the ethereum virtual machine sender : The account address sending the transfer recipient : The account address receiving the transfer transfer_amount : The amount of ETH transacted
def emit_transfer_log(evm: Evm, sender: Address, recipient: Address, transfer_amount: U256) -> None:
| 285 | """ |
|---|---|
| 286 | Emit a LOG3 for all ETH transfers satisfying EIP-7708. |
| 287 | |
| 288 | Parameters |
| 289 | ---------- |
| 290 | evm : |
| 291 | The state of the ethereum virtual machine |
| 292 | sender : |
| 293 | The account address sending the transfer |
| 294 | recipient : |
| 295 | The account address receiving the transfer |
| 296 | transfer_amount : |
| 297 | The amount of ETH transacted |
| 298 | |
| 299 | """ |
| 300 | if transfer_amount == 0: |
| 301 | return |
| 302 | |
| 303 | padded_sender = left_pad_zero_bytes(sender, 32) |
| 304 | padded_recipient = left_pad_zero_bytes(recipient, 32) |
| 305 | log_entry = Log( |
| 306 | address=SYSTEM_ADDRESS, |
| 307 | topics=( |
| 308 | TRANSFER_TOPIC, |
| 309 | Hash32(padded_sender), |
| 310 | Hash32(padded_recipient), |
| 311 | ), |
| 312 | data=transfer_amount.to_be_bytes32(), |
| 313 | ) |
| 314 | |
| 315 | evm.logs = evm.logs + (log_entry,) |
emit_burn_log ¶
Emit a LOG2 for ETH burn per EIP-7708.
Parameters
evm : The state of the ethereum virtual machine account : The account address whose ETH is being burned amount : The amount of ETH being burned
def emit_burn_log(evm: Evm, account: Address, amount: U256) -> None:
| 323 | """ |
|---|---|
| 324 | Emit a LOG2 for ETH burn per EIP-7708. |
| 325 | |
| 326 | Parameters |
| 327 | ---------- |
| 328 | evm : |
| 329 | The state of the ethereum virtual machine |
| 330 | account : |
| 331 | The account address whose ETH is being burned |
| 332 | amount : |
| 333 | The amount of ETH being burned |
| 334 | |
| 335 | """ |
| 336 | if amount == 0: |
| 337 | return |
| 338 | |
| 339 | padded_account = left_pad_zero_bytes(account, 32) |
| 340 | log_entry = Log( |
| 341 | address=SYSTEM_ADDRESS, |
| 342 | topics=( |
| 343 | BURN_TOPIC, |
| 344 | Hash32(padded_account), |
| 345 | ), |
| 346 | data=amount.to_be_bytes32(), |
| 347 | ) |
| 348 | |
| 349 | evm.logs = evm.logs + (log_entry,) |