Skip to content

Commit d5b2b6b

Browse files
committed
More strict bounds on ommer types
1 parent 29b8abf commit d5b2b6b

File tree

25 files changed

+608
-40
lines changed

25 files changed

+608
-40
lines changed

src/ethereum/arrow_glacier/blocks.py

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

14+
from ethereum_rlp import rlp
1415
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1516
from ethereum_types.frozen import slotted_freezable
1617
from ethereum_types.numeric import U256, Uint
1718
from typing_extensions import TypeAlias
1819

20+
from ethereum.exceptions import InvalidBlock
1921
from ethereum.london import blocks as previous_blocks
2022

2123
from ..crypto.hash import Hash32
@@ -55,6 +57,42 @@ class Header:
5557
"""
5658

5759

60+
def decode_header(raw_header: rlp.Simple) -> AnyHeader:
61+
"""
62+
Convert `raw_header` from raw sequences and bytes to a structured block
63+
header.
64+
65+
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
66+
to this fork, decodes it accordingly. If not, this function forwards to the
67+
preceding fork where the process is repeated.
68+
"""
69+
from . import FORK_CRITERIA
70+
71+
# First, ensure that `raw_header` is not `bytes` (and is therefore a
72+
# sequence.)
73+
if isinstance(raw_header, bytes):
74+
raise InvalidBlock("header is bytes, expected sequence")
75+
76+
# Next, extract the block number and timestamp (which are always at index 8
77+
# and 11 respectively.)
78+
raw_number = raw_header[8]
79+
if not isinstance(raw_number, bytes):
80+
raise InvalidBlock("header number is sequence, expected bytes")
81+
number = Uint.from_be_bytes(raw_number)
82+
83+
raw_timestamp = raw_header[11]
84+
if not isinstance(raw_timestamp, bytes):
85+
raise InvalidBlock("header timestamp is sequence, expected bytes")
86+
timestamp = U256.from_be_bytes(raw_timestamp)
87+
88+
# Finally, check if this header belongs to this fork.
89+
if FORK_CRITERIA.check(number, timestamp):
90+
return rlp.deserialize_to(Header, raw_header)
91+
92+
# If it doesn't, forward to the preceding fork.
93+
return previous_blocks.decode_header(raw_header)
94+
95+
5896
@slotted_freezable
5997
@dataclass
6098
class Block:
@@ -64,7 +102,7 @@ class Block:
64102

65103
header: Header
66104
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
67-
ommers: Tuple[AnyHeader, ...]
105+
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
68106

69107

70108
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]

src/ethereum/berlin/blocks.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple, Union
12+
from typing import Annotated, Tuple, Union
1313

14+
from ethereum_rlp import rlp
1415
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1516
from ethereum_types.frozen import slotted_freezable
1617
from ethereum_types.numeric import U256, Uint
1718
from typing_extensions import TypeAlias
1819

20+
from ethereum.exceptions import InvalidBlock
1921
from ethereum.muir_glacier import blocks as previous_blocks
2022

2123
from ..crypto.hash import Hash32
@@ -54,6 +56,42 @@ class Header:
5456
"""
5557

5658

59+
def decode_header(raw_header: rlp.Simple) -> AnyHeader:
60+
"""
61+
Convert `raw_header` from raw sequences and bytes to a structured block
62+
header.
63+
64+
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
65+
to this fork, decodes it accordingly. If not, this function forwards to the
66+
preceding fork where the process is repeated.
67+
"""
68+
from . import FORK_CRITERIA
69+
70+
# First, ensure that `raw_header` is not `bytes` (and is therefore a
71+
# sequence.)
72+
if isinstance(raw_header, bytes):
73+
raise InvalidBlock("header is bytes, expected sequence")
74+
75+
# Next, extract the block number and timestamp (which are always at index 8
76+
# and 11 respectively.)
77+
raw_number = raw_header[8]
78+
if not isinstance(raw_number, bytes):
79+
raise InvalidBlock("header number is sequence, expected bytes")
80+
number = Uint.from_be_bytes(raw_number)
81+
82+
raw_timestamp = raw_header[11]
83+
if not isinstance(raw_timestamp, bytes):
84+
raise InvalidBlock("header timestamp is sequence, expected bytes")
85+
timestamp = U256.from_be_bytes(raw_timestamp)
86+
87+
# Finally, check if this header belongs to this fork.
88+
if FORK_CRITERIA.check(number, timestamp):
89+
return rlp.deserialize_to(Header, raw_header)
90+
91+
# If it doesn't, forward to the preceding fork.
92+
return previous_blocks.decode_header(raw_header)
93+
94+
5795
@slotted_freezable
5896
@dataclass
5997
class Block:
@@ -63,7 +101,7 @@ class Block:
63101

64102
header: Header
65103
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
66-
ommers: Tuple[AnyHeader, ...]
104+
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
67105

68106

69107
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]

src/ethereum/byzantium/blocks.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple, Union
12+
from typing import Annotated, Tuple, Union
1313

14+
from ethereum_rlp import rlp
1415
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1516
from ethereum_types.frozen import slotted_freezable
1617
from ethereum_types.numeric import U256, Uint
1718
from typing_extensions import TypeAlias
1819

20+
from ethereum.exceptions import InvalidBlock
1921
from ethereum.spurious_dragon import blocks as previous_blocks
2022

2123
from ..crypto.hash import Hash32
@@ -54,6 +56,42 @@ class Header:
5456
"""
5557

5658

59+
def decode_header(raw_header: rlp.Simple) -> AnyHeader:
60+
"""
61+
Convert `raw_header` from raw sequences and bytes to a structured block
62+
header.
63+
64+
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
65+
to this fork, decodes it accordingly. If not, this function forwards to the
66+
preceding fork where the process is repeated.
67+
"""
68+
from . import FORK_CRITERIA
69+
70+
# First, ensure that `raw_header` is not `bytes` (and is therefore a
71+
# sequence.)
72+
if isinstance(raw_header, bytes):
73+
raise InvalidBlock("header is bytes, expected sequence")
74+
75+
# Next, extract the block number and timestamp (which are always at index 8
76+
# and 11 respectively.)
77+
raw_number = raw_header[8]
78+
if not isinstance(raw_number, bytes):
79+
raise InvalidBlock("header number is sequence, expected bytes")
80+
number = Uint.from_be_bytes(raw_number)
81+
82+
raw_timestamp = raw_header[11]
83+
if not isinstance(raw_timestamp, bytes):
84+
raise InvalidBlock("header timestamp is sequence, expected bytes")
85+
timestamp = U256.from_be_bytes(raw_timestamp)
86+
87+
# Finally, check if this header belongs to this fork.
88+
if FORK_CRITERIA.check(number, timestamp):
89+
return rlp.deserialize_to(Header, raw_header)
90+
91+
# If it doesn't, forward to the preceding fork.
92+
return previous_blocks.decode_header(raw_header)
93+
94+
5795
@slotted_freezable
5896
@dataclass
5997
class Block:
@@ -63,7 +101,7 @@ class Block:
63101

64102
header: Header
65103
transactions: Tuple[Transaction, ...]
66-
ommers: Tuple[AnyHeader, ...]
104+
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
67105

68106

69107
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]

src/ethereum/cancun/blocks.py

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

14+
from ethereum_rlp import rlp
1415
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1516
from ethereum_types.frozen import slotted_freezable
1617
from ethereum_types.numeric import U64, U256, Uint
1718
from typing_extensions import TypeAlias
1819

20+
from ethereum.exceptions import InvalidBlock
1921
from ethereum.shanghai import blocks as previous_blocks
2022

2123
from ..crypto.hash import Hash32
@@ -72,6 +74,42 @@ class Header:
7274
"""
7375

7476

77+
def decode_header(raw_header: rlp.Simple) -> AnyHeader:
78+
"""
79+
Convert `raw_header` from raw sequences and bytes to a structured block
80+
header.
81+
82+
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
83+
to this fork, decodes it accordingly. If not, this function forwards to the
84+
preceding fork where the process is repeated.
85+
"""
86+
from . import FORK_CRITERIA
87+
88+
# First, ensure that `raw_header` is not `bytes` (and is therefore a
89+
# sequence.)
90+
if isinstance(raw_header, bytes):
91+
raise InvalidBlock("header is bytes, expected sequence")
92+
93+
# Next, extract the block number and timestamp (which are always at index 8
94+
# and 11 respectively.)
95+
raw_number = raw_header[8]
96+
if not isinstance(raw_number, bytes):
97+
raise InvalidBlock("header number is sequence, expected bytes")
98+
number = Uint.from_be_bytes(raw_number)
99+
100+
raw_timestamp = raw_header[11]
101+
if not isinstance(raw_timestamp, bytes):
102+
raise InvalidBlock("header timestamp is sequence, expected bytes")
103+
timestamp = U256.from_be_bytes(raw_timestamp)
104+
105+
# Finally, check if this header belongs to this fork.
106+
if FORK_CRITERIA.check(number, timestamp):
107+
return rlp.deserialize_to(Header, raw_header)
108+
109+
# If it doesn't, forward to the preceding fork.
110+
return previous_blocks.decode_header(raw_header)
111+
112+
75113
@slotted_freezable
76114
@dataclass
77115
class Block:
@@ -81,7 +119,7 @@ class Block:
81119

82120
header: Header
83121
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
84-
ommers: Tuple[AnyHeader, ...]
122+
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
85123
withdrawals: Tuple[Withdrawal, ...]
86124

87125

src/ethereum/constantinople/blocks.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
chain.
1010
"""
1111
from dataclasses import dataclass
12-
from typing import Tuple, Union
12+
from typing import Annotated, Tuple, Union
1313

14+
from ethereum_rlp import rlp
1415
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
1516
from ethereum_types.frozen import slotted_freezable
1617
from ethereum_types.numeric import U256, Uint
1718
from typing_extensions import TypeAlias
1819

1920
from ethereum.byzantium import blocks as previous_blocks
21+
from ethereum.exceptions import InvalidBlock
2022

2123
from ..crypto.hash import Hash32
2224
from .fork_types import Address, Bloom, Root
@@ -54,6 +56,42 @@ class Header:
5456
"""
5557

5658

59+
def decode_header(raw_header: rlp.Simple) -> AnyHeader:
60+
"""
61+
Convert `raw_header` from raw sequences and bytes to a structured block
62+
header.
63+
64+
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
65+
to this fork, decodes it accordingly. If not, this function forwards to the
66+
preceding fork where the process is repeated.
67+
"""
68+
from . import FORK_CRITERIA
69+
70+
# First, ensure that `raw_header` is not `bytes` (and is therefore a
71+
# sequence.)
72+
if isinstance(raw_header, bytes):
73+
raise InvalidBlock("header is bytes, expected sequence")
74+
75+
# Next, extract the block number and timestamp (which are always at index 8
76+
# and 11 respectively.)
77+
raw_number = raw_header[8]
78+
if not isinstance(raw_number, bytes):
79+
raise InvalidBlock("header number is sequence, expected bytes")
80+
number = Uint.from_be_bytes(raw_number)
81+
82+
raw_timestamp = raw_header[11]
83+
if not isinstance(raw_timestamp, bytes):
84+
raise InvalidBlock("header timestamp is sequence, expected bytes")
85+
timestamp = U256.from_be_bytes(raw_timestamp)
86+
87+
# Finally, check if this header belongs to this fork.
88+
if FORK_CRITERIA.check(number, timestamp):
89+
return rlp.deserialize_to(Header, raw_header)
90+
91+
# If it doesn't, forward to the preceding fork.
92+
return previous_blocks.decode_header(raw_header)
93+
94+
5795
@slotted_freezable
5896
@dataclass
5997
class Block:
@@ -63,7 +101,7 @@ class Block:
63101

64102
header: Header
65103
transactions: Tuple[Transaction, ...]
66-
ommers: Tuple[AnyHeader, ...]
104+
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
67105

68106

69107
AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]

0 commit comments

Comments
 (0)