Skip to content

Commit cba70e1

Browse files
authored
Merge pull request #2022 from carver/prelim-london-fixups
Preliminary london fixups
2 parents 6d02bd6 + 94573ef commit cba70e1

File tree

5 files changed

+61
-29
lines changed

5 files changed

+61
-29
lines changed

eth/tools/_utils/normalization.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,8 @@ def normalize_block_header(header: Dict[str, Any]) -> Dict[str, Any]:
542542
}
543543
if 'blocknumber' in header:
544544
normalized_header['blocknumber'] = to_int(header['blocknumber'])
545+
if 'baseFeePerGas' in header:
546+
normalized_header['baseFeePerGas'] = to_int(header['baseFeePerGas'])
545547
if 'chainname' in header:
546548
normalized_header['chainname'] = header['chainname']
547549
if 'chainnetwork' in header:

eth/tools/fixtures/helpers.py

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
Type,
1212
)
1313

14-
from eth_utils.toolz import first
14+
from eth_utils.toolz import (
15+
assoc,
16+
first,
17+
)
1518

1619
from eth_utils import (
1720
to_normalized_address,
@@ -133,6 +136,10 @@ def chain_vm_configuration(fixture: Dict[str, Any]) -> Iterable[Tuple[int, Type[
133136
return (
134137
(0, BerlinVM),
135138
)
139+
elif network == 'London':
140+
return (
141+
(0, LondonVM),
142+
)
136143
elif network == 'FrontierToHomesteadAt5':
137144
HomesteadVM = BaseHomesteadVM.configure(support_dao_fork=False)
138145
return (
@@ -177,23 +184,28 @@ def genesis_fields_from_fixture(fixture: Dict[str, Any]) -> Dict[str, Any]:
177184
Convert all genesis fields in a fixture to a dictionary of header fields and values.
178185
"""
179186

180-
return {
181-
'parent_hash': fixture['genesisBlockHeader']['parentHash'],
182-
'uncles_hash': fixture['genesisBlockHeader']['uncleHash'],
183-
'coinbase': fixture['genesisBlockHeader']['coinbase'],
184-
'state_root': fixture['genesisBlockHeader']['stateRoot'],
185-
'transaction_root': fixture['genesisBlockHeader']['transactionsTrie'],
186-
'receipt_root': fixture['genesisBlockHeader']['receiptTrie'],
187-
'bloom': fixture['genesisBlockHeader']['bloom'],
188-
'difficulty': fixture['genesisBlockHeader']['difficulty'],
189-
'block_number': fixture['genesisBlockHeader']['number'],
190-
'gas_limit': fixture['genesisBlockHeader']['gasLimit'],
191-
'gas_used': fixture['genesisBlockHeader']['gasUsed'],
192-
'timestamp': fixture['genesisBlockHeader']['timestamp'],
193-
'extra_data': fixture['genesisBlockHeader']['extraData'],
194-
'mix_hash': fixture['genesisBlockHeader']['mixHash'],
195-
'nonce': fixture['genesisBlockHeader']['nonce'],
187+
header_fields = fixture['genesisBlockHeader']
188+
base_fields = {
189+
'parent_hash': header_fields['parentHash'],
190+
'uncles_hash': header_fields['uncleHash'],
191+
'coinbase': header_fields['coinbase'],
192+
'state_root': header_fields['stateRoot'],
193+
'transaction_root': header_fields['transactionsTrie'],
194+
'receipt_root': header_fields['receiptTrie'],
195+
'bloom': header_fields['bloom'],
196+
'difficulty': header_fields['difficulty'],
197+
'block_number': header_fields['number'],
198+
'gas_limit': header_fields['gasLimit'],
199+
'gas_used': header_fields['gasUsed'],
200+
'timestamp': header_fields['timestamp'],
201+
'extra_data': header_fields['extraData'],
202+
'mix_hash': header_fields['mixHash'],
203+
'nonce': header_fields['nonce'],
196204
}
205+
if 'baseFeePerGas' in header_fields:
206+
return assoc(base_fields, 'base_fee_per_gas', header_fields['baseFeePerGas'])
207+
else:
208+
return base_fields
197209

198210

199211
def genesis_params_from_fixture(fixture: Dict[str, Any]) -> Dict[str, Any]:

eth/vm/forks/london/headers.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,25 @@ def create_header_from_parent(difficulty_fn: Callable[[BlockHeaderAPI, int], int
108108
header_params['timestamp'],
109109
)
110110

111+
# The general fill function doesn't recognize this custom field, so remove it
112+
configured_fee_per_gas = header_params.pop('base_fee_per_gas', None)
113+
111114
all_fields = fill_header_params_from_parent(parent_header, **header_params)
112115

113-
# must add the new field *after* filling, because the general fill function doesn't recognize it
114-
base_fee_per_gas = calculate_expected_base_fee_per_gas(parent_header)
115-
if 'base_fee_per_gas' in header_params and all_fields['base_fee_per_gas'] != base_fee_per_gas:
116-
raise ValidationError(
117-
f"Cannot select an invalid base_fee_per_gas of:"
118-
f" {all_fields['base_fee_per_gas']!r}, expected: {base_fee_per_gas}"
119-
)
116+
calculated_fee_per_gas = calculate_expected_base_fee_per_gas(parent_header)
117+
if configured_fee_per_gas is None:
118+
all_fields['base_fee_per_gas'] = calculated_fee_per_gas
120119
else:
121-
all_fields['base_fee_per_gas'] = base_fee_per_gas
120+
# Must not configure an invalid base fee. So verify that either:
121+
# 1. This is the genesis header, or
122+
# 2. The configured value matches the calculated value from the parent
123+
if parent_header is None or configured_fee_per_gas == calculated_fee_per_gas:
124+
all_fields['base_fee_per_gas'] = configured_fee_per_gas
125+
else:
126+
raise ValidationError(
127+
f"Cannot select an invalid base_fee_per_gas of:"
128+
f" {configured_fee_per_gas}, expected: {calculated_fee_per_gas}"
129+
)
122130

123131
new_header = LondonBlockHeader(**all_fields) # type:ignore
124132
return new_header

newsfragments/2022.internal.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
During fixture tests, verify that the generated genesis block matches the fixture's RLP-encoding.

tests/json-fixtures/blockchain/test_blockchain.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from eth.tools.rlp import (
1212
assert_mined_block_unchanged,
13+
assert_headers_eq,
1314
)
1415
from eth.tools._utils.normalization import (
1516
normalize_blockchain_fixtures,
@@ -24,6 +25,7 @@
2425
should_run_slow_tests,
2526
verify_state,
2627
)
28+
from eth.vm.header import HeaderSedes
2729

2830

2931
ROOT_PROJECT_DIR = Path(__file__).parents[3]
@@ -325,15 +327,22 @@ def test_blockchain_fixtures(fixture_data, fixture):
325327
except ValueError as e:
326328
raise AssertionError(f"could not load chain for {fixture_data}") from e
327329

328-
# TODO: find out if this is supposed to pass?
329-
# if 'genesisRLP' in fixture:
330-
# assert rlp.encode(genesis_header) == fixture['genesisRLP']
331-
332330
genesis_fields = genesis_fields_from_fixture(fixture)
333331

334332
genesis_block = chain.get_canonical_block_by_number(0)
335333
genesis_header = genesis_block.header
336334

335+
# Validate the genesis header RLP against the generated header
336+
if 'genesisRLP' in fixture:
337+
# Super hacky, but better than nothing: extract the header, then re-decode it
338+
fixture_decoded_block = rlp.decode(fixture['genesisRLP'])
339+
fixture_encoded_header = rlp.encode(fixture_decoded_block[0])
340+
fixture_header = rlp.decode(fixture_encoded_header, sedes=HeaderSedes)
341+
# Error message with pretty output if header doesn't match
342+
assert_headers_eq(fixture_header, genesis_header)
343+
# Last gut check that transactions & receipts are valid, too
344+
assert rlp.encode(genesis_block) == fixture['genesisRLP']
345+
337346
assert_imported_genesis_header_unchanged(genesis_fields, genesis_header)
338347

339348
# 1 - mine the genesis block

0 commit comments

Comments
 (0)