Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ommers #931

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/ethereum/arrow_glacier/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
from dataclasses import dataclass
from typing import Tuple, Union

from ..base_types import U256, Bytes, Bytes8, Bytes32, Uint, slotted_freezable
from ethereum.base_types import (
U256,
BaseHeader,
Bytes,
Bytes8,
Bytes32,
Uint,
slotted_freezable,
)

from ..crypto.hash import Hash32
from .fork_types import Address, Bloom, Root
from .transactions import LegacyTransaction
Expand Down Expand Up @@ -51,7 +60,7 @@ class Block:

header: Header
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[Header, ...]
ommers: Tuple[BaseHeader, ...]


@slotted_freezable
Expand Down
53 changes: 44 additions & 9 deletions src/ethereum/arrow_glacier/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,25 @@
from dataclasses import dataclass
from typing import List, Optional, Set, Tuple, Union

from ethereum.base_types import Bytes0
from ethereum.base_types import (
U64,
U256,
U256_CEIL_VALUE,
BaseHeader,
Bytes,
Bytes0,
FeeMarketHeader,
Uint,
)
from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover
from ethereum.crypto.hash import Hash32, keccak256
from ethereum.ethash import dataset_size, generate_cache, hashimoto_light
from ethereum.exceptions import InvalidBlock
from ethereum.london import fork as previous_fork
from ethereum.utils.ensure import ensure

from .. import rlp
from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Uint
from . import vm
from . import FORK_CRITERIA, vm
from .blocks import Block, Header, Log, Receipt
from .bloom import logs_bloom
from .fork_types import Address, Bloom, Root
Expand Down Expand Up @@ -262,7 +271,7 @@ def calculate_base_fee_per_gas(
return Uint(expected_base_fee_per_gas)


def validate_header(header: Header, parent_header: Header) -> None:
def validate_header(header: Header, parent_header: FeeMarketHeader) -> None:
"""
Verifies a block header.

Expand Down Expand Up @@ -486,7 +495,7 @@ def apply_body(
block_time: U256,
block_difficulty: Uint,
transactions: Tuple[Union[LegacyTransaction, Bytes], ...],
ommers: Tuple[Header, ...],
ommers: Tuple[BaseHeader, ...],
chain_id: U64,
) -> Tuple[Uint, Root, Root, Bloom, State]:
"""
Expand Down Expand Up @@ -604,8 +613,33 @@ def apply_body(
)


def validate_ommer_header(
header: BaseHeader,
parent_header: BaseHeader,
) -> None:
"""
Validates an ommer header. See `validate_ommers`.

Ommer headers are validated according to the rules of the fork they belong
to. If the block number or timestamp of the block does not match this fork,
this function forwards to the preceding fork.
"""
if FORK_CRITERIA.check(header.number, header.timestamp):
assert isinstance(header, Header)

if not isinstance(parent_header, FeeMarketHeader):
# While it is possible to construct a chain where this fork was
# preceded by a fork without EIP-1559, this is not the case on
# Ethereum's main network, and so we leave that case undefined.
raise NotImplementedError("ommer lacking EIP-1559")

validate_header(header, parent_header)
else:
previous_fork.validate_ommer_header(header, parent_header)


def validate_ommers(
ommers: Tuple[Header, ...], block_header: Header, chain: BlockChain
ommers: Tuple[BaseHeader, ...], block_header: Header, chain: BlockChain
) -> None:
"""
Validates the ommers mentioned in the block.
Expand Down Expand Up @@ -642,7 +676,7 @@ def validate_ommers(
ommer_parent_header = chain.blocks[
-(block_header.number - ommer.number) - 1
].header
validate_header(ommer, ommer_parent_header)
validate_ommer_header(ommer, ommer_parent_header)

# Check that there can be only at most 2 ommers for a block.
ensure(len(ommers) <= 2, InvalidBlock)
Expand Down Expand Up @@ -688,7 +722,7 @@ def pay_rewards(
state: State,
block_number: Uint,
coinbase: Address,
ommers: Tuple[Header, ...],
ommers: Tuple[BaseHeader, ...],
) -> None:
"""
Pay rewards to the block miner as well as the ommers miners.
Expand Down Expand Up @@ -722,7 +756,8 @@ def pay_rewards(
# Ommer age with respect to the current block.
ommer_age = U256(block_number - ommer.number)
ommer_miner_reward = ((8 - ommer_age) * BLOCK_REWARD) // 8
create_ether(state, ommer.coinbase, ommer_miner_reward)
coinbase = Address(ommer.coinbase)
create_ether(state, coinbase, ommer_miner_reward)


def process_transaction(
Expand Down
5 changes: 3 additions & 2 deletions src/ethereum/arrow_glacier/fork_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@

from dataclasses import dataclass

from .. import rlp
from ..base_types import (
from ethereum.base_types import (
U256,
Bytes,
Bytes20,
Bytes256,
Uint,
slotted_freezable,
)

from .. import rlp
from ..crypto.hash import Hash32, keccak256

Address = Bytes20
Expand Down
5 changes: 3 additions & 2 deletions src/ethereum/arrow_glacier/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from dataclasses import dataclass
from typing import Tuple, Union

from .. import rlp
from ..base_types import (
from ethereum.base_types import (
U64,
U256,
Bytes,
Expand All @@ -16,6 +15,8 @@
Uint,
slotted_freezable,
)

from .. import rlp
from ..exceptions import InvalidBlock
from .fork_types import Address

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum/arrow_glacier/trie.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
cast,
)

from ethereum.base_types import U256, Bytes, Uint, slotted_freezable
from ethereum.crypto.hash import keccak256
from ethereum.london import trie as previous_trie
from ethereum.utils.ensure import ensure
from ethereum.utils.hexadecimal import hex_to_bytes

from .. import rlp
from ..base_types import U256, Bytes, Uint, slotted_freezable
from .blocks import Receipt
from .fork_types import Account, Address, Root, encode_account
from .transactions import LegacyTransaction
Expand Down
3 changes: 1 addition & 2 deletions src/ethereum/arrow_glacier/vm/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@

EVM memory operations.
"""
from ethereum.base_types import U256, Bytes, Uint
from ethereum.utils.byte import right_pad_zero_bytes

from ...base_types import U256, Bytes, Uint


def memory_write(
memory: bytearray, start_position: U256, value: Bytes
Expand Down
100 changes: 100 additions & 0 deletions src/ethereum/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
[`Bytes64`]: ref:ethereum.base_types.Bytes64
"""

from abc import abstractmethod
from dataclasses import is_dataclass, replace
from typing import (
TYPE_CHECKING,
Any,
Callable,
ClassVar,
Expand All @@ -32,6 +34,9 @@
runtime_checkable,
)

if TYPE_CHECKING:
from .crypto.hash import Hash32


@runtime_checkable
class SlottedFreezable(Protocol):
Expand Down Expand Up @@ -927,6 +932,101 @@ class Bytes256(FixedBytes):
"""


@runtime_checkable
class BaseHeader(Protocol):
"""
A [`Protocol`] implemented by block headers like, for example, [`Header`].

[`Header`]: ref:ethereum.frontier.blocks.Header
[`Protocol`]: https://docs.python.org/library/typing.html#typing.Protocol
"""

@property
@abstractmethod
def parent_hash(self) -> "Hash32":
"""
Block hash of the block immediately preceding this block.
"""
raise NotImplementedError

@property
@abstractmethod
def ommers_hash(self) -> "Hash32":
"""
Hash of the ommers list for this block.
"""
raise NotImplementedError

@property
@abstractmethod
def coinbase(self) -> FixedBytes:
"""
Address that receives the reward for creating this block.
"""
raise NotImplementedError

@property
@abstractmethod
def difficulty(self) -> Uint:
"""
Level of computation required to create this block in pre-merge forks.
"""
raise NotImplementedError

@property
@abstractmethod
def number(self) -> Uint:
"""
Index of this block in the chain.
"""
raise NotImplementedError

@property
@abstractmethod
def gas_used(self) -> Uint:
"""
Total amount of gas used by transactions in this block.
"""
raise NotImplementedError

@property
@abstractmethod
def gas_limit(self) -> Uint:
"""
Maximum total amount of gas that can be consumed by transactions in
this block.
"""
raise NotImplementedError

@property
@abstractmethod
def timestamp(self) -> U256:
"""
Creation time of this block, expressed in the number of seconds that
had passed since 00:00:00 UTC on Thursday, 1 January 1970.
"""
raise NotImplementedError


@runtime_checkable
class FeeMarketHeader(BaseHeader, Protocol):
"""
A [`Protocol`] implemented by block headers after [EIP-1559].

[EIP-1559]: https://eips.ethereum.org/EIPS/eip-1559
[`Header`]: ref:ethereum.frontier.blocks.Header
[`Protocol`]: https://docs.python.org/library/typing.html#typing.Protocol
"""

@property
@abstractmethod
def base_fee_per_gas(self) -> Uint:
"""
Portion of transaction fees that is burned.
"""
raise NotImplementedError


def _setattr_function(self: Any, attr: str, value: Any) -> None:
if getattr(self, "_frozen", None):
raise Exception("Mutating frozen dataclasses is not allowed.")
Expand Down
13 changes: 11 additions & 2 deletions src/ethereum/berlin/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
from dataclasses import dataclass
from typing import Tuple, Union

from ..base_types import U256, Bytes, Bytes8, Bytes32, Uint, slotted_freezable
from ethereum.base_types import (
U256,
BaseHeader,
Bytes,
Bytes8,
Bytes32,
Uint,
slotted_freezable,
)

from ..crypto.hash import Hash32
from .fork_types import Address, Bloom, Root
from .transactions import LegacyTransaction
Expand Down Expand Up @@ -50,7 +59,7 @@ class Block:

header: Header
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[Header, ...]
ommers: Tuple[BaseHeader, ...]


@slotted_freezable
Expand Down
Loading
Loading