diff --git a/src/ethereum/arrow_glacier/blocks.py b/src/ethereum/arrow_glacier/blocks.py index 2fa1095e05..87acc34369 100644 --- a/src/ethereum/arrow_glacier/blocks.py +++ b/src/ethereum/arrow_glacier/blocks.py @@ -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 @@ -51,7 +60,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/arrow_glacier/fork.py b/src/ethereum/arrow_glacier/fork.py index e518801266..2e922ff786 100644 --- a/src/ethereum/arrow_glacier/fork.py +++ b/src/ethereum/arrow_glacier/fork.py @@ -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 @@ -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. @@ -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]: """ @@ -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. @@ -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) @@ -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. @@ -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( diff --git a/src/ethereum/arrow_glacier/fork_types.py b/src/ethereum/arrow_glacier/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/arrow_glacier/fork_types.py +++ b/src/ethereum/arrow_glacier/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/arrow_glacier/transactions.py b/src/ethereum/arrow_glacier/transactions.py index d11bc88219..22eabed88c 100644 --- a/src/ethereum/arrow_glacier/transactions.py +++ b/src/ethereum/arrow_glacier/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address diff --git a/src/ethereum/arrow_glacier/trie.py b/src/ethereum/arrow_glacier/trie.py index 7adef9e487..596b363b73 100644 --- a/src/ethereum/arrow_glacier/trie.py +++ b/src/ethereum/arrow_glacier/trie.py @@ -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 diff --git a/src/ethereum/arrow_glacier/vm/memory.py b/src/ethereum/arrow_glacier/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/arrow_glacier/vm/memory.py +++ b/src/ethereum/arrow_glacier/vm/memory.py @@ -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 diff --git a/src/ethereum/base_types.py b/src/ethereum/base_types.py index 3e44fe8478..d2f2a17788 100644 --- a/src/ethereum/base_types.py +++ b/src/ethereum/base_types.py @@ -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, @@ -32,6 +34,9 @@ runtime_checkable, ) +if TYPE_CHECKING: + from .crypto.hash import Hash32 + @runtime_checkable class SlottedFreezable(Protocol): @@ -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.") diff --git a/src/ethereum/berlin/blocks.py b/src/ethereum/berlin/blocks.py index 5adef0441a..28e6e75e3d 100644 --- a/src/ethereum/berlin/blocks.py +++ b/src/ethereum/berlin/blocks.py @@ -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 @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/berlin/fork.py b/src/ethereum/berlin/fork.py index bf03c3b698..d3956586d7 100644 --- a/src/ethereum/berlin/fork.py +++ b/src/ethereum/berlin/fork.py @@ -15,16 +15,24 @@ 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, + 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.muir_glacier 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 @@ -193,7 +201,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -388,7 +396,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]: """ @@ -501,8 +509,26 @@ 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) + 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. @@ -539,7 +565,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) @@ -585,7 +611,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. @@ -619,7 +645,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( diff --git a/src/ethereum/berlin/fork_types.py b/src/ethereum/berlin/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/berlin/fork_types.py +++ b/src/ethereum/berlin/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/berlin/transactions.py b/src/ethereum/berlin/transactions.py index f6878a34b1..70a8ec5caf 100644 --- a/src/ethereum/berlin/transactions.py +++ b/src/ethereum/berlin/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from ..utils.ensure import ensure from .fork_types import Address diff --git a/src/ethereum/berlin/trie.py b/src/ethereum/berlin/trie.py index dab86bbd1a..8776779dc3 100644 --- a/src/ethereum/berlin/trie.py +++ b/src/ethereum/berlin/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.muir_glacier 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 diff --git a/src/ethereum/berlin/vm/memory.py b/src/ethereum/berlin/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/berlin/vm/memory.py +++ b/src/ethereum/berlin/vm/memory.py @@ -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 diff --git a/src/ethereum/byzantium/blocks.py b/src/ethereum/byzantium/blocks.py index 6b951c480c..2e9fdb6ab9 100644 --- a/src/ethereum/byzantium/blocks.py +++ b/src/ethereum/byzantium/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/byzantium/fork.py b/src/ethereum/byzantium/fork.py index c29dd67d41..256e060bab 100644 --- a/src/ethereum/byzantium/fork.py +++ b/src/ethereum/byzantium/fork.py @@ -15,16 +15,24 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + 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.spurious_dragon 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 @@ -187,7 +195,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -379,7 +387,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], chain_id: U64, ) -> Tuple[Uint, Root, Root, Bloom, State]: """ @@ -489,8 +497,26 @@ 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) + 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. @@ -527,7 +553,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) @@ -573,7 +599,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. @@ -607,7 +633,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( diff --git a/src/ethereum/byzantium/fork_types.py b/src/ethereum/byzantium/fork_types.py index b8a26bd545..6f9ee6ebb7 100644 --- a/src/ethereum/byzantium/fork_types.py +++ b/src/ethereum/byzantium/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/byzantium/transactions.py b/src/ethereum/byzantium/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/byzantium/transactions.py +++ b/src/ethereum/byzantium/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/byzantium/trie.py b/src/ethereum/byzantium/trie.py index 7fa998ea1d..5f659935cd 100644 --- a/src/ethereum/byzantium/trie.py +++ b/src/ethereum/byzantium/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.spurious_dragon 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 Transaction diff --git a/src/ethereum/byzantium/vm/memory.py b/src/ethereum/byzantium/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/byzantium/vm/memory.py +++ b/src/ethereum/byzantium/vm/memory.py @@ -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 diff --git a/src/ethereum/cancun/blocks.py b/src/ethereum/cancun/blocks.py index e08214ee34..4ac7b3b1e4 100644 --- a/src/ethereum/cancun/blocks.py +++ b/src/ethereum/cancun/blocks.py @@ -11,15 +11,17 @@ from dataclasses import dataclass from typing import Tuple, Union -from ..base_types import ( +from ethereum.base_types import ( U64, U256, + BaseHeader, Bytes, Bytes8, Bytes32, Uint, slotted_freezable, ) + from ..crypto.hash import Hash32 from .fork_types import Address, Bloom, Root from .transactions import LegacyTransaction @@ -76,7 +78,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] withdrawals: Tuple[Withdrawal, ...] diff --git a/src/ethereum/cancun/fork.py b/src/ethereum/cancun/fork.py index 9e87099457..cce8b579ec 100644 --- a/src/ethereum/cancun/fork.py +++ b/src/ethereum/cancun/fork.py @@ -15,14 +15,21 @@ from dataclasses import dataclass from typing import List, Optional, Tuple, Union -from ethereum.base_types import Bytes0, Bytes32 +from ethereum.base_types import ( + U64, + U256, + Bytes, + Bytes0, + Bytes32, + FeeMarketHeader, + Uint, +) from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 from ethereum.exceptions import InvalidBlock from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, Bytes, Uint from . import vm from .blocks import Block, Header, Log, Receipt, Withdrawal from .bloom import logs_bloom @@ -285,7 +292,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. diff --git a/src/ethereum/cancun/fork_types.py b/src/ethereum/cancun/fork_types.py index 8d97937789..50784349a9 100644 --- a/src/ethereum/cancun/fork_types.py +++ b/src/ethereum/cancun/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/cancun/transactions.py b/src/ethereum/cancun/transactions.py index d81d11ed13..42e16222f8 100644 --- a/src/ethereum/cancun/transactions.py +++ b/src/ethereum/cancun/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address, VersionedHash diff --git a/src/ethereum/cancun/trie.py b/src/ethereum/cancun/trie.py index f7a7c29e17..d466c8bf8c 100644 --- a/src/ethereum/cancun/trie.py +++ b/src/ethereum/cancun/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.shanghai 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, Withdrawal from .fork_types import Account, Address, Root, encode_account from .transactions import LegacyTransaction diff --git a/src/ethereum/cancun/vm/memory.py b/src/ethereum/cancun/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/cancun/vm/memory.py +++ b/src/ethereum/cancun/vm/memory.py @@ -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 diff --git a/src/ethereum/constantinople/blocks.py b/src/ethereum/constantinople/blocks.py index 6b951c480c..2e9fdb6ab9 100644 --- a/src/ethereum/constantinople/blocks.py +++ b/src/ethereum/constantinople/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/constantinople/fork.py b/src/ethereum/constantinople/fork.py index 779d87d0b5..7ba7614d06 100644 --- a/src/ethereum/constantinople/fork.py +++ b/src/ethereum/constantinople/fork.py @@ -15,7 +15,16 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Uint, +) +from ethereum.byzantium import fork as previous_fork 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 @@ -23,8 +32,7 @@ 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 @@ -187,7 +195,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -379,7 +387,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], chain_id: U64, ) -> Tuple[Uint, Root, Root, Bloom, State]: """ @@ -489,8 +497,26 @@ 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) + 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. @@ -527,7 +553,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) @@ -573,7 +599,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. @@ -607,7 +633,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( diff --git a/src/ethereum/constantinople/fork_types.py b/src/ethereum/constantinople/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/constantinople/fork_types.py +++ b/src/ethereum/constantinople/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/constantinople/transactions.py b/src/ethereum/constantinople/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/constantinople/transactions.py +++ b/src/ethereum/constantinople/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/constantinople/trie.py b/src/ethereum/constantinople/trie.py index 99c1fa4a74..6db0008f36 100644 --- a/src/ethereum/constantinople/trie.py +++ b/src/ethereum/constantinople/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.byzantium import trie as previous_trie from ethereum.crypto.hash import keccak256 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 Transaction diff --git a/src/ethereum/constantinople/vm/memory.py b/src/ethereum/constantinople/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/constantinople/vm/memory.py +++ b/src/ethereum/constantinople/vm/memory.py @@ -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 diff --git a/src/ethereum/crypto/elliptic_curve.py b/src/ethereum/crypto/elliptic_curve.py index 1b6c23b90f..2895684e3b 100644 --- a/src/ethereum/crypto/elliptic_curve.py +++ b/src/ethereum/crypto/elliptic_curve.py @@ -7,7 +7,8 @@ import coincurve -from ..base_types import U256, Bytes +from ethereum.base_types import U256, Bytes + from .finite_field import Field from .hash import Hash32 diff --git a/src/ethereum/crypto/finite_field.py b/src/ethereum/crypto/finite_field.py index c45f7fd49a..43fc831987 100644 --- a/src/ethereum/crypto/finite_field.py +++ b/src/ethereum/crypto/finite_field.py @@ -9,7 +9,7 @@ from typing_extensions import Protocol -from ..base_types import Bytes, Bytes32 +from ethereum.base_types import Bytes, Bytes32 F = TypeVar("F", bound="Field") diff --git a/src/ethereum/dao_fork/blocks.py b/src/ethereum/dao_fork/blocks.py index e1c7f5d55d..15734eec84 100644 --- a/src/ethereum/dao_fork/blocks.py +++ b/src/ethereum/dao_fork/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/dao_fork/fork.py b/src/ethereum/dao_fork/fork.py index fe82c129e7..dfd06d43cf 100644 --- a/src/ethereum/dao_fork/fork.py +++ b/src/ethereum/dao_fork/fork.py @@ -17,15 +17,24 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Bytes32, + 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.homestead import fork as previous_fork from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Bytes32, Uint from . import FORK_CRITERIA, vm from .blocks import Block, Header, Log, Receipt from .bloom import logs_bloom @@ -194,7 +203,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -387,7 +396,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], ) -> Tuple[Uint, Root, Root, Bloom, State]: """ Executes a block. @@ -494,8 +503,26 @@ 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) + 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. @@ -532,7 +559,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) @@ -578,7 +605,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. @@ -612,7 +639,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( diff --git a/src/ethereum/dao_fork/fork_types.py b/src/ethereum/dao_fork/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/dao_fork/fork_types.py +++ b/src/ethereum/dao_fork/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/dao_fork/transactions.py b/src/ethereum/dao_fork/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/dao_fork/transactions.py +++ b/src/ethereum/dao_fork/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/dao_fork/trie.py b/src/ethereum/dao_fork/trie.py index dab4cbdd68..8ef915fb95 100644 --- a/src/ethereum/dao_fork/trie.py +++ b/src/ethereum/dao_fork/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.homestead 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 Transaction diff --git a/src/ethereum/dao_fork/vm/memory.py b/src/ethereum/dao_fork/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/dao_fork/vm/memory.py +++ b/src/ethereum/dao_fork/vm/memory.py @@ -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 diff --git a/src/ethereum/frontier/blocks.py b/src/ethereum/frontier/blocks.py index e1c7f5d55d..15734eec84 100644 --- a/src/ethereum/frontier/blocks.py +++ b/src/ethereum/frontier/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/frontier/fork.py b/src/ethereum/frontier/fork.py index 1ce71565ec..56a51b90ca 100644 --- a/src/ethereum/frontier/fork.py +++ b/src/ethereum/frontier/fork.py @@ -15,6 +15,15 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes32, + 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 @@ -22,7 +31,6 @@ from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Bytes32, Uint from . import vm from .blocks import Block, Header, Log, Receipt from .bloom import logs_bloom @@ -368,7 +376,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], ) -> Tuple[Uint, Root, Root, Bloom, State]: """ Executes a block. @@ -475,8 +483,25 @@ 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. + """ + assert isinstance(header, Header) + assert isinstance(parent_header, Header) + + validate_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. @@ -513,7 +538,8 @@ 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) @@ -559,7 +585,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. @@ -593,7 +619,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( diff --git a/src/ethereum/frontier/fork_types.py b/src/ethereum/frontier/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/frontier/fork_types.py +++ b/src/ethereum/frontier/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/frontier/transactions.py b/src/ethereum/frontier/transactions.py index a08b4cf71d..c52fcb3476 100644 --- a/src/ethereum/frontier/transactions.py +++ b/src/ethereum/frontier/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/frontier/trie.py b/src/ethereum/frontier/trie.py index 12e411aebf..8063f292af 100644 --- a/src/ethereum/frontier/trie.py +++ b/src/ethereum/frontier/trie.py @@ -29,12 +29,12 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 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 Transaction diff --git a/src/ethereum/frontier/vm/memory.py b/src/ethereum/frontier/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/frontier/vm/memory.py +++ b/src/ethereum/frontier/vm/memory.py @@ -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 diff --git a/src/ethereum/gray_glacier/blocks.py b/src/ethereum/gray_glacier/blocks.py index 2fa1095e05..87acc34369 100644 --- a/src/ethereum/gray_glacier/blocks.py +++ b/src/ethereum/gray_glacier/blocks.py @@ -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 @@ -51,7 +60,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/gray_glacier/fork.py b/src/ethereum/gray_glacier/fork.py index 808e0a88f7..206aa5322b 100644 --- a/src/ethereum/gray_glacier/fork.py +++ b/src/ethereum/gray_glacier/fork.py @@ -15,7 +15,17 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple, Union -from ethereum.base_types import Bytes0 +from ethereum.arrow_glacier import fork as previous_fork +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 @@ -23,8 +33,7 @@ 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 @@ -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. @@ -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]: """ @@ -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. @@ -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) @@ -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. @@ -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( diff --git a/src/ethereum/gray_glacier/fork_types.py b/src/ethereum/gray_glacier/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/gray_glacier/fork_types.py +++ b/src/ethereum/gray_glacier/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/gray_glacier/transactions.py b/src/ethereum/gray_glacier/transactions.py index d11bc88219..22eabed88c 100644 --- a/src/ethereum/gray_glacier/transactions.py +++ b/src/ethereum/gray_glacier/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address diff --git a/src/ethereum/gray_glacier/trie.py b/src/ethereum/gray_glacier/trie.py index ad9e209df1..e725b6d5ad 100644 --- a/src/ethereum/gray_glacier/trie.py +++ b/src/ethereum/gray_glacier/trie.py @@ -30,12 +30,12 @@ ) from ethereum.arrow_glacier import trie as previous_trie +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 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 diff --git a/src/ethereum/gray_glacier/vm/memory.py b/src/ethereum/gray_glacier/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/gray_glacier/vm/memory.py +++ b/src/ethereum/gray_glacier/vm/memory.py @@ -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 diff --git a/src/ethereum/homestead/blocks.py b/src/ethereum/homestead/blocks.py index e1c7f5d55d..15734eec84 100644 --- a/src/ethereum/homestead/blocks.py +++ b/src/ethereum/homestead/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/homestead/fork.py b/src/ethereum/homestead/fork.py index e0dcab2475..df39ace56b 100644 --- a/src/ethereum/homestead/fork.py +++ b/src/ethereum/homestead/fork.py @@ -15,16 +15,25 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Bytes32, + 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.frontier import fork as previous_fork from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Bytes32, 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 @@ -183,7 +192,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -370,7 +379,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], ) -> Tuple[Uint, Root, Root, Bloom, State]: """ Executes a block. @@ -477,8 +486,26 @@ 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) + 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. @@ -515,7 +542,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) @@ -561,7 +588,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. @@ -595,7 +622,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( diff --git a/src/ethereum/homestead/fork_types.py b/src/ethereum/homestead/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/homestead/fork_types.py +++ b/src/ethereum/homestead/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/homestead/transactions.py b/src/ethereum/homestead/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/homestead/transactions.py +++ b/src/ethereum/homestead/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/homestead/trie.py b/src/ethereum/homestead/trie.py index d45d3ad336..247425ed1f 100644 --- a/src/ethereum/homestead/trie.py +++ b/src/ethereum/homestead/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.frontier 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 Transaction diff --git a/src/ethereum/homestead/vm/memory.py b/src/ethereum/homestead/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/homestead/vm/memory.py +++ b/src/ethereum/homestead/vm/memory.py @@ -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 diff --git a/src/ethereum/istanbul/blocks.py b/src/ethereum/istanbul/blocks.py index 6b951c480c..2e9fdb6ab9 100644 --- a/src/ethereum/istanbul/blocks.py +++ b/src/ethereum/istanbul/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/istanbul/fork.py b/src/ethereum/istanbul/fork.py index 1647327b42..15676c6046 100644 --- a/src/ethereum/istanbul/fork.py +++ b/src/ethereum/istanbul/fork.py @@ -15,7 +15,16 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Uint, +) +from ethereum.constantinople import fork as previous_fork 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 @@ -23,8 +32,7 @@ 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 @@ -187,7 +195,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -379,7 +387,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], chain_id: U64, ) -> Tuple[Uint, Root, Root, Bloom, State]: """ @@ -490,8 +498,26 @@ 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) + 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. @@ -528,7 +554,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) @@ -574,7 +600,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. @@ -608,7 +634,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( diff --git a/src/ethereum/istanbul/fork_types.py b/src/ethereum/istanbul/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/istanbul/fork_types.py +++ b/src/ethereum/istanbul/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/istanbul/transactions.py b/src/ethereum/istanbul/transactions.py index af0c75abf8..1bd2c6bfe2 100644 --- a/src/ethereum/istanbul/transactions.py +++ b/src/ethereum/istanbul/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/istanbul/trie.py b/src/ethereum/istanbul/trie.py index 8bd1f0dc61..967be64824 100644 --- a/src/ethereum/istanbul/trie.py +++ b/src/ethereum/istanbul/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.constantinople import trie as previous_trie from ethereum.crypto.hash import keccak256 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 Transaction diff --git a/src/ethereum/istanbul/vm/memory.py b/src/ethereum/istanbul/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/istanbul/vm/memory.py +++ b/src/ethereum/istanbul/vm/memory.py @@ -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 diff --git a/src/ethereum/london/blocks.py b/src/ethereum/london/blocks.py index 2fa1095e05..87acc34369 100644 --- a/src/ethereum/london/blocks.py +++ b/src/ethereum/london/blocks.py @@ -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 @@ -51,7 +60,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/london/fork.py b/src/ethereum/london/fork.py index a84149a5d1..f0299fa596 100644 --- a/src/ethereum/london/fork.py +++ b/src/ethereum/london/fork.py @@ -15,7 +15,17 @@ 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.berlin import fork as previous_fork 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 @@ -23,7 +33,6 @@ from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Uint from . import FORK_CRITERIA, vm from .blocks import Block, Header, Log, Receipt from .bloom import logs_bloom @@ -203,7 +212,6 @@ def calculate_base_fee_per_gas( parent_gas_limit: Uint, parent_gas_used: Uint, parent_base_fee_per_gas: Uint, - is_fork_block: bool, ) -> Uint: """ Calculates the base fee per gas for the block. @@ -218,16 +226,12 @@ def calculate_base_fee_per_gas( Gas used in the parent block. parent_base_fee_per_gas : Base fee per gas of the parent block. - is_fork_block : - Whether the block is the fork block. Returns ------- base_fee_per_gas : `Uint` Base fee per gas for the block. """ - if is_fork_block: - return Uint(INITIAL_BASE_FEE) parent_gas_target = parent_gas_limit // ELASTICITY_MULTIPLIER ensure( @@ -268,7 +272,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: BaseHeader) -> None: """ Verifies a block header. @@ -288,14 +292,16 @@ def validate_header(header: Header, parent_header: Header) -> None: """ ensure(header.gas_used <= header.gas_limit, InvalidBlock) - is_fork_block = header.number == FORK_CRITERIA.block_number - expected_base_fee_per_gas = calculate_base_fee_per_gas( - header.gas_limit, - parent_header.gas_limit, - parent_header.gas_used, - parent_header.base_fee_per_gas, - is_fork_block, - ) + expected_base_fee_per_gas = Uint(INITIAL_BASE_FEE) + + if header.number != FORK_CRITERIA.block_number: + assert isinstance(parent_header, FeeMarketHeader) + expected_base_fee_per_gas = calculate_base_fee_per_gas( + header.gas_limit, + parent_header.gas_limit, + parent_header.gas_used, + parent_header.base_fee_per_gas, + ) ensure(expected_base_fee_per_gas == header.base_fee_per_gas, InvalidBlock) @@ -494,7 +500,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]: """ @@ -612,8 +618,26 @@ 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) + 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. @@ -650,7 +674,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) @@ -696,7 +720,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. @@ -730,7 +754,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( diff --git a/src/ethereum/london/fork_types.py b/src/ethereum/london/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/london/fork_types.py +++ b/src/ethereum/london/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/london/transactions.py b/src/ethereum/london/transactions.py index d11bc88219..22eabed88c 100644 --- a/src/ethereum/london/transactions.py +++ b/src/ethereum/london/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address diff --git a/src/ethereum/london/trie.py b/src/ethereum/london/trie.py index 7ff103ef1f..43e67da3ad 100644 --- a/src/ethereum/london/trie.py +++ b/src/ethereum/london/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.berlin import trie as previous_trie from ethereum.crypto.hash import keccak256 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 diff --git a/src/ethereum/london/vm/memory.py b/src/ethereum/london/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/london/vm/memory.py +++ b/src/ethereum/london/vm/memory.py @@ -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 diff --git a/src/ethereum/muir_glacier/blocks.py b/src/ethereum/muir_glacier/blocks.py index 6b951c480c..2e9fdb6ab9 100644 --- a/src/ethereum/muir_glacier/blocks.py +++ b/src/ethereum/muir_glacier/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/muir_glacier/fork.py b/src/ethereum/muir_glacier/fork.py index 1ac64730a2..2a94751f05 100644 --- a/src/ethereum/muir_glacier/fork.py +++ b/src/ethereum/muir_glacier/fork.py @@ -15,16 +15,24 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + 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.istanbul 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 @@ -187,7 +195,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -379,7 +387,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], chain_id: U64, ) -> Tuple[Uint, Root, Root, Bloom, State]: """ @@ -490,8 +498,26 @@ 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) + 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. @@ -528,7 +554,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) @@ -574,7 +600,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. @@ -608,7 +634,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( diff --git a/src/ethereum/muir_glacier/fork_types.py b/src/ethereum/muir_glacier/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/muir_glacier/fork_types.py +++ b/src/ethereum/muir_glacier/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/muir_glacier/transactions.py b/src/ethereum/muir_glacier/transactions.py index af0c75abf8..1bd2c6bfe2 100644 --- a/src/ethereum/muir_glacier/transactions.py +++ b/src/ethereum/muir_glacier/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/muir_glacier/trie.py b/src/ethereum/muir_glacier/trie.py index e5e74bb39f..5828d913ce 100644 --- a/src/ethereum/muir_glacier/trie.py +++ b/src/ethereum/muir_glacier/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.istanbul 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 Transaction diff --git a/src/ethereum/muir_glacier/vm/memory.py b/src/ethereum/muir_glacier/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/muir_glacier/vm/memory.py +++ b/src/ethereum/muir_glacier/vm/memory.py @@ -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 diff --git a/src/ethereum/paris/blocks.py b/src/ethereum/paris/blocks.py index 68dc44f1bb..b319f611ad 100644 --- a/src/ethereum/paris/blocks.py +++ b/src/ethereum/paris/blocks.py @@ -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 @@ -51,7 +60,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/paris/fork.py b/src/ethereum/paris/fork.py index 424f1d00df..1b067a9b48 100644 --- a/src/ethereum/paris/fork.py +++ b/src/ethereum/paris/fork.py @@ -15,14 +15,21 @@ from dataclasses import dataclass from typing import List, Optional, Tuple, Union -from ethereum.base_types import Bytes0, Bytes32 +from ethereum.base_types import ( + U64, + U256, + Bytes, + Bytes0, + Bytes32, + FeeMarketHeader, + Uint, +) from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 from ethereum.exceptions import InvalidBlock from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, Bytes, Uint from . import vm from .blocks import Block, Header, Log, Receipt from .bloom import logs_bloom @@ -255,7 +262,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. diff --git a/src/ethereum/paris/fork_types.py b/src/ethereum/paris/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/paris/fork_types.py +++ b/src/ethereum/paris/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/paris/transactions.py b/src/ethereum/paris/transactions.py index d11bc88219..22eabed88c 100644 --- a/src/ethereum/paris/transactions.py +++ b/src/ethereum/paris/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address diff --git a/src/ethereum/paris/trie.py b/src/ethereum/paris/trie.py index 9603968594..8192d839d1 100644 --- a/src/ethereum/paris/trie.py +++ b/src/ethereum/paris/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.gray_glacier 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 diff --git a/src/ethereum/paris/vm/memory.py b/src/ethereum/paris/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/paris/vm/memory.py +++ b/src/ethereum/paris/vm/memory.py @@ -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 diff --git a/src/ethereum/shanghai/blocks.py b/src/ethereum/shanghai/blocks.py index d1a13629d5..d127cb9609 100644 --- a/src/ethereum/shanghai/blocks.py +++ b/src/ethereum/shanghai/blocks.py @@ -11,15 +11,17 @@ from dataclasses import dataclass from typing import Tuple, Union -from ..base_types import ( +from ethereum.base_types import ( U64, U256, + BaseHeader, Bytes, Bytes8, Bytes32, Uint, slotted_freezable, ) + from ..crypto.hash import Hash32 from .fork_types import Address, Bloom, Root from .transactions import LegacyTransaction @@ -73,7 +75,7 @@ class Block: header: Header transactions: Tuple[Union[Bytes, LegacyTransaction], ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] withdrawals: Tuple[Withdrawal, ...] diff --git a/src/ethereum/shanghai/fork.py b/src/ethereum/shanghai/fork.py index f6e8b42c2e..07f011bbfe 100644 --- a/src/ethereum/shanghai/fork.py +++ b/src/ethereum/shanghai/fork.py @@ -15,14 +15,21 @@ from dataclasses import dataclass from typing import List, Optional, Tuple, Union -from ethereum.base_types import Bytes0, Bytes32 +from ethereum.base_types import ( + U64, + U256, + Bytes, + Bytes0, + Bytes32, + FeeMarketHeader, + Uint, +) from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 from ethereum.exceptions import InvalidBlock from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, Bytes, Uint from . import vm from .blocks import Block, Header, Log, Receipt, Withdrawal from .bloom import logs_bloom @@ -260,7 +267,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. diff --git a/src/ethereum/shanghai/fork_types.py b/src/ethereum/shanghai/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/shanghai/fork_types.py +++ b/src/ethereum/shanghai/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/shanghai/transactions.py b/src/ethereum/shanghai/transactions.py index d11bc88219..22eabed88c 100644 --- a/src/ethereum/shanghai/transactions.py +++ b/src/ethereum/shanghai/transactions.py @@ -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, @@ -16,6 +15,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..exceptions import InvalidBlock from .fork_types import Address diff --git a/src/ethereum/shanghai/trie.py b/src/ethereum/shanghai/trie.py index e29b575c93..b5b9cab6bf 100644 --- a/src/ethereum/shanghai/trie.py +++ b/src/ethereum/shanghai/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.paris 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, Withdrawal from .fork_types import Account, Address, Root, encode_account from .transactions import LegacyTransaction diff --git a/src/ethereum/shanghai/vm/memory.py b/src/ethereum/shanghai/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/shanghai/vm/memory.py +++ b/src/ethereum/shanghai/vm/memory.py @@ -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 diff --git a/src/ethereum/spurious_dragon/blocks.py b/src/ethereum/spurious_dragon/blocks.py index e1c7f5d55d..15734eec84 100644 --- a/src/ethereum/spurious_dragon/blocks.py +++ b/src/ethereum/spurious_dragon/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/spurious_dragon/fork.py b/src/ethereum/spurious_dragon/fork.py index 3862c26fef..ace9c7d777 100644 --- a/src/ethereum/spurious_dragon/fork.py +++ b/src/ethereum/spurious_dragon/fork.py @@ -15,16 +15,25 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Bytes32, + 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.tangerine_whistle import fork as previous_fork from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Bytes32, 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 @@ -185,7 +194,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -375,7 +384,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], chain_id: U64, ) -> Tuple[Uint, Root, Root, Bloom, State]: """ @@ -485,8 +494,26 @@ 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) + 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. @@ -523,7 +550,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) @@ -569,7 +596,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. @@ -603,7 +630,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( diff --git a/src/ethereum/spurious_dragon/fork_types.py b/src/ethereum/spurious_dragon/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/spurious_dragon/fork_types.py +++ b/src/ethereum/spurious_dragon/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/spurious_dragon/transactions.py b/src/ethereum/spurious_dragon/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/spurious_dragon/transactions.py +++ b/src/ethereum/spurious_dragon/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/spurious_dragon/trie.py b/src/ethereum/spurious_dragon/trie.py index 41f4f61ab6..433ed8cb18 100644 --- a/src/ethereum/spurious_dragon/trie.py +++ b/src/ethereum/spurious_dragon/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.tangerine_whistle 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 Transaction diff --git a/src/ethereum/spurious_dragon/vm/memory.py b/src/ethereum/spurious_dragon/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/spurious_dragon/vm/memory.py +++ b/src/ethereum/spurious_dragon/vm/memory.py @@ -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 diff --git a/src/ethereum/tangerine_whistle/blocks.py b/src/ethereum/tangerine_whistle/blocks.py index e1c7f5d55d..15734eec84 100644 --- a/src/ethereum/tangerine_whistle/blocks.py +++ b/src/ethereum/tangerine_whistle/blocks.py @@ -11,7 +11,16 @@ from dataclasses import dataclass from typing import Tuple -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 Transaction @@ -50,7 +59,7 @@ class Block: header: Header transactions: Tuple[Transaction, ...] - ommers: Tuple[Header, ...] + ommers: Tuple[BaseHeader, ...] @slotted_freezable diff --git a/src/ethereum/tangerine_whistle/fork.py b/src/ethereum/tangerine_whistle/fork.py index e0dcab2475..23b0e6c552 100644 --- a/src/ethereum/tangerine_whistle/fork.py +++ b/src/ethereum/tangerine_whistle/fork.py @@ -15,16 +15,25 @@ from dataclasses import dataclass from typing import List, Optional, Set, Tuple -from ethereum.base_types import Bytes0 +from ethereum.base_types import ( + U64, + U256, + U256_CEIL_VALUE, + BaseHeader, + Bytes, + Bytes0, + Bytes32, + Uint, +) from ethereum.crypto.elliptic_curve import SECP256K1N, secp256k1_recover from ethereum.crypto.hash import Hash32, keccak256 +from ethereum.dao_fork import fork as previous_fork from ethereum.ethash import dataset_size, generate_cache, hashimoto_light from ethereum.exceptions import InvalidBlock from ethereum.utils.ensure import ensure from .. import rlp -from ..base_types import U64, U256, U256_CEIL_VALUE, Bytes, Bytes32, 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 @@ -183,7 +192,7 @@ def state_transition(chain: BlockChain, block: Block) -> None: chain.blocks = chain.blocks[-255:] -def validate_header(header: Header, parent_header: Header) -> None: +def validate_header(header: Header, parent_header: BaseHeader) -> None: """ Verifies a block header. @@ -370,7 +379,7 @@ def apply_body( block_time: U256, block_difficulty: Uint, transactions: Tuple[Transaction, ...], - ommers: Tuple[Header, ...], + ommers: Tuple[BaseHeader, ...], ) -> Tuple[Uint, Root, Root, Bloom, State]: """ Executes a block. @@ -477,8 +486,26 @@ 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) + 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. @@ -515,7 +542,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) @@ -561,7 +588,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. @@ -595,7 +622,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( diff --git a/src/ethereum/tangerine_whistle/fork_types.py b/src/ethereum/tangerine_whistle/fork_types.py index 75812be178..cbbfafaa36 100644 --- a/src/ethereum/tangerine_whistle/fork_types.py +++ b/src/ethereum/tangerine_whistle/fork_types.py @@ -14,8 +14,7 @@ from dataclasses import dataclass -from .. import rlp -from ..base_types import ( +from ethereum.base_types import ( U256, Bytes, Bytes20, @@ -23,6 +22,8 @@ Uint, slotted_freezable, ) + +from .. import rlp from ..crypto.hash import Hash32, keccak256 Address = Bytes20 diff --git a/src/ethereum/tangerine_whistle/transactions.py b/src/ethereum/tangerine_whistle/transactions.py index 99c55fc975..bd84379f6c 100644 --- a/src/ethereum/tangerine_whistle/transactions.py +++ b/src/ethereum/tangerine_whistle/transactions.py @@ -6,7 +6,8 @@ from dataclasses import dataclass from typing import Union -from ..base_types import U256, Bytes, Bytes0, Uint, slotted_freezable +from ethereum.base_types import U256, Bytes, Bytes0, Uint, slotted_freezable + from .fork_types import Address TX_BASE_COST = 21000 diff --git a/src/ethereum/tangerine_whistle/trie.py b/src/ethereum/tangerine_whistle/trie.py index 47da1d101d..5d486a696f 100644 --- a/src/ethereum/tangerine_whistle/trie.py +++ b/src/ethereum/tangerine_whistle/trie.py @@ -29,13 +29,13 @@ cast, ) +from ethereum.base_types import U256, Bytes, Uint, slotted_freezable from ethereum.crypto.hash import keccak256 from ethereum.dao_fork 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 Transaction diff --git a/src/ethereum/tangerine_whistle/vm/memory.py b/src/ethereum/tangerine_whistle/vm/memory.py index d8a904c352..4315a8cc11 100644 --- a/src/ethereum/tangerine_whistle/vm/memory.py +++ b/src/ethereum/tangerine_whistle/vm/memory.py @@ -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 diff --git a/src/ethereum_spec_tools/lint/lints/glacier_forks_hygiene.py b/src/ethereum_spec_tools/lint/lints/glacier_forks_hygiene.py index a567df50a7..284f0ead23 100644 --- a/src/ethereum_spec_tools/lint/lints/glacier_forks_hygiene.py +++ b/src/ethereum_spec_tools/lint/lints/glacier_forks_hygiene.py @@ -18,6 +18,7 @@ EXCEPTIONAL_DIFFS = [ # There are some differences between london and arrow_glacier # in terms of how the fork block is handled. + ("arrow_glacier", ".fork", "validate_ommer_header"), ("arrow_glacier", ".fork", "calculate_base_fee_per_gas"), ("arrow_glacier", ".fork", "validate_header"), ("arrow_glacier", ".fork", "INITIAL_BASE_FEE"), diff --git a/whitelist.txt b/whitelist.txt index 2d0c8d696f..25f8084774 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -18,11 +18,13 @@ coinbase coincurve crypto E501 +eip encodings endian eth ethash ethereum +ethereum's evm exc fmt