Skip to content

Commit 6813313

Browse files
committed
Force forks to deal with blocks from previous forks
1 parent 51f2d6a commit 6813313

File tree

34 files changed

+624
-121
lines changed

34 files changed

+624
-121
lines changed

src/ethereum/arrow_glacier/blocks.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple, Union
12+
from typing import Optional, Tuple, Union
1313

1414
from ethereum_rlp import rlp
1515
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1616
from ethereum_types.frozen import slotted_freezable
1717
from ethereum_types.numeric import U256, Uint
18+
from typing_extensions import TypeAlias
19+
20+
from ethereum.london import blocks as previous_blocks
1821

1922
from ..crypto.hash import Hash32
2023
from .fork_types import Address, Bloom, Root
@@ -51,6 +54,13 @@ class Header:
5154
base_fee_per_gas: Uint
5255

5356

57+
AnyHeader: TypeAlias = Union[previous_blocks.AnyHeader, Header]
58+
"""
59+
Represents all headers that may have appeared in the blockchain before or in
60+
the current fork.
61+
"""
62+
63+
5464
@slotted_freezable
5565
@dataclass
5666
class Block:
@@ -63,6 +73,13 @@ class Block:
6373
ommers: Tuple[Header, ...]
6474

6575

76+
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
77+
"""
78+
Represents all blocks that may have appeared in the blockchain before or in the
79+
current fork.
80+
"""
81+
82+
6683
@slotted_freezable
6784
@dataclass
6885
class Log:
@@ -109,3 +126,13 @@ def decode_receipt(receipt: Union[Bytes, Receipt]) -> Receipt:
109126
return rlp.decode_to(Receipt, receipt[1:])
110127
else:
111128
return receipt
129+
130+
131+
def header_base_fee_per_gas(header: AnyHeader) -> Optional[Uint]:
132+
"""
133+
Returns the `base_fee_per_gas` of the given header, or `None` for headers
134+
without that field.
135+
"""
136+
if isinstance(header, Header):
137+
return header.base_fee_per_gas
138+
return previous_blocks.header_base_fee_per_gas(header)

src/ethereum/arrow_glacier/fork.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,19 @@
2626
InvalidBlock,
2727
InvalidSenderError,
2828
)
29+
from ethereum.london import fork as previous_fork
2930

3031
from . import vm
31-
from .blocks import Block, Header, Log, Receipt, encode_receipt
32+
from .blocks import (
33+
AnyBlock,
34+
AnyHeader,
35+
Block,
36+
Header,
37+
Log,
38+
Receipt,
39+
encode_receipt,
40+
header_base_fee_per_gas,
41+
)
3242
from .bloom import logs_bloom
3343
from .fork_types import Address
3444
from .state import (
@@ -63,6 +73,7 @@
6373
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)
6474
GAS_LIMIT_MINIMUM = Uint(5000)
6575
MINIMUM_DIFFICULTY = Uint(131072)
76+
INITIAL_BASE_FEE = Uint(1000000000)
6677
MAX_OMMER_DEPTH = Uint(6)
6778
BOMB_DELAY_BLOCKS = 10700000
6879
EMPTY_OMMER_HASH = keccak256(rlp.encode([]))
@@ -74,7 +85,7 @@ class BlockChain:
7485
History and current state of the block chain.
7586
"""
7687

77-
blocks: List[Block]
88+
blocks: List[AnyBlock]
7889
state: State
7990
chain_id: U64
8091

@@ -270,7 +281,7 @@ def calculate_base_fee_per_gas(
270281
return Uint(expected_base_fee_per_gas)
271282

272283

273-
def validate_header(chain: BlockChain, header: Header) -> None:
284+
def validate_header(chain: BlockChain, header: AnyHeader) -> None:
274285
"""
275286
Verifies a block header.
276287
@@ -304,15 +315,25 @@ def validate_header(chain: BlockChain, header: Header) -> None:
304315
parent_header_number - first_block_number
305316
].header
306317

318+
if not isinstance(header, Header):
319+
assert not isinstance(parent_header, Header)
320+
return previous_fork.validate_header(chain, header)
321+
307322
if header.gas_used > header.gas_limit:
308323
raise InvalidBlock
309324

310-
expected_base_fee_per_gas = calculate_base_fee_per_gas(
311-
header.gas_limit,
312-
parent_header.gas_limit,
313-
parent_header.gas_used,
314-
parent_header.base_fee_per_gas,
315-
)
325+
expected_base_fee_per_gas = INITIAL_BASE_FEE
326+
parent_base_fee_per_gas = header_base_fee_per_gas(parent_header)
327+
if parent_base_fee_per_gas is not None:
328+
# For every block except the first, calculate the base fee per gas
329+
# based on the parent block.
330+
expected_base_fee_per_gas = calculate_base_fee_per_gas(
331+
header.gas_limit,
332+
parent_header.gas_limit,
333+
parent_header.gas_used,
334+
parent_base_fee_per_gas,
335+
)
336+
316337
if expected_base_fee_per_gas != header.base_fee_per_gas:
317338
raise InvalidBlock
318339

@@ -554,7 +575,7 @@ def apply_body(
554575

555576

556577
def validate_ommers(
557-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
578+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
558579
) -> None:
559580
"""
560581
Validates the ommers mentioned in the block.

src/ethereum/berlin/blocks.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1616
from ethereum_types.frozen import slotted_freezable
1717
from ethereum_types.numeric import U256, Uint
18+
from typing_extensions import TypeAlias
19+
20+
from ethereum.muir_glacier import blocks as previous_blocks
1821

1922
from ..crypto.hash import Hash32
2023
from .fork_types import Address, Bloom, Root
@@ -45,6 +48,13 @@ class Header:
4548
nonce: Bytes8
4649

4750

51+
AnyHeader: TypeAlias = Union[previous_blocks.AnyHeader, Header]
52+
"""
53+
Represents all headers that may have appeared in the blockchain before or in
54+
the current fork.
55+
"""
56+
57+
4858
@slotted_freezable
4959
@dataclass
5060
class Block:
@@ -57,6 +67,13 @@ class Block:
5767
ommers: Tuple[Header, ...]
5868

5969

70+
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
71+
"""
72+
Represents all blocks that may have appeared in the blockchain before or in the
73+
current fork.
74+
"""
75+
76+
6077
@slotted_freezable
6178
@dataclass
6279
class Log:

src/ethereum/berlin/fork.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,18 @@
2525
InvalidBlock,
2626
InvalidSenderError,
2727
)
28+
from ethereum.muir_glacier import fork as previous_fork
2829

2930
from . import vm
30-
from .blocks import Block, Header, Log, Receipt, encode_receipt
31+
from .blocks import (
32+
AnyBlock,
33+
AnyHeader,
34+
Block,
35+
Header,
36+
Log,
37+
Receipt,
38+
encode_receipt,
39+
)
3140
from .bloom import logs_bloom
3241
from .fork_types import Address
3342
from .state import (
@@ -70,7 +79,7 @@ class BlockChain:
7079
History and current state of the block chain.
7180
"""
7281

73-
blocks: List[Block]
82+
blocks: List[AnyBlock]
7483
state: State
7584
chain_id: U64
7685

@@ -203,7 +212,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
203212
chain.blocks = chain.blocks[-255:]
204213

205214

206-
def validate_header(chain: BlockChain, header: Header) -> None:
215+
def validate_header(chain: BlockChain, header: AnyHeader) -> None:
207216
"""
208217
Verifies a block header.
209218
@@ -240,6 +249,10 @@ def validate_header(chain: BlockChain, header: Header) -> None:
240249
if header.gas_used > header.gas_limit:
241250
raise InvalidBlock
242251

252+
if not isinstance(header, Header):
253+
assert not isinstance(parent_header, Header)
254+
return previous_fork.validate_header(chain, header)
255+
243256
parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
244257
if header.timestamp <= parent_header.timestamp:
245258
raise InvalidBlock
@@ -461,7 +474,7 @@ def apply_body(
461474

462475

463476
def validate_ommers(
464-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
477+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
465478
) -> None:
466479
"""
467480
Validates the ommers mentioned in the block.

src/ethereum/byzantium/blocks.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple
12+
from typing import Tuple, Union
1313

1414
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1515
from ethereum_types.frozen import slotted_freezable
1616
from ethereum_types.numeric import U256, Uint
17+
from typing_extensions import TypeAlias
18+
19+
from ethereum.spurious_dragon import blocks as previous_blocks
1720

1821
from ..crypto.hash import Hash32
1922
from .fork_types import Address, Bloom, Root
@@ -44,6 +47,13 @@ class Header:
4447
nonce: Bytes8
4548

4649

50+
AnyHeader: TypeAlias = Union[previous_blocks.AnyHeader, Header]
51+
"""
52+
Represents all headers that may have appeared in the blockchain before or in
53+
the current fork.
54+
"""
55+
56+
4757
@slotted_freezable
4858
@dataclass
4959
class Block:
@@ -56,6 +66,13 @@ class Block:
5666
ommers: Tuple[Header, ...]
5767

5868

69+
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
70+
"""
71+
Represents all blocks that may have appeared in the blockchain before or in the
72+
current fork.
73+
"""
74+
75+
5976
@slotted_freezable
6077
@dataclass
6178
class Log:

src/ethereum/byzantium/fork.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
InvalidBlock,
2525
InvalidSenderError,
2626
)
27+
from ethereum.spurious_dragon import fork as previous_fork
2728

2829
from . import vm
29-
from .blocks import Block, Header, Log, Receipt
30+
from .blocks import AnyBlock, AnyHeader, Block, Header, Log, Receipt
3031
from .bloom import logs_bloom
3132
from .fork_types import Address
3233
from .state import (
@@ -65,7 +66,7 @@ class BlockChain:
6566
History and current state of the block chain.
6667
"""
6768

68-
blocks: List[Block]
69+
blocks: List[AnyBlock]
6970
state: State
7071
chain_id: U64
7172

@@ -198,7 +199,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
198199
chain.blocks = chain.blocks[-255:]
199200

200201

201-
def validate_header(chain: BlockChain, header: Header) -> None:
202+
def validate_header(chain: BlockChain, header: AnyHeader) -> None:
202203
"""
203204
Verifies a block header.
204205
@@ -235,6 +236,10 @@ def validate_header(chain: BlockChain, header: Header) -> None:
235236
if header.gas_used > header.gas_limit:
236237
raise InvalidBlock
237238

239+
if not isinstance(header, Header):
240+
assert not isinstance(parent_header, Header)
241+
return previous_fork.validate_header(chain, header)
242+
238243
parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
239244
if header.timestamp <= parent_header.timestamp:
240245
raise InvalidBlock
@@ -453,7 +458,7 @@ def apply_body(
453458

454459

455460
def validate_ommers(
456-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
461+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
457462
) -> None:
458463
"""
459464
Validates the ommers mentioned in the block.

src/ethereum/cancun/blocks.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple, Union
12+
from typing import Optional, Tuple, Union
1313

1414
from ethereum_rlp import rlp
1515
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1616
from ethereum_types.frozen import slotted_freezable
1717
from ethereum_types.numeric import U64, U256, Uint
18+
from typing_extensions import TypeAlias
19+
20+
from ethereum.shanghai import blocks as previous_blocks
1821

1922
from ..crypto.hash import Hash32
2023
from .fork_types import Address, Bloom, Root
@@ -69,6 +72,13 @@ class Header:
6972
parent_beacon_block_root: Root
7073

7174

75+
AnyHeader: TypeAlias = Union[previous_blocks.AnyHeader, Header]
76+
"""
77+
Represents all headers that may have appeared in the blockchain before or in
78+
the current fork.
79+
"""
80+
81+
7282
@slotted_freezable
7383
@dataclass
7484
class Block:
@@ -82,6 +92,13 @@ class Block:
8292
withdrawals: Tuple[Withdrawal, ...]
8393

8494

95+
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
96+
"""
97+
Represents all blocks that may have appeared in the blockchain before or in the
98+
current fork.
99+
"""
100+
101+
85102
@slotted_freezable
86103
@dataclass
87104
class Log:
@@ -130,3 +147,13 @@ def decode_receipt(receipt: Union[Bytes, Receipt]) -> Receipt:
130147
return rlp.decode_to(Receipt, receipt[1:])
131148
else:
132149
return receipt
150+
151+
152+
def header_base_fee_per_gas(header: AnyHeader) -> Optional[Uint]:
153+
"""
154+
Returns the `base_fee_per_gas` of the given header, or `None` for headers
155+
without that field.
156+
"""
157+
if isinstance(header, Header):
158+
return header.base_fee_per_gas
159+
return previous_blocks.header_base_fee_per_gas(header)

0 commit comments

Comments
 (0)