Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement Pectra Devnet 4 changes for requests and 7702 #1016

Merged
merged 5 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/ethereum/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,41 @@ def to_signed(self) -> int:
U256.MAX_VALUE = int.__new__(U256, (2**256) - 1)


class U8(FixedUint):
"""
Unsigned positive integer, which can represent `0` to `2 ** 8 - 1`,
inclusive.
"""

MAX_VALUE: ClassVar["U8"]
"""
Largest value that can be represented by this integer type.
"""

__slots__ = ()

@classmethod
def from_le_bytes(cls: Type, buffer: "Bytes1") -> "U8":
"""
Converts a sequence of bytes into an arbitrarily sized unsigned integer
from its little endian representation.
"""
if len(buffer) > 1:
raise ValueError()

return cls(int.from_bytes(buffer, "little"))

def to_le_bytes(self) -> "Bytes1":
"""
Converts this fixed sized unsigned integer into its little endian
representation, with exactly 1 byte.
"""
return Bytes1(self.to_bytes(1, "little"))


U8.MAX_VALUE = int.__new__(U8, (2**8) - 1)


class U32(FixedUint):
"""
Unsigned positive integer, which can represent `0` to `2 ** 32 - 1`,
Expand Down Expand Up @@ -848,6 +883,17 @@ class Bytes0(FixedBytes):
"""


class Bytes1(FixedBytes):
"""
Byte array of exactly a single byte.
"""

LENGTH = 1
"""
Number of bytes in each instance of this class.
"""


class Bytes4(FixedBytes):
"""
Byte array of exactly four elements.
Expand Down
4 changes: 2 additions & 2 deletions src/ethereum/genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ def add_genesis_block(
if has_field(hardfork.Header, "parent_beacon_block_root"):
fields["parent_beacon_block_root"] = Hash32(b"\0" * 32)

if has_field(hardfork.Header, "requests_root"):
fields["requests_root"] = hardfork.root(hardfork.Trie(False, None))
if has_field(hardfork.Header, "requests_hash"):
fields["requests_hash"] = Hash32(b"\0" * 32)

genesis_header = hardfork.Header(**fields)

Expand Down
3 changes: 1 addition & 2 deletions src/ethereum/prague/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class Header:
blob_gas_used: U64
excess_blob_gas: U64
parent_beacon_block_root: Root
requests_root: Root
requests_hash: Hash32


@slotted_freezable
Expand All @@ -87,7 +87,6 @@ class Block:
transactions: Tuple[Union[Bytes, LegacyTransaction], ...]
ommers: Tuple[Header, ...]
withdrawals: Tuple[Withdrawal, ...]
requests: Tuple[Bytes, ...]


@slotted_freezable
Expand Down
135 changes: 93 additions & 42 deletions src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
from .bloom import logs_bloom
from .fork_types import Address, Authorization, Bloom, Root, VersionedHash
from .requests import (
parse_consolidation_requests_from_system_tx,
CONSOLIDATION_REQUEST_TYPE,
DEPOSIT_REQUEST_TYPE,
WITHDRAWAL_REQUEST_TYPE,
compute_requests_hash,
parse_deposit_requests_from_receipt,
parse_withdrawal_requests_from_system_tx,
)
from .state import (
State,
Expand Down Expand Up @@ -91,10 +93,10 @@
"0x0aae40965e6800cd9b1f4b05ff21581047e3f91e"
)
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS = hex_to_address(
"0x00A3ca265EBcb825B45F985A16CEFB49958cE017"
"0x09Fc772D0857550724b07B850a4323f39112aAaA"
)
CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS = hex_to_address(
"0x00b42dbf2194e931e80326d950320f7d9dbeac02"
"0x01aBEa29659e5e97C95107F20bb753cD3e09bBBb"
)
SYSTEM_TRANSACTION_GAS = Uint(30000000)
MAX_BLOB_GAS_PER_BLOCK = 786432
Expand Down Expand Up @@ -220,7 +222,6 @@ def state_transition(chain: BlockChain, block: Block) -> None:
block.withdrawals,
block.header.parent_beacon_block_root,
excess_blob_gas,
block.requests,
)
if apply_body_output.block_gas_used != block.header.gas_used:
raise InvalidBlock
Expand All @@ -236,7 +237,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
raise InvalidBlock
if apply_body_output.blob_gas_used != block.header.blob_gas_used:
raise InvalidBlock
if apply_body_output.requests_root != block.header.requests_root:
if apply_body_output.requests_hash != block.header.requests_hash:
raise InvalidBlock

chain.blocks.append(block)
Expand Down Expand Up @@ -522,8 +523,8 @@ class ApplyBodyOutput:
Trie root of all the withdrawals in the block.
blob_gas_used : `ethereum.base_types.Uint`
Total blob gas used in the block.
requests_root : `ethereum.fork_types.Root`
Trie root of all the requests in the block.
requests_hash : `Bytes`
Hash of all the requests in the block.
"""

block_gas_used: Uint
Expand All @@ -533,7 +534,7 @@ class ApplyBodyOutput:
state_root: Root
withdrawals_root: Root
blob_gas_used: Uint
requests_root: Root
requests_hash: Bytes


def process_system_transaction(
Expand Down Expand Up @@ -652,7 +653,6 @@ def apply_body(
withdrawals: Tuple[Withdrawal, ...],
parent_beacon_block_root: Root,
excess_blob_gas: U64,
requests: Tuple[Bytes, ...],
) -> ApplyBodyOutput:
"""
Executes a block.
Expand Down Expand Up @@ -696,8 +696,6 @@ def apply_body(
The root of the beacon block from the parent block.
excess_blob_gas :
Excess blob gas calculated from the previous block.
requests :
Requests to be processed in the current block.

Returns
-------
Expand All @@ -715,11 +713,8 @@ def apply_body(
withdrawals_trie: Trie[Bytes, Optional[Union[Bytes, Withdrawal]]] = Trie(
secured=False, default=None
)
requests_trie: Trie[Bytes, Optional[Bytes]] = Trie(
secured=False, default=None
)
block_logs: Tuple[Log, ...] = ()
requests_from_execution: Tuple[Bytes, ...] = ()
deposit_requests: Bytes = b""

process_system_transaction(
BEACON_ROOTS_ADDRESS,
Expand Down Expand Up @@ -801,8 +796,7 @@ def apply_body(
receipt,
)

deposit_requests = parse_deposit_requests_from_receipt(receipt)
requests_from_execution += deposit_requests
deposit_requests += parse_deposit_requests_from_receipt(receipt)

block_logs += logs
blob_gas_used += calculate_total_blob_gas(tx)
Expand All @@ -820,7 +814,83 @@ def apply_body(
if account_exists_and_is_empty(state, wd.address):
destroy_account(state, wd.address)

requests_from_execution = process_general_purpose_requests(
deposit_requests,
state,
block_hashes,
coinbase,
block_number,
base_fee_per_gas,
block_gas_limit,
block_time,
prev_randao,
chain_id,
excess_blob_gas,
)

requests_hash = compute_requests_hash(requests_from_execution)

return ApplyBodyOutput(
block_gas_used,
root(transactions_trie),
root(receipts_trie),
block_logs_bloom,
state_root(state),
root(withdrawals_trie),
blob_gas_used,
requests_hash,
)


def process_general_purpose_requests(
deposit_requests: Bytes,
state: State,
block_hashes: List[Hash32],
coinbase: Address,
block_number: Uint,
base_fee_per_gas: Uint,
block_gas_limit: Uint,
block_time: U256,
prev_randao: Bytes32,
chain_id: U64,
excess_blob_gas: U64,
) -> List[Bytes]:
"""
Process all the requests in the block.

Parameters
----------
deposit_requests :
The deposit requests.
state :
Current state.
block_hashes :
List of hashes of the previous 256 blocks.
coinbase :
Address of the block's coinbase.
block_number :
Block number.
base_fee_per_gas :
Base fee per gas.
block_gas_limit :
Initial amount of gas available for execution in this block.
block_time :
Time the block was produced.
prev_randao :
The previous randao from the beacon chain.
chain_id :
ID of the executing chain.
excess_blob_gas :
Excess blob gas.

Returns
-------
requests_from_execution : `List[Bytes]`
The requests from the execution
"""
# Requests are to be in ascending order of request type
requests_from_execution: List[Bytes] = []
requests_from_execution.append(DEPOSIT_REQUEST_TYPE + deposit_requests)

system_withdrawal_tx_output = process_system_transaction(
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
Expand All @@ -837,12 +907,10 @@ def apply_body(
excess_blob_gas,
)

withdrawal_requests = parse_withdrawal_requests_from_system_tx(
system_withdrawal_tx_output.return_data
requests_from_execution.append(
WITHDRAWAL_REQUEST_TYPE + system_withdrawal_tx_output.return_data
)

requests_from_execution += withdrawal_requests

system_consolidation_tx_output = process_system_transaction(
CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS,
b"",
Expand All @@ -858,28 +926,11 @@ def apply_body(
excess_blob_gas,
)

consolidation_requests = parse_consolidation_requests_from_system_tx(
system_consolidation_tx_output.return_data
requests_from_execution.append(
CONSOLIDATION_REQUEST_TYPE + system_consolidation_tx_output.return_data
)

requests_from_execution += consolidation_requests

if requests_from_execution != requests:
raise InvalidBlock

for i, request in enumerate(requests_from_execution):
trie_set(requests_trie, rlp.encode(Uint(i)), request)

return ApplyBodyOutput(
block_gas_used,
root(transactions_trie),
root(receipts_trie),
block_logs_bloom,
state_root(state),
root(withdrawals_trie),
blob_gas_used,
root(requests_trie),
)
return requests_from_execution


def process_transaction(
Expand Down
3 changes: 2 additions & 1 deletion src/ethereum/prague/fork_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from .. import rlp
from ..base_types import (
U8,
U64,
U256,
Bytes,
Expand Down Expand Up @@ -79,6 +80,6 @@ class Authorization:
chain_id: U64
address: Address
nonce: U64
y_parity: U256
y_parity: U8
r: U256
s: U256
Loading
Loading