Skip to content

Commit

Permalink
Merge pull request #1016 from gurukamath/update-requests
Browse files Browse the repository at this point in the history
Implement Pectra Devnet 4 changes for requests and 7702
  • Loading branch information
petertdavies authored Oct 24, 2024
2 parents 2875a73 + af31289 commit a95b7aa
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 372 deletions.
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

0 comments on commit a95b7aa

Please sign in to comment.