Skip to content

Commit

Permalink
More strict bounds on ommer types
Browse files Browse the repository at this point in the history
  • Loading branch information
SamWilsn committed Feb 12, 2025
1 parent 0c573cd commit 149dd1c
Show file tree
Hide file tree
Showing 25 changed files with 608 additions and 40 deletions.
42 changes: 40 additions & 2 deletions src/ethereum/arrow_glacier/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
chain.
"""
from dataclasses import dataclass
from typing import Optional, Tuple, Union
from typing import Annotated, Optional, Tuple, Union

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
from ethereum_types.frozen import slotted_freezable
from ethereum_types.numeric import U256, Uint
from typing_extensions import TypeAlias

from ethereum.exceptions import InvalidBlock
from ethereum.london import blocks as previous_blocks

from ..crypto.hash import Hash32
Expand Down Expand Up @@ -55,6 +57,42 @@ class Header:
"""


def decode_header(raw_header: rlp.Simple) -> AnyHeader:
"""
Convert `raw_header` from raw sequences and bytes to a structured block
header.
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
to this fork, decodes it accordingly. If not, this function forwards to the
preceding fork where the process is repeated.
"""
from . import FORK_CRITERIA

# First, ensure that `raw_header` is not `bytes` (and is therefore a
# sequence.)
if isinstance(raw_header, bytes):
raise InvalidBlock("header is bytes, expected sequence")

# Next, extract the block number and timestamp (which are always at index 8
# and 11 respectively.)
raw_number = raw_header[8]
if not isinstance(raw_number, bytes):
raise InvalidBlock("header number is sequence, expected bytes")
number = Uint.from_be_bytes(raw_number)

raw_timestamp = raw_header[11]
if not isinstance(raw_timestamp, bytes):
raise InvalidBlock("header timestamp is sequence, expected bytes")
timestamp = U256.from_be_bytes(raw_timestamp)

# Finally, check if this header belongs to this fork.
if FORK_CRITERIA.check(number, timestamp):
return rlp.deserialize_to(Header, raw_header)

# If it doesn't, forward to the preceding fork.
return previous_blocks.decode_header(raw_header)


@slotted_freezable
@dataclass
class Block:
Expand All @@ -64,7 +102,7 @@ class Block:

header: Header
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[AnyHeader, ...]
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]


AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
Expand Down
42 changes: 40 additions & 2 deletions src/ethereum/berlin/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
chain.
"""
from dataclasses import dataclass
from typing import Tuple, Union
from typing import Annotated, Tuple, Union

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
from ethereum_types.frozen import slotted_freezable
from ethereum_types.numeric import U256, Uint
from typing_extensions import TypeAlias

from ethereum.exceptions import InvalidBlock
from ethereum.muir_glacier import blocks as previous_blocks

from ..crypto.hash import Hash32
Expand Down Expand Up @@ -54,6 +56,42 @@ class Header:
"""


def decode_header(raw_header: rlp.Simple) -> AnyHeader:
"""
Convert `raw_header` from raw sequences and bytes to a structured block
header.
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
to this fork, decodes it accordingly. If not, this function forwards to the
preceding fork where the process is repeated.
"""
from . import FORK_CRITERIA

# First, ensure that `raw_header` is not `bytes` (and is therefore a
# sequence.)
if isinstance(raw_header, bytes):
raise InvalidBlock("header is bytes, expected sequence")

# Next, extract the block number and timestamp (which are always at index 8
# and 11 respectively.)
raw_number = raw_header[8]
if not isinstance(raw_number, bytes):
raise InvalidBlock("header number is sequence, expected bytes")
number = Uint.from_be_bytes(raw_number)

raw_timestamp = raw_header[11]
if not isinstance(raw_timestamp, bytes):
raise InvalidBlock("header timestamp is sequence, expected bytes")
timestamp = U256.from_be_bytes(raw_timestamp)

# Finally, check if this header belongs to this fork.
if FORK_CRITERIA.check(number, timestamp):
return rlp.deserialize_to(Header, raw_header)

# If it doesn't, forward to the preceding fork.
return previous_blocks.decode_header(raw_header)


@slotted_freezable
@dataclass
class Block:
Expand All @@ -63,7 +101,7 @@ class Block:

header: Header
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[AnyHeader, ...]
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]


AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
Expand Down
42 changes: 40 additions & 2 deletions src/ethereum/byzantium/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
chain.
"""
from dataclasses import dataclass
from typing import Tuple, Union
from typing import Annotated, Tuple, Union

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
from ethereum_types.frozen import slotted_freezable
from ethereum_types.numeric import U256, Uint
from typing_extensions import TypeAlias

from ethereum.exceptions import InvalidBlock
from ethereum.spurious_dragon import blocks as previous_blocks

from ..crypto.hash import Hash32
Expand Down Expand Up @@ -54,6 +56,42 @@ class Header:
"""


def decode_header(raw_header: rlp.Simple) -> AnyHeader:
"""
Convert `raw_header` from raw sequences and bytes to a structured block
header.
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
to this fork, decodes it accordingly. If not, this function forwards to the
preceding fork where the process is repeated.
"""
from . import FORK_CRITERIA

# First, ensure that `raw_header` is not `bytes` (and is therefore a
# sequence.)
if isinstance(raw_header, bytes):
raise InvalidBlock("header is bytes, expected sequence")

# Next, extract the block number and timestamp (which are always at index 8
# and 11 respectively.)
raw_number = raw_header[8]
if not isinstance(raw_number, bytes):
raise InvalidBlock("header number is sequence, expected bytes")
number = Uint.from_be_bytes(raw_number)

raw_timestamp = raw_header[11]
if not isinstance(raw_timestamp, bytes):
raise InvalidBlock("header timestamp is sequence, expected bytes")
timestamp = U256.from_be_bytes(raw_timestamp)

# Finally, check if this header belongs to this fork.
if FORK_CRITERIA.check(number, timestamp):
return rlp.deserialize_to(Header, raw_header)

# If it doesn't, forward to the preceding fork.
return previous_blocks.decode_header(raw_header)


@slotted_freezable
@dataclass
class Block:
Expand All @@ -63,7 +101,7 @@ class Block:

header: Header
transactions: Tuple[Transaction, ...]
ommers: Tuple[AnyHeader, ...]
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]


AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
Expand Down
42 changes: 40 additions & 2 deletions src/ethereum/cancun/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
chain.
"""
from dataclasses import dataclass
from typing import Optional, Tuple, Union
from typing import Annotated, Optional, Tuple, Union

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
from ethereum_types.frozen import slotted_freezable
from ethereum_types.numeric import U64, U256, Uint
from typing_extensions import TypeAlias

from ethereum.exceptions import InvalidBlock
from ethereum.shanghai import blocks as previous_blocks

from ..crypto.hash import Hash32
Expand Down Expand Up @@ -72,6 +74,42 @@ class Header:
"""


def decode_header(raw_header: rlp.Simple) -> AnyHeader:
"""
Convert `raw_header` from raw sequences and bytes to a structured block
header.
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
to this fork, decodes it accordingly. If not, this function forwards to the
preceding fork where the process is repeated.
"""
from . import FORK_CRITERIA

# First, ensure that `raw_header` is not `bytes` (and is therefore a
# sequence.)
if isinstance(raw_header, bytes):
raise InvalidBlock("header is bytes, expected sequence")

# Next, extract the block number and timestamp (which are always at index 8
# and 11 respectively.)
raw_number = raw_header[8]
if not isinstance(raw_number, bytes):
raise InvalidBlock("header number is sequence, expected bytes")
number = Uint.from_be_bytes(raw_number)

raw_timestamp = raw_header[11]
if not isinstance(raw_timestamp, bytes):
raise InvalidBlock("header timestamp is sequence, expected bytes")
timestamp = U256.from_be_bytes(raw_timestamp)

# Finally, check if this header belongs to this fork.
if FORK_CRITERIA.check(number, timestamp):
return rlp.deserialize_to(Header, raw_header)

# If it doesn't, forward to the preceding fork.
return previous_blocks.decode_header(raw_header)


@slotted_freezable
@dataclass
class Block:
Expand All @@ -81,7 +119,7 @@ class Block:

header: Header
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[AnyHeader, ...]
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]
withdrawals: Tuple[Withdrawal, ...]


Expand Down
42 changes: 40 additions & 2 deletions src/ethereum/constantinople/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
chain.
"""
from dataclasses import dataclass
from typing import Tuple, Union
from typing import Annotated, Tuple, Union

from ethereum_rlp import rlp
from ethereum_types.bytes import Bytes, Bytes8, Bytes32
from ethereum_types.frozen import slotted_freezable
from ethereum_types.numeric import U256, Uint
from typing_extensions import TypeAlias

from ethereum.byzantium import blocks as previous_blocks
from ethereum.exceptions import InvalidBlock

from ..crypto.hash import Hash32
from .fork_types import Address, Bloom, Root
Expand Down Expand Up @@ -54,6 +56,42 @@ class Header:
"""


def decode_header(raw_header: rlp.Simple) -> AnyHeader:
"""
Convert `raw_header` from raw sequences and bytes to a structured block
header.
Checks `raw_header` against this fork's `FORK_CRITERIA`, and if it belongs
to this fork, decodes it accordingly. If not, this function forwards to the
preceding fork where the process is repeated.
"""
from . import FORK_CRITERIA

# First, ensure that `raw_header` is not `bytes` (and is therefore a
# sequence.)
if isinstance(raw_header, bytes):
raise InvalidBlock("header is bytes, expected sequence")

# Next, extract the block number and timestamp (which are always at index 8
# and 11 respectively.)
raw_number = raw_header[8]
if not isinstance(raw_number, bytes):
raise InvalidBlock("header number is sequence, expected bytes")
number = Uint.from_be_bytes(raw_number)

raw_timestamp = raw_header[11]
if not isinstance(raw_timestamp, bytes):
raise InvalidBlock("header timestamp is sequence, expected bytes")
timestamp = U256.from_be_bytes(raw_timestamp)

# Finally, check if this header belongs to this fork.
if FORK_CRITERIA.check(number, timestamp):
return rlp.deserialize_to(Header, raw_header)

# If it doesn't, forward to the preceding fork.
return previous_blocks.decode_header(raw_header)


@slotted_freezable
@dataclass
class Block:
Expand All @@ -63,7 +101,7 @@ class Block:

header: Header
transactions: Tuple[Transaction, ...]
ommers: Tuple[AnyHeader, ...]
ommers: Tuple[Annotated[AnyHeader, rlp.With(decode_header)], ...]


AnyBlock: TypeAlias = Union[previous_blocks.AnyBlock, Block]
Expand Down
Loading

0 comments on commit 149dd1c

Please sign in to comment.