Skip to content

Commit f77982c

Browse files
committed
TEMP:
prefer exceptions for base gas fee to None, where feasible update mainnet block number for London pass header sedes class in to APIs that used to assume a stable header spec, like when decoding block header uncles track header sedes in VM (unnecessary?), all_header_sedes infer sedes class of uncles from header that has the uncles eth.db.chain.get_block_uncles API change use new agnostic header deserializer when decoding unknown header bytes (eg~ look up hash by header) increase default gas price in tests to 10 gwei to easily out-price the 1559 min gas fee of 1gwei make old transactions understand max_priority_fee_per_gas and max_fee_per_gas (just return the gas_price, as the 1559 spec suggests) validate the transaction nonce on new london transactions enable creating a genesis London header (was hard-coded to pre-London-style) generally allow create_header_from_parent to accept a None parent, for genesis creation use the correct VM's block header when creating a temp block for txn evaluation Update tests that were configured with a gas price of < 1 gwei Drop support for Header.from_parent which is essentially always wrong. Should use vm_class.create_header_from_parent instead.
1 parent 5b205e6 commit f77982c

32 files changed

+398
-290
lines changed

eth/_utils/headers.py

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,73 @@
77

88
from eth.abc import BlockHeaderAPI
99
from eth.constants import (
10+
BLANK_ROOT_HASH,
11+
EMPTY_UNCLE_HASH,
12+
GENESIS_BLOCK_NUMBER,
1013
GENESIS_GAS_LIMIT,
14+
GENESIS_NONCE,
15+
GENESIS_PARENT_HASH,
1116
GAS_LIMIT_EMA_DENOMINATOR,
1217
GAS_LIMIT_ADJUSTMENT_FACTOR,
1318
GAS_LIMIT_MINIMUM,
1419
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR,
1520
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR,
21+
ZERO_ADDRESS,
22+
ZERO_HASH32,
1623
)
1724
from eth.rlp.headers import (
1825
BlockHeader,
1926
)
2027

2128

29+
def fill_header_params_from_parent(
30+
parent: BlockHeaderAPI,
31+
gas_limit: int,
32+
difficulty: int,
33+
timestamp: int,
34+
coinbase: Address = ZERO_ADDRESS,
35+
nonce: bytes = None,
36+
extra_data: bytes = None,
37+
transaction_root: bytes = None,
38+
state_root: bytes = None,
39+
mix_hash: bytes = None,
40+
receipt_root: bytes = None) -> 'BlockHeaderAPI':
41+
42+
if parent is None:
43+
parent_hash = GENESIS_PARENT_HASH
44+
block_number = GENESIS_BLOCK_NUMBER
45+
if state_root is None:
46+
raise ValueError(f"Must set state root on genesis block")
47+
else:
48+
parent_hash = parent.hash
49+
block_number = parent.block_number + 1
50+
51+
if state_root is None:
52+
state_root = parent.state_root
53+
54+
header_kwargs: Dict[str, HeaderParams] = {
55+
'parent_hash': parent_hash,
56+
'coinbase': coinbase,
57+
'state_root': state_root,
58+
'gas_limit': gas_limit,
59+
'difficulty': difficulty,
60+
'block_number': block_number,
61+
'timestamp': timestamp,
62+
}
63+
if nonce is not None:
64+
header_kwargs['nonce'] = nonce
65+
if extra_data is not None:
66+
header_kwargs['extra_data'] = extra_data
67+
if transaction_root is not None:
68+
header_kwargs['transaction_root'] = transaction_root
69+
if receipt_root is not None:
70+
header_kwargs['receipt_root'] = receipt_root
71+
if mix_hash is not None:
72+
header_kwargs['mix_hash'] = mix_hash
73+
74+
return header_kwargs
75+
76+
2277
def compute_gas_limit_bounds(parent: BlockHeaderAPI) -> Tuple[int, int]:
2378
"""
2479
Compute the boundaries for the block gas limit based on the parent block.
@@ -29,7 +84,7 @@ def compute_gas_limit_bounds(parent: BlockHeaderAPI) -> Tuple[int, int]:
2984
return lower_bound, upper_bound
3085

3186

32-
def compute_gas_limit(parent_header: BlockHeaderAPI, gas_limit_floor: int) -> int:
87+
def compute_gas_limit(parent_header: BlockHeaderAPI, genesis_gas_limit: int) -> int:
3388
"""
3489
A simple strategy for adjusting the gas limit.
3590
@@ -38,21 +93,24 @@ def compute_gas_limit(parent_header: BlockHeaderAPI, gas_limit_floor: int) -> in
3893
- decrease by 1/1024th of the gas limit from the previous block
3994
- increase by 50% of the total gas used by the previous block
4095
41-
If the value is less than the given `gas_limit_floor`:
96+
If the value is less than the given `genesis_gas_limit`:
4297
4398
- increase the gas limit by 1/1024th of the gas limit from the previous block.
4499
45100
If the value is less than the GAS_LIMIT_MINIMUM:
46101
47102
- use the GAS_LIMIT_MINIMUM as the new gas limit.
48103
"""
49-
if gas_limit_floor < GAS_LIMIT_MINIMUM:
104+
if genesis_gas_limit < GAS_LIMIT_MINIMUM:
50105
raise ValueError(
51-
"The `gas_limit_floor` value must be greater than the "
52-
f"GAS_LIMIT_MINIMUM. Got {gas_limit_floor}. Must be greater than "
106+
"The `genesis_gas_limit` value must be greater than the "
107+
f"GAS_LIMIT_MINIMUM. Got {genesis_gas_limit}. Must be greater than "
53108
f"{GAS_LIMIT_MINIMUM}"
54109
)
55110

111+
if parent_header is None:
112+
return genesis_gas_limit
113+
56114
decay = parent_header.gas_limit // GAS_LIMIT_EMA_DENOMINATOR
57115

58116
if parent_header.gas_used:
@@ -73,40 +131,7 @@ def compute_gas_limit(parent_header: BlockHeaderAPI, gas_limit_floor: int) -> in
73131

74132
if gas_limit < GAS_LIMIT_MINIMUM:
75133
return GAS_LIMIT_MINIMUM
76-
elif gas_limit < gas_limit_floor:
134+
elif gas_limit < genesis_gas_limit:
77135
return parent_header.gas_limit + decay
78136
else:
79137
return gas_limit
80-
81-
82-
def generate_header_from_parent_header(
83-
compute_difficulty_fn: Callable[[BlockHeaderAPI, int], int],
84-
parent_header: BlockHeaderAPI,
85-
coinbase: Address,
86-
timestamp: Optional[int] = None,
87-
extra_data: bytes = b'') -> BlockHeader:
88-
"""
89-
Generate BlockHeader from state_root and parent_header
90-
"""
91-
if timestamp is None:
92-
timestamp = max(int(time.time()), parent_header.timestamp + 1)
93-
elif timestamp <= parent_header.timestamp:
94-
raise ValueError(
95-
f"header.timestamp ({timestamp}) should be higher than"
96-
f"parent_header.timestamp ({parent_header.timestamp})"
97-
)
98-
header = BlockHeader(
99-
difficulty=compute_difficulty_fn(parent_header, timestamp),
100-
block_number=(parent_header.block_number + 1),
101-
gas_limit=compute_gas_limit(
102-
parent_header,
103-
gas_limit_floor=GENESIS_GAS_LIMIT,
104-
),
105-
timestamp=timestamp,
106-
parent_hash=parent_header.hash,
107-
state_root=parent_header.state_root,
108-
coinbase=coinbase,
109-
extra_data=extra_data,
110-
)
111-
112-
return header

eth/abc.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class MiningHeaderAPI(ABC):
7474
gas_used: int
7575
timestamp: int
7676
extra_data: bytes
77-
base_fee_per_gas: int # EIP-1559
77+
base_fee_per_gas: int # EIP-1559, set to None in pre-London header
7878

7979
@property
8080
@abstractmethod
@@ -337,7 +337,10 @@ def nonce(self) -> int:
337337

338338
@property
339339
@abstractmethod
340-
def gas_price(self) -> Optional[int]:
340+
def gas_price(self) -> int:
341+
"""
342+
Will raise :cls:`AttributeError` if get or set on a 1559 transaction.
343+
"""
341344
...
342345

343346
@property
@@ -2877,8 +2880,9 @@ def get_computation(self,
28772880
#
28782881
# Transaction context
28792882
#
2883+
@classmethod
28802884
@abstractmethod
2881-
def get_transaction_context_class(self) -> Type[TransactionContextAPI]:
2885+
def get_transaction_context_class(cls) -> Type[TransactionContextAPI]:
28822886
"""
28832887
Return the :class:`~eth.vm.transaction_context.BaseTransactionContext` class that the
28842888
state class uses.
@@ -2990,6 +2994,36 @@ def get_fee_recipient(cls, header: BlockHeaderAPI) -> Address:
29902994
...
29912995

29922996

2997+
2998+
class BlockHeaderSedesAPI(ABC):
2999+
"""
3000+
Serialize and deserialize RLP for a header.
3001+
3002+
The header may be one of several definitions, like a London (EIP-1559) or
3003+
pre-London header.
3004+
"""
3005+
3006+
@classmethod
3007+
@abstractmethod
3008+
def deserialize(cls, encoded: List[bytes]) -> BlockHeaderAPI:
3009+
"""
3010+
Extract a header from an encoded RLP object.
3011+
3012+
This method is used by rlp.decode(..., sedes=TransactionBuilderAPI).
3013+
"""
3014+
...
3015+
3016+
@classmethod
3017+
@abstractmethod
3018+
def serialize(cls, obj: BlockHeaderAPI) -> List[bytes]:
3019+
"""
3020+
Encode a header to a series of bytes used by RLP.
3021+
3022+
This method is used by rlp.encode(obj).
3023+
"""
3024+
...
3025+
3026+
29933027
class VirtualMachineAPI(ConfigurableAPI):
29943028
"""
29953029
The :class:`~eth.abc.VirtualMachineAPI` class represents the Chain rules for a
@@ -3008,6 +3042,7 @@ class VirtualMachineAPI(ConfigurableAPI):
30083042
extra_data_max_bytes: ClassVar[int]
30093043
consensus_class: Type[ConsensusAPI]
30103044
consensus_context: ConsensusContextAPI
3045+
all_header_sedes: ClassVar[Type[BlockHeaderSedesAPI]]
30113046

30123047
@abstractmethod
30133048
def __init__(self,

eth/chains/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
)
2323
from eth_utils.toolz import (
2424
concatv,
25+
keyfilter,
2526
sliding_window,
2627
)
2728

@@ -249,7 +250,7 @@ def from_genesis(cls,
249250
f"Expected {genesis_params['state_root']!r}"
250251
)
251252

252-
genesis_header = BlockHeader(**genesis_params)
253+
genesis_header = genesis_vm_class.create_header_from_parent(None, **genesis_params)
253254
return cls.from_genesis_header(base_db, genesis_header)
254255

255256
@classmethod
@@ -497,6 +498,7 @@ def persist_block(
497498
if perform_validation:
498499
self.validate_block(block)
499500

501+
vm = self.get_vm(block.header)
500502
(
501503
new_canonical_hashes,
502504
old_canonical_hashes,

eth/chains/mainnet/constants.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@
5858
#
5959
BERLIN_MAINNET_BLOCK = BlockNumber(12244000)
6060

61-
6261
#
6362
# London Block
6463
#
65-
LONDON_MAINNET_BLOCK = BlockNumber(12244001) # TODO change to actual when known
64+
LONDON_MAINNET_BLOCK = BlockNumber(12965000)

eth/db/chain.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from eth.abc import (
2626
BlockAPI,
2727
BlockHeaderAPI,
28+
BlockHeaderSedesAPI,
2829
ChainDatabaseAPI,
2930
DatabaseAPI,
3031
AtomicDatabaseAPI,
@@ -154,7 +155,8 @@ def _update_header_chain_gaps(
154155
#
155156
# Header API
156157
#
157-
def get_block_uncles(self, uncles_hash: Hash32) -> Tuple[BlockHeaderAPI, ...]:
158+
def get_block_uncles(self, niece_header: BlockHeader) -> Tuple[BlockHeaderAPI, ...]:
159+
uncles_hash = niece_header.uncles_hash
158160
validate_word(uncles_hash, title="Uncles Hash")
159161
if uncles_hash == EMPTY_UNCLE_HASH:
160162
return ()
@@ -165,7 +167,8 @@ def get_block_uncles(self, uncles_hash: Hash32) -> Tuple[BlockHeaderAPI, ...]:
165167
f"No uncles found for hash {uncles_hash!r}"
166168
) from exc
167169
else:
168-
return tuple(rlp.decode(encoded_uncles, sedes=rlp.sedes.CountableList(BlockHeader)))
170+
header_sedes = niece_header
171+
return tuple(rlp.decode(encoded_uncles, sedes=rlp.sedes.CountableList(header_sedes)))
169172

170173
@classmethod
171174
def _decanonicalize_old_headers(
@@ -261,7 +264,7 @@ def _persist_block(
261264
cls._add_transaction_to_canonical_chain(db, transaction_hash, header, index)
262265

263266
if block.uncles:
264-
uncles_hash = cls._persist_uncles(db, block.uncles)
267+
uncles_hash = cls._persist_uncles(db, block.uncles, block.header)
265268
else:
266269
uncles_hash = EMPTY_UNCLE_HASH
267270
if uncles_hash != block.header.uncles_hash:
@@ -275,15 +278,22 @@ def _persist_block(
275278
cls._update_chain_gaps(db, block)
276279
return new_canonical_hashes, old_canonical_hashes
277280

278-
def persist_uncles(self, uncles: Tuple[BlockHeaderAPI]) -> Hash32:
279-
return self._persist_uncles(self.db, uncles)
281+
def persist_uncles(
282+
self,
283+
uncles: Tuple[BlockHeaderAPI],
284+
header_sedes: BlockHeaderSedesAPI) -> Hash32:
285+
return self._persist_uncles(self.db, uncles, header_sedes)
280286

281287
@staticmethod
282-
def _persist_uncles(db: DatabaseAPI, uncles: Tuple[BlockHeaderAPI, ...]) -> Hash32:
288+
def _persist_uncles(
289+
db: DatabaseAPI,
290+
uncles: Tuple[BlockHeaderAPI, ...],
291+
header_sedes: BlockHeaderSedesAPI) -> Hash32:
292+
283293
uncles_hash = keccak(rlp.encode(uncles))
284294
db.set(
285295
uncles_hash,
286-
rlp.encode(uncles, sedes=rlp.sedes.CountableList(BlockHeader)))
296+
rlp.encode(uncles, sedes=rlp.sedes.CountableList(header_sedes)))
287297
return uncles_hash
288298

289299
#

eth/db/header.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@
5656
validate_block_number,
5757
validate_word,
5858
)
59-
from eth.vm.forks.london.blocks import (
60-
LondonBlockHeader
59+
from eth.vm.forks.london.headers import (
60+
LondonBackwardsHeader,
6161
)
6262

6363
from rlp.exceptions import (
@@ -625,8 +625,10 @@ def _add_block_number_to_hash_lookup(db: DatabaseAPI, header: BlockHeaderAPI) ->
625625
# be looking up recent blocks.
626626
@functools.lru_cache(128)
627627
def _decode_block_header(header_rlp: bytes) -> BlockHeaderAPI:
628-
try:
629-
return rlp.decode(header_rlp, sedes=BlockHeader)
630-
except ObjectDeserializationError:
631-
# could be a new >=London block header
632-
return rlp.decode(header_rlp, sedes=LondonBlockHeader)
628+
# Use a deserialization class that can handle any type of header.
629+
# This feels a little hack-y, but we don't know the shape of the header
630+
# at this point. It could be a pre-London header, or a post-London
631+
# header, which includes the base fee. So we use a class that simply
632+
# checks both. Ideally, it will try London first, since all new headers will
633+
# be valid for London (until the next fork that breaks it).
634+
return rlp.decode(header_rlp, sedes=LondonBackwardsHeader)

eth/estimators/gas.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def binary_gas_search(state: StateAPI,
6363
maximum_transaction = cast(SignedTransactionAPI, SpoofTransaction(
6464
transaction,
6565
gas=state.gas_limit,
66+
# TODO EIP-1559 update
6667
gas_price=0,
6768
))
6869
error = _get_computation_error(state, maximum_transaction)

0 commit comments

Comments
 (0)