Skip to content

Commit

Permalink
bug(fw): fix account empty code check (#425)
Browse files Browse the repository at this point in the history
* fix(fw): fix account empty code check

* changelog
  • Loading branch information
marioevz authored Feb 6, 2024
1 parent f2fb51e commit ccf25a3
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Test fixtures for use by clients are available for each release on the [Github r

### 🧪 Test Cases

- 🐞 Fix beacon root contract deployment tests so the account in the pre-alloc is not empty ([#425](https://github.com/ethereum/execution-spec-tests/pull/425)).

### 🛠️ Framework

- ✨ Add Prague to forks ([#419](https://github.com/ethereum/execution-spec-tests/pull/419)).
Expand Down
25 changes: 20 additions & 5 deletions src/ethereum_test_tools/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,20 @@ def check_alloc(self: "Account", address: Address, alloc: dict):
actual_storage = Storage(alloc["storage"]) if "storage" in alloc else Storage({})
expected_storage.must_be_equal(address=address, other=actual_storage)

def has_empty_code(self: "Account") -> bool:
"""
Returns true if an account has no bytecode.
"""
return not self.code or Bytes(self.code) == b""

def is_empty(self: "Account") -> bool:
"""
Returns true if an account deemed empty.
"""
return (
(self.nonce == 0 or self.nonce is None)
and (self.balance == 0 or self.balance is None)
and (not self.code and self.code is None)
and self.has_empty_code()
and (not self.storage or self.storage == {} or self.storage is None)
)

Expand Down Expand Up @@ -580,9 +586,7 @@ def __init__(self, d: Mapping[FixedSizeBytesConvertible, Account | Dict] = {}):
for address, account in d.items():
address = Address(address)
assert address not in self, f"Duplicate address in alloc: {address}"
account = Account.from_dict(account)
assert not account.is_empty(), f"Empty account: {account} for address: {address}"
self[address] = account
self[address] = Account.from_dict(account)

@classmethod
def merge(cls, alloc_1: "Alloc", alloc_2: "Alloc") -> "Alloc":
Expand All @@ -592,10 +596,21 @@ def merge(cls, alloc_1: "Alloc", alloc_2: "Alloc") -> "Alloc":
merged = alloc_1.copy()

for address, other_account in alloc_2.items():
merged[address] = Account.merge(merged.get(address, None), other_account)
merged_account = Account.merge(merged.get(address, None), other_account)
if merged_account.is_empty():
if address in merged:
merged.pop(address, None)
else:
merged[address] = merged_account

return Alloc(merged)

def empty_accounts(self) -> List[Address]:
"""
Returns a list of addresses of empty accounts.
"""
return [address for address, account in self.items() if account.is_empty()]

def __json__(self, encoder: JSONEncoder) -> Mapping[str, Any]:
"""
Returns the JSON representation of the allocation.
Expand Down
13 changes: 9 additions & 4 deletions src/ethereum_test_tools/spec/blockchain/blockchain_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Ethereum blockchain test spec definition and filler.
"""

from copy import copy
from dataclasses import dataclass, field, replace
from pprint import pprint
Expand Down Expand Up @@ -133,12 +134,16 @@ def make_genesis(
if env.beacon_root is not None:
assert Hash(env.beacon_root) == Hash(0), "beacon_root must be empty at genesis"

pre_alloc = Alloc(
fork.pre_allocation(block_number=0, timestamp=Number(env.timestamp)),
pre_alloc = Alloc.merge(
Alloc(
fork.pre_allocation(block_number=0, timestamp=Number(env.timestamp)),
),
Alloc(self.pre),
)

if empty_accounts := pre_alloc.empty_accounts():
raise Exception(f"Empty accounts in pre state: {empty_accounts}")
new_alloc, state_root = t8n.calc_state_root(
alloc=to_json(Alloc.merge(pre_alloc, Alloc(self.pre))),
alloc=to_json(pre_alloc),
fork=fork,
debug_output_path=self.get_next_transition_tool_output_path(),
)
Expand Down
3 changes: 3 additions & 0 deletions src/ethereum_test_tools/spec/state/state_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Ethereum state test spec definition and filler.
"""

from copy import copy
from dataclasses import dataclass
from typing import Callable, Generator, List, Mapping, Optional, Type
Expand Down Expand Up @@ -133,6 +134,8 @@ def make_state_test_fixture(
),
Alloc(self.pre),
)
if empty_accounts := pre_alloc.empty_accounts():
raise Exception(f"Empty accounts in pre state: {empty_accounts}")
transition_tool_name = fork.transition_tool_name(
block_number=Number(self.env.number),
timestamp=Number(self.env.timestamp),
Expand Down

0 comments on commit ccf25a3

Please sign in to comment.