Skip to content

Commit

Permalink
Implement most of EIP-4788 - considerations:
Browse files Browse the repository at this point in the history
- Should we make sure to update the Cancun state with the contract at
  BEACON_ROOTS_ADDRESS if it doesn't exist yet since it is vital to
  this EIP?
  • Loading branch information
fselmo committed Jan 23, 2024
1 parent 0ecccac commit 9262f9e
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 15 deletions.
8 changes: 8 additions & 0 deletions eth/abc.py
Expand Up @@ -194,6 +194,14 @@ def copy(self, *args: Any, **kwargs: Any) -> "BlockHeaderAPI":
"""
...

@property
@abstractmethod
def parent_beacon_block_root(self) -> Optional[Hash32]:
"""
Return the hash of the parent beacon block.
"""
...


class LogAPI(ABC):
"""
Expand Down
4 changes: 4 additions & 0 deletions eth/rlp/headers.py
Expand Up @@ -192,3 +192,7 @@ def base_fee_per_gas(self) -> int:
@property
def withdrawals_root(self) -> Optional[Hash32]:
raise AttributeError("Withdrawals root not available until Shanghai fork")

@property
def parent_beacon_block_root(self) -> Optional[Hash32]:
raise AttributeError("Parent beacon block root not available until Cancun fork")
1 change: 1 addition & 0 deletions eth/validation.py
Expand Up @@ -251,6 +251,7 @@ def validate_gas_limit(gas_limit: int, parent_gas_limit: int) -> None:
"transaction_root",
"receipt_root",
"withdrawals_root",
"parent_beacon_block_root",
}


Expand Down
27 changes: 22 additions & 5 deletions eth/vm/base.py
Expand Up @@ -345,7 +345,7 @@ def import_block(self, block: BlockAPI) -> BlockAndMetaWitness:
f" the attempted block was #{block.number}"
)

header_params = {
block_header_fields = {
"coinbase": block.header.coinbase,
"difficulty": block.header.difficulty,
"gas_limit": block.header.gas_limit,
Expand All @@ -356,16 +356,23 @@ def import_block(self, block: BlockAPI) -> BlockAndMetaWitness:
"uncles_hash": keccak(rlp.encode(block.uncles)),
}

block_params = {
"header": self.configure_header(**header_params),
try:
# post-cancun blocks
parent_beacon_block_root = block.header.parent_beacon_block_root
block_header_fields["parent_beacon_block_root"] = parent_beacon_block_root
except AttributeError:
pass

block_fields = {
"header": self.configure_header(**block_header_fields),
"uncles": block.uncles,
}

if hasattr(block, "withdrawals"):
# post-shanghai blocks
block_params["withdrawals"] = block.withdrawals
block_fields["withdrawals"] = block.withdrawals

self._block = self.get_block().copy(**block_params)
self._block = self.get_block().copy(**block_fields)

execution_context = self.create_execution_context(
block.header, self.previous_hashes, self.chain_context
Expand All @@ -380,6 +387,9 @@ def import_block(self, block: BlockAPI) -> BlockAndMetaWitness:
self.chaindb.db, execution_context, header.state_root
)

# apply any block-related state processing
self.block_preprocessing(self._state, block.header)

# run all of the transactions.
new_header, receipts, _ = self.apply_all_transactions(
block.transactions, header
Expand All @@ -401,6 +411,13 @@ def import_block(self, block: BlockAPI) -> BlockAndMetaWitness:

return self.mine_block(filled_block)

@classmethod
def block_preprocessing(cls, state: StateAPI, header: BlockHeaderAPI) -> None:
"""
Process any state changes before processing a block. Pre-processing does not
become relevant until the Cancun network upgrade.
"""

def mine_block(
self, block: BlockAPI, *args: Any, **kwargs: Any
) -> BlockAndMetaWitness:
Expand Down
48 changes: 43 additions & 5 deletions eth/vm/forks/cancun/__init__.py
Expand Up @@ -2,16 +2,37 @@
Type,
)

from eth.rlp.blocks import BaseBlock
from eth.vm.forks.shanghai import ShanghaiVM
from eth.vm.state import BaseState
from eth.abc import (
BlockHeaderAPI,
StateAPI,
)
from eth.rlp.blocks import (
BaseBlock,
)
from eth.vm.forks.shanghai import (
ShanghaiVM,
)
from eth.vm.state import (
BaseState,
)
from eth_utils import (
to_int,
)

from .blocks import CancunBlock
from .blocks import (
CancunBlock,
)
from .constants import (
BEACON_ROOTS_ADDRESS,
HISTORY_BUFFER_LENGTH,
)
from .headers import (
configure_cancun_header,
create_cancun_header_from_parent,
)
from .state import CancunState
from .state import (
CancunState,
)


class CancunVM(ShanghaiVM):
Expand All @@ -27,3 +48,20 @@ class CancunVM(ShanghaiVM):
create_cancun_header_from_parent()
)
configure_header = configure_cancun_header

@classmethod
def block_preprocessing(cls, state: StateAPI, header: BlockHeaderAPI) -> None:
super().block_preprocessing(state, header)

parent_beacon_root = header.parent_beacon_block_root

state.set_storage(
BEACON_ROOTS_ADDRESS,
header.timestamp % HISTORY_BUFFER_LENGTH,
header.timestamp,
)
state.set_storage(
BEACON_ROOTS_ADDRESS,
header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH,
to_int(parent_beacon_root),
)
4 changes: 4 additions & 0 deletions eth/vm/forks/cancun/constants.py
@@ -0,0 +1,4 @@
HISTORY_BUFFER_LENGTH = 8191
BEACON_ROOTS_ADDRESS = (
b'\x00\x0f=\xf6\xd72\x80~\xf11\x9f\xb7\xb8\xbb\x85"\xd0\xbe\xac\x02'
)
2 changes: 1 addition & 1 deletion eth/vm/forks/cancun/headers.py
Expand Up @@ -30,10 +30,10 @@ def create_cancun_header_from_parent(
shanghai_validated_header = create_shanghai_header_from_parent(
parent_header, **header_params
)

# extract params validated up to shanghai (previous VM)
# and plug into a `CancunBlockHeader` class
all_fields = shanghai_validated_header.as_dict()

return CancunBlockHeader(**all_fields)


Expand Down
4 changes: 4 additions & 0 deletions eth/vm/forks/london/blocks.py
Expand Up @@ -176,6 +176,10 @@ def is_genesis(self) -> bool:
def withdrawals_root(self) -> Optional[Hash32]:
raise AttributeError("Withdrawals root not available until Shanghai fork")

@property
def parent_beacon_block_root(self) -> Optional[Hash32]:
raise AttributeError("Parent beacon block root not available until Cancun fork")


class LondonBackwardsHeader(BlockHeaderSedesAPI):
"""
Expand Down
5 changes: 5 additions & 0 deletions eth/vm/forks/shanghai/blocks.py
Expand Up @@ -3,6 +3,7 @@
)
from typing import (
List,
Optional,
Sequence,
Tuple,
Type,
Expand Down Expand Up @@ -181,6 +182,10 @@ def hex_hash(self) -> str:
def is_genesis(self) -> bool:
return self.parent_hash == GENESIS_PARENT_HASH and self.block_number == 0

@property
def parent_beacon_block_root(self) -> Optional[Hash32]:
raise AttributeError("Parent beacon block root is not available until Cancun.")


class ShanghaiBackwardsHeader(BlockHeaderSedesAPI):
"""
Expand Down
4 changes: 0 additions & 4 deletions tests/json-fixtures/blockchain/test_blockchain.py
Expand Up @@ -1149,10 +1149,6 @@
def blockchain_fixture_mark_fn(fixture_path, fixture_name, fixture_fork):
fixture_id = (fixture_path, fixture_name)

if "Pyspecs" in fixture_path:
# TODO: Turn on Pyspecs tests when we restructure the test suite
return pytest.mark.skip("Turn off Pyspecs tests for now.")

# -- expected skips and failures -- #
if "bcExploitTest/" in fixture_path:
return pytest.mark.skip("Exploit tests are slow")
Expand Down

0 comments on commit 9262f9e

Please sign in to comment.