ethereum / ethereum/execution-specs
EIP-8297: state-root computation raises raw Python errors instead of protocol-level failures
- Dominant language
- Python
- Stars
- 1.2k
- Forks
- 505
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 106
Description
Surfaced by the EIP-8297 test work in #3246. Two cases where computing a state root raises a raw Python exception rather than failing through the protocol's own error path.
### 1. Balance at or above 2^128
`ethereum.binary_trie.embedding.encode_basic_data` carries:
```python
assert balance < U256(2) ** U256(128) # U128 doesn't exist
```
BASIC_DATA gives `balance` a 16-byte field, so the bound is real — but it is enforced by a bare `assert` during root computation, and `AssertionError` is not an `EthereumException`. There is no protocol-level cap anywhere: `move_ether`, `create_ether` and `set_account_balance` all operate on unbounded `U256`. So a block that mints a balance past the cap **crashes the transition tool** instead of being rejected as invalid.
The EIP states no cap either — it only gives the field's offset and width.
This is unfillable at the EEST layer (t8n dies), so it is pinned only as a unit test.
### 2. Unknown code hash
`ethereum.state_pbt.State.get_code` is a bare dict subscript and raises `KeyError` for a hash absent from the store. `state_mpt.get_code` is identical in that respect — but MPT root computation never calls it, while the PBT embedding **must**, because code chunk leaves commit the code itself rather than just its hash. So an account whose code is missing from the store crashes root computation on PBT and not on MPT.
### The decision needed
- Should the balance bound be a protocol-level validity condition (rejecting the block) rather than an assertion? If balances past 2^128 are genuinely unreachable given the issuance schedule, saying so explicitly and keeping the assert as a defensive check would also be a fine answer — but that reasoning should be written down.
- Should `get_code` raise a typed error on the PBT path, given it is now reachable during root computation?
Neither is urgent, but both turn a would-be invalid block into a tooling crash, which is unpleasant to debug and would look like a client bug rather than a bad block.
Related: #3246.
Contributor guide
Research direction
Start with ethereum.binary_trie.embedding.encode_basic_data and the balance mutation paths move_ether, create_ether, and set_account_balance, then inspect ethereum.state_pbt.State.get_code and state_mpt.get_code. Review the EIP-8297 tests from #3246 and add focused unit coverage for the oversized balance and missing code hash cases. Done means the protocol behavior is decided and root computation reports a typed protocol failure rather than a raw Python exception, or the defensive assertion rationale is documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100