Skip to content

Commit a592ac1

Browse files
committed
Force forks to deal with blocks from previous forks
1 parent 534ee74 commit a592ac1

File tree

34 files changed

+610
-121
lines changed

34 files changed

+610
-121
lines changed

src/ethereum/arrow_glacier/blocks.py

Lines changed: 28 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, Union
12+
from typing import Optional, 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.london import blocks as previous_blocks
1720

1821
from ..crypto.hash import Hash32
1922
from .fork_types import Address, Bloom, Root
@@ -45,6 +48,13 @@ class Header:
4548
base_fee_per_gas: Uint
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:
@@ -80,3 +97,13 @@ class Receipt:
8097
cumulative_gas_used: Uint
8198
bloom: Bloom
8299
logs: Tuple[Log, ...]
100+
101+
102+
def header_base_fee_per_gas(header: AnyHeader) -> Optional[Uint]:
103+
"""
104+
Returns the `base_fee_per_gas` of the given header, or `None` for headers
105+
without that field.
106+
"""
107+
if isinstance(header, Header):
108+
return header.base_fee_per_gas
109+
return previous_blocks.header_base_fee_per_gas(header)

src/ethereum/arrow_glacier/fork.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,18 @@
2222
from ethereum.crypto.hash import Hash32, keccak256
2323
from ethereum.ethash import dataset_size, generate_cache, hashimoto_light
2424
from ethereum.exceptions import InvalidBlock, InvalidSenderError
25+
from ethereum.london import fork as previous_fork
2526

2627
from . import vm
27-
from .blocks import Block, Header, Log, Receipt
28+
from .blocks import (
29+
AnyBlock,
30+
AnyHeader,
31+
Block,
32+
Header,
33+
Log,
34+
Receipt,
35+
header_base_fee_per_gas,
36+
)
2837
from .bloom import logs_bloom
2938
from .fork_types import Address, Bloom, Root
3039
from .state import (
@@ -58,6 +67,7 @@
5867
GAS_LIMIT_ADJUSTMENT_FACTOR = Uint(1024)
5968
GAS_LIMIT_MINIMUM = Uint(5000)
6069
MINIMUM_DIFFICULTY = Uint(131072)
70+
INITIAL_BASE_FEE = Uint(1000000000)
6171
MAX_OMMER_DEPTH = Uint(6)
6272
BOMB_DELAY_BLOCKS = 10700000
6373
EMPTY_OMMER_HASH = keccak256(rlp.encode([]))
@@ -69,7 +79,7 @@ class BlockChain:
6979
History and current state of the block chain.
7080
"""
7181

72-
blocks: List[Block]
82+
blocks: List[AnyBlock]
7383
state: State
7484
chain_id: U64
7585

@@ -256,7 +266,7 @@ def calculate_base_fee_per_gas(
256266
return Uint(expected_base_fee_per_gas)
257267

258268

259-
def validate_header(header: Header, parent_header: Header) -> None:
269+
def validate_header(header: AnyHeader, parent_header: AnyHeader) -> None:
260270
"""
261271
Verifies a block header.
262272
@@ -274,15 +284,25 @@ def validate_header(header: Header, parent_header: Header) -> None:
274284
parent_header :
275285
Parent Header of the header to check for correctness
276286
"""
287+
if not isinstance(header, Header):
288+
assert not isinstance(parent_header, Header)
289+
return previous_fork.validate_header(header, parent_header)
290+
277291
if header.gas_used > header.gas_limit:
278292
raise InvalidBlock
279293

280-
expected_base_fee_per_gas = calculate_base_fee_per_gas(
281-
header.gas_limit,
282-
parent_header.gas_limit,
283-
parent_header.gas_used,
284-
parent_header.base_fee_per_gas,
285-
)
294+
expected_base_fee_per_gas = INITIAL_BASE_FEE
295+
parent_base_fee_per_gas = header_base_fee_per_gas(parent_header)
296+
if parent_base_fee_per_gas is not None:
297+
# For every block except the first, calculate the base fee per gas
298+
# based on the parent block.
299+
expected_base_fee_per_gas = calculate_base_fee_per_gas(
300+
header.gas_limit,
301+
parent_header.gas_limit,
302+
parent_header.gas_used,
303+
parent_base_fee_per_gas,
304+
)
305+
286306
if expected_base_fee_per_gas != header.base_fee_per_gas:
287307
raise InvalidBlock
288308

@@ -627,7 +647,7 @@ def apply_body(
627647

628648

629649
def validate_ommers(
630-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
650+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
631651
) -> None:
632652
"""
633653
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
@@ -14,6 +14,9 @@
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.muir_glacier 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/berlin/fork.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222
from ethereum.crypto.hash import Hash32, keccak256
2323
from ethereum.ethash import dataset_size, generate_cache, hashimoto_light
2424
from ethereum.exceptions import InvalidBlock, InvalidSenderError
25+
from ethereum.muir_glacier import fork as previous_fork
2526

2627
from . import vm
27-
from .blocks import Block, Header, Log, Receipt
28+
from .blocks import AnyBlock, AnyHeader, Block, Header, Log, Receipt
2829
from .bloom import logs_bloom
2930
from .fork_types import Address, Bloom, Root
3031
from .state import (
@@ -66,7 +67,7 @@ class BlockChain:
6667
History and current state of the block chain.
6768
"""
6869

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

@@ -190,7 +191,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
190191
chain.blocks = chain.blocks[-255:]
191192

192193

193-
def validate_header(header: Header, parent_header: Header) -> None:
194+
def validate_header(header: AnyHeader, parent_header: AnyHeader) -> None:
194195
"""
195196
Verifies a block header.
196197
@@ -208,6 +209,10 @@ def validate_header(header: Header, parent_header: Header) -> None:
208209
parent_header :
209210
Parent Header of the header to check for correctness
210211
"""
212+
if not isinstance(header, Header):
213+
assert not isinstance(parent_header, Header)
214+
return previous_fork.validate_header(header, parent_header)
215+
211216
parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
212217
if header.timestamp <= parent_header.timestamp:
213218
raise InvalidBlock
@@ -521,7 +526,7 @@ def apply_body(
521526

522527

523528
def validate_ommers(
524-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
529+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
525530
) -> None:
526531
"""
527532
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
@@ -22,9 +22,10 @@
2222
from ethereum.crypto.hash import Hash32, keccak256
2323
from ethereum.ethash import dataset_size, generate_cache, hashimoto_light
2424
from ethereum.exceptions import InvalidBlock, InvalidSenderError
25+
from ethereum.spurious_dragon import fork as previous_fork
2526

2627
from . import vm
27-
from .blocks import Block, Header, Log, Receipt
28+
from .blocks import AnyBlock, AnyHeader, Block, Header, Log, Receipt
2829
from .bloom import logs_bloom
2930
from .fork_types import Address, Bloom, Root
3031
from .state import (
@@ -62,7 +63,7 @@ class BlockChain:
6263
History and current state of the block chain.
6364
"""
6465

65-
blocks: List[Block]
66+
blocks: List[AnyBlock]
6667
state: State
6768
chain_id: U64
6869

@@ -186,7 +187,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
186187
chain.blocks = chain.blocks[-255:]
187188

188189

189-
def validate_header(header: Header, parent_header: Header) -> None:
190+
def validate_header(header: AnyHeader, parent_header: AnyHeader) -> None:
190191
"""
191192
Verifies a block header.
192193
@@ -204,6 +205,10 @@ def validate_header(header: Header, parent_header: Header) -> None:
204205
parent_header :
205206
Parent Header of the header to check for correctness
206207
"""
208+
if not isinstance(header, Header):
209+
assert not isinstance(parent_header, Header)
210+
return previous_fork.validate_header(header, parent_header)
211+
207212
parent_has_ommers = parent_header.ommers_hash != EMPTY_OMMER_HASH
208213
if header.timestamp <= parent_header.timestamp:
209214
raise InvalidBlock
@@ -511,7 +516,7 @@ def apply_body(
511516

512517

513518
def validate_ommers(
514-
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
519+
ommers: Tuple[AnyHeader, ...], block_header: Header, chain: BlockChain
515520
) -> None:
516521
"""
517522
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,11 +9,14 @@
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_types.bytes import Bytes, Bytes8, Bytes32
1515
from ethereum_types.frozen import slotted_freezable
1616
from ethereum_types.numeric import U64, U256, Uint
17+
from typing_extensions import TypeAlias
18+
19+
from ethereum.shanghai import blocks as previous_blocks
1720

1821
from ..crypto.hash import Hash32
1922
from .fork_types import Address, Bloom, Root
@@ -62,6 +65,13 @@ class Header:
6265
parent_beacon_block_root: Root
6366

6467

68+
AnyHeader: TypeAlias = Union[previous_blocks.AnyHeader, Header]
69+
"""
70+
Represents all headers that may have appeared in the blockchain before or in
71+
the current fork.
72+
"""
73+
74+
6575
@slotted_freezable
6676
@dataclass
6777
class Block:
@@ -75,6 +85,13 @@ class Block:
7585
withdrawals: Tuple[Withdrawal, ...]
7686

7787

88+
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
89+
"""
90+
Represents all blocks that may have appeared in the blockchain before or in the
91+
current fork.
92+
"""
93+
94+
7895
@slotted_freezable
7996
@dataclass
8097
class Log:
@@ -98,3 +115,13 @@ class Receipt:
98115
cumulative_gas_used: Uint
99116
bloom: Bloom
100117
logs: Tuple[Log, ...]
118+
119+
120+
def header_base_fee_per_gas(header: AnyHeader) -> Optional[Uint]:
121+
"""
122+
Returns the `base_fee_per_gas` of the given header, or `None` for headers
123+
without that field.
124+
"""
125+
if isinstance(header, Header):
126+
return header.base_fee_per_gas
127+
return previous_blocks.header_base_fee_per_gas(header)

0 commit comments

Comments
 (0)