Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 40 additions & 37 deletions packages/testing/src/execution_testing/vm/bytecode.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Ethereum Virtual Machine bytecode primitives and utilities."""

from functools import cache
from typing import Any, List, Self, SupportsBytes, Type

from pydantic import GetCoreSchemaHandler
Expand Down Expand Up @@ -35,6 +34,14 @@ class Bytecode:
_name_: str = ""
_bytes_: bytes
_keccak_256_: Hash | None = None
_gas_cost_: int | None = None
_gas_cost_fork_: Type[ForkOpcodeInterface] | None = None
_gas_cost_block_number_: int | None = None
_gas_cost_timestamp_: int | None = None
_refund_: int | None = None
_refund_fork_: Type[ForkOpcodeInterface] | None = None
_refund_block_number_: int | None = None
_refund_timestamp_: int | None = None

popped_stack_items: int
pushed_stack_items: int
Expand Down Expand Up @@ -275,7 +282,22 @@ def gas_cost(
timestamp: int = 0,
) -> int:
"""Use a fork object to calculate the gas used by this bytecode."""
return _bytecode_gas_cost(self, fork, block_number, timestamp)
if (
self._gas_cost_ is None
or self._gas_cost_fork_ != fork
or self._gas_cost_block_number_ != block_number
or self._gas_cost_timestamp_ != timestamp
):
self._gas_cost_fork_ = fork
self._gas_cost_block_number_ = block_number
self._gas_cost_timestamp_ = timestamp
opcode_gas_calculator = fork.opcode_gas_calculator(
block_number=block_number, timestamp=timestamp
)
self._gas_cost_ = 0
for opcode in self.opcode_list:
self._gas_cost_ += opcode_gas_calculator(opcode)
return self._gas_cost_

def refund(
self,
Expand All @@ -285,7 +307,22 @@ def refund(
timestamp: int = 0,
) -> int:
"""Use a fork object to calculate the gas refund from this bytecode."""
return _bytecode_refund(self, fork, block_number, timestamp)
if (
self._refund_ is None
or self._refund_fork_ != fork
or self._refund_block_number_ != block_number
or self._refund_timestamp_ != timestamp
):
self._refund_fork_ = fork
self._refund_block_number_ = block_number
self._refund_timestamp_ = timestamp
opcode_refund_calculator = fork.opcode_refund_calculator(
block_number=block_number, timestamp=timestamp
)
self._refund_ = 0
for opcode in self.opcode_list:
self._refund_ += opcode_refund_calculator(opcode)
return self._refund_

@classmethod
def __get_pydantic_core_schema__(
Expand All @@ -302,37 +339,3 @@ def __get_pydantic_core_schema__(
info_arg=False,
),
)


@cache
def _bytecode_gas_cost(
bytecode: Bytecode,
fork: Type[ForkOpcodeInterface],
block_number: int,
timestamp: int,
) -> int:
"""Return cached gas cost for the given bytecode and fork parameters."""
opcode_gas_calculator = fork.opcode_gas_calculator(
block_number=block_number, timestamp=timestamp
)
total_gas = 0
for opcode in bytecode.opcode_list:
total_gas += opcode_gas_calculator(opcode)
return total_gas


@cache
def _bytecode_refund(
bytecode: Bytecode,
fork: Type[ForkOpcodeInterface],
block_number: int,
timestamp: int,
) -> int:
"""Return cached gas refund for the given bytecode and fork parameters."""
opcode_refund_calculator = fork.opcode_refund_calculator(
block_number=block_number, timestamp=timestamp
)
total_refund = 0
for opcode in bytecode.opcode_list:
total_refund += opcode_refund_calculator(opcode)
return total_refund
Loading