Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(forks,base_types,types,vm): Misc changes fixes #827

Merged
merged 7 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions src/ethereum_test_base_types/composite_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ def set_next_slot(self, slot: int) -> "Storage":
self._current_slot = slot
return self

def items(self):
"""Returns the items of the storage"""
return self.root.items()

def store_next(
self, value: StorageKeyValueTypeConvertible | StorageKeyValueType | bool
) -> StorageKeyValueType:
Expand Down
11 changes: 11 additions & 0 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,17 @@ def engine_forkchoice_updated_version(
"""
pass

@classmethod
@abstractmethod
def engine_get_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
Returns `None` if the forks canonical chain cannot be set using the forkchoice method.
"""
pass

# EVM information abstract methods
@classmethod
@abstractmethod
def evm_code_types(cls, block_number: int = 0, timestamp: int = 0) -> List[EVMCodeType]:
Expand Down
9 changes: 9 additions & 0 deletions src/ethereum_test_forks/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ def engine_forkchoice_updated_version(
"""
return cls.engine_new_payload_version(block_number, timestamp)

@classmethod
def engine_get_payload_version(
cls, block_number: int = 0, timestamp: int = 0
) -> Optional[int]:
"""
At genesis, payloads cannot be retrieved through the engine API.
"""
return cls.engine_new_payload_version(block_number, timestamp)

@classmethod
def get_reward(cls, block_number: int = 0, timestamp: int = 0) -> int:
"""
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Requests,
Storage,
Transaction,
TransactionDefaults,
Withdrawal,
WithdrawalRequest,
keccak256,
Expand Down Expand Up @@ -54,6 +55,7 @@
"TestPrivateKey",
"TestPrivateKey2",
"Transaction",
"TransactionDefaults",
"Withdrawal",
"WithdrawalRequest",
"ZeroPaddedHexNumber",
Expand Down
5 changes: 2 additions & 3 deletions src/ethereum_test_types/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ethereum_test_base_types.conversions import BytesConvertible, FixedSizeBytesConvertible
from ethereum_test_vm import Opcodes as Op

from .types import EOA
from .types import EOA, int_to_bytes

"""
Helper functions
Expand Down Expand Up @@ -46,8 +46,7 @@ def compute_create_address(
address = Address(address)
if nonce is None:
nonce = 0
nonce_bytes = bytes() if nonce == 0 else nonce.to_bytes(length=1, byteorder="big")
hash = Bytes(encode([address, nonce_bytes])).keccak256()
hash = Bytes(encode([address, int_to_bytes(nonce)])).keccak256()
return Address(hash[-20:])
if opcode == Op.CREATE2:
return compute_create2_address(address, salt, initcode)
Expand Down
48 changes: 39 additions & 9 deletions src/ethereum_test_types/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
BaseModel,
ConfigDict,
Field,
PrivateAttr,
RootModel,
computed_field,
model_serializer,
Expand Down Expand Up @@ -56,6 +57,16 @@ def keccak256(data: bytes) -> Hash:
return Bytes(data).keccak256()


def int_to_bytes(value: int) -> bytes:
"""
Converts an integer to its big-endian representation.
"""
if value == 0:
return b""

return int_to_bytes(value // 256) + bytes([value % 256])


# Sentinel classes
class Removable:
"""
Expand Down Expand Up @@ -119,6 +130,8 @@ class Alloc(BaseAlloc):
Allocation of accounts in the state, pre and post test execution.
"""

_eoa_fund_amount_default: int = PrivateAttr(10**21)

@dataclass(kw_only=True)
class UnexpectedAccount(Exception):
"""
Expand Down Expand Up @@ -175,6 +188,12 @@ def __iter__(self):
"""
return iter(self.root)

def items(self):
"""
Returns an iterator over the allocation items.
"""
return self.root.items()

def __getitem__(self, address: Address | FixedSizeBytesConvertible) -> Account | None:
"""
Returns the account associated with an address.
Expand Down Expand Up @@ -286,7 +305,7 @@ def deploy_contract(

def fund_eoa(
self,
amount: NumberConvertible = 10**21,
amount: NumberConvertible | None = None,
label: str | None = None,
storage: Storage | None = None,
delegation: Address | Literal["Self"] | None = None,
Expand Down Expand Up @@ -581,13 +600,27 @@ def sign(self, private_key: Hash) -> None:
self.s = HexNumber(signature[2])


@dataclass
class TransactionDefaults:
"""
Default values for transactions.
"""

chain_id: int = 1
gas_price = 10
max_fee_per_gas = 7
max_priority_fee_per_gas: int = 0


class TransactionGeneric(BaseModel, Generic[NumberBoundTypeVar]):
"""
Generic transaction type used as a parent for Transaction and FixtureTransaction (blockchain).
"""

ty: NumberBoundTypeVar = Field(0, alias="type") # type: ignore
chain_id: NumberBoundTypeVar = Field(1) # type: ignore
chain_id: NumberBoundTypeVar = Field(
default_factory=lambda: TransactionDefaults.chain_id
) # type: ignore
nonce: NumberBoundTypeVar = Field(0) # type: ignore
gas_price: NumberBoundTypeVar | None = None
max_priority_fee_per_gas: NumberBoundTypeVar | None = None
Expand Down Expand Up @@ -743,16 +776,16 @@ def model_post_init(self, __context):

# Set default values for fields that are required for certain tx types
if self.ty <= 1 and self.gas_price is None:
self.gas_price = 10
self.gas_price = TransactionDefaults.gas_price
if self.ty >= 1 and self.access_list is None:
self.access_list = []
if self.ty < 1:
assert self.access_list is None, "access_list must be None"

if self.ty >= 2 and self.max_fee_per_gas is None:
self.max_fee_per_gas = 7
self.max_fee_per_gas = TransactionDefaults.max_fee_per_gas
if self.ty >= 2 and self.max_priority_fee_per_gas is None:
self.max_priority_fee_per_gas = 0
self.max_priority_fee_per_gas = TransactionDefaults.max_priority_fee_per_gas
if self.ty < 2:
assert self.max_fee_per_gas is None, "max_fee_per_gas must be None"
assert self.max_priority_fee_per_gas is None, "max_priority_fee_per_gas must be None"
Expand Down Expand Up @@ -1078,12 +1111,9 @@ def created_contract(self) -> Address:
"""
if self.to is not None:
raise ValueError("transaction is not a contract creation")
nonce_bytes = (
bytes() if self.nonce == 0 else self.nonce.to_bytes(length=1, byteorder="big")
)
if self.sender is None:
raise ValueError("sender address is None")
hash = Bytes(eth_rlp.encode([self.sender, nonce_bytes])).keccak256()
hash = Bytes(eth_rlp.encode([self.sender, int_to_bytes(self.nonce)])).keccak256()
return Address(hash[-20:])


Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_test_vm/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _get_int_size(n: int) -> int:


def _stack_argument_to_bytecode(
arg: "int | bytes | str | Opcode | Bytecode | Iterable[int]",
arg: "int | bytes | SupportsBytes | str | Opcode | Bytecode | Iterable[int]",
) -> Bytecode:
"""
Converts a stack argument in an opcode or macro to bytecode.
Expand Down
8 changes: 6 additions & 2 deletions src/pytest_plugins/filler/pre_alloc.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ def pytest_addoption(parser: pytest.Parser):
"""
Adds command-line options to pytest.
"""
pre_alloc_group = parser.getgroup("pre_alloc", "Arguments defining pre-allocation behavior.")
pre_alloc_group = parser.getgroup(
"pre_alloc", "Arguments defining pre-allocation behavior during test filling."
)

pre_alloc_group.addoption(
"--strict-alloc",
Expand Down Expand Up @@ -193,7 +195,7 @@ def deploy_contract(

def fund_eoa(
self,
amount: NumberConvertible = 10**21,
amount: NumberConvertible | None = None,
label: str | None = None,
storage: Storage | None = None,
delegation: Address | Literal["Self"] | None = None,
Expand All @@ -205,6 +207,8 @@ def fund_eoa(
returned.
"""
eoa = next(self._eoa_iterator)
if amount is None:
amount = self._eoa_fund_amount_default
if Number(amount) > 0 or storage is not None or delegation is not None:
if storage is None and delegation is None:
account = Account(
Expand Down