Skip to content

Commit

Permalink
refactor based on review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
gurukamath authored and SamWilsn committed Jun 18, 2024
1 parent 180f96b commit 7b72f83
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 132 deletions.
99 changes: 49 additions & 50 deletions src/ethereum/prague/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from dataclasses import dataclass
from typing import Tuple, Union

from ethereum.exceptions import InvalidBlock

from .. import rlp
from ..base_types import (
U64,
Expand All @@ -27,7 +25,13 @@
)
from ..crypto.hash import Hash32
from .fork_types import Address, Bloom, Root
from .transactions import LegacyTransaction
from .transactions import (
AccessListTransaction,
BlobTransaction,
FeeMarketTransaction,
LegacyTransaction,
Transaction,
)
from .utils.hexadecimal import hex_to_address

DEPOSIT_CONTRACT_ADDRESS = hex_to_address(
Expand Down Expand Up @@ -119,22 +123,29 @@ class Receipt:
logs: Tuple[Log, ...]


def validate_requests(requests: Tuple[Bytes, ...]) -> None:
def encode_receipt(tx: Transaction, receipt: Receipt) -> Union[Bytes, Receipt]:
"""
Validate a list of requests.
Encodes a receipt.
"""
current_request_type = b"\x00"
for request in requests:
request_type = request[:1]
if isinstance(tx, AccessListTransaction):
return b"\x01" + rlp.encode(receipt)
elif isinstance(tx, FeeMarketTransaction):
return b"\x02" + rlp.encode(receipt)
elif isinstance(tx, BlobTransaction):
return b"\x03" + rlp.encode(receipt)
else:
return receipt

# Ensure that no undefined requests are present.
if request_type not in (DEPOSIT_REQUEST_TYPE, WITHDRAWAL_REQUEST_TYPE):
raise InvalidBlock("BlockException.INVALID_REQUESTS")

# Ensure that requests are in order.
if request_type < current_request_type:
raise InvalidBlock("BlockException.INVALID_REQUESTS")
current_request_type = request_type
def decode_receipt(receipt: Union[Bytes, Receipt]) -> Receipt:
"""
Decodes a receipt.
"""
if isinstance(receipt, Bytes):
assert receipt[0] in (b"\x01", b"\x02", b"\x03")
return rlp.decode_to(Receipt, receipt[1:])
else:
return receipt


@slotted_freezable
Expand Down Expand Up @@ -178,7 +189,7 @@ def encode_request(req: Request) -> Bytes:
raise Exception("Unknown request type")


def parse_deposit_data(data: Bytes) -> Bytes:
def parse_deposit_data(data: Bytes) -> DepositRequest:
"""
Parses Deposit Request from the DepositContract.DepositEvent data.
"""
Expand All @@ -190,33 +201,26 @@ def parse_deposit_data(data: Bytes) -> Bytes:
index=U64.from_le_bytes(data[544:552]),
)

return encode_request(deposit_request)
return deposit_request


def validate_deposit_requests(
receipts: Tuple[Receipt, ...], requests: Tuple[Bytes, ...]
) -> None:
def parse_deposit_requests_from_receipt(
receipt: Union[Bytes, Receipt],
) -> Tuple[Bytes, ...]:
"""
Validate a list of deposit requests.
Parse deposit requests from a receipt.
"""
# Retrieve all deposit requests from receipts.
expected_deposit_requests = []
for receipt in receipts:
for log in receipt.logs:
if log.address == DEPOSIT_CONTRACT_ADDRESS:
deposit_request_rlp = parse_deposit_data(log.data)
expected_deposit_requests.append(deposit_request_rlp)
deposit_requests: Tuple[Bytes, ...] = ()
decoded_receipt = decode_receipt(receipt)
for log in decoded_receipt.logs:
if log.address == DEPOSIT_CONTRACT_ADDRESS:
deposit_request = parse_deposit_data(log.data)
deposit_requests += (encode_request(deposit_request),)

# Retrieve all deposit requests from block body
deposit_requests = [
req for req in requests if req[:1] == DEPOSIT_REQUEST_TYPE
]
return deposit_requests

if deposit_requests != expected_deposit_requests:
raise InvalidBlock("BlockException.INVALID_REQUESTS")


def parse_withdrawal_data(data: Bytes) -> Bytes:
def parse_withdrawal_data(data: Bytes) -> WithdrawalRequest:
"""
Parses Withdrawal Request from the data.
"""
Expand All @@ -227,28 +231,23 @@ def parse_withdrawal_data(data: Bytes) -> Bytes:
amount=U64.from_be_bytes(data[68:76]),
)

return encode_request(req)
return req


def validate_withdrawal_requests(
evm_call_output: Bytes, requests: Tuple[Bytes, ...]
) -> None:
def parse_withdrawal_requests_from_system_tx(
evm_call_output: Bytes,
) -> Tuple[Bytes, ...]:
"""
Validate a list of withdrawal requests.
Parse withdrawal requests from the system transaction output.
"""
count_withdrawal_requests = len(evm_call_output) // 76

expected_withdrawal_requests = []
withdrawal_requests: Tuple[Bytes, ...] = ()
for i in range(count_withdrawal_requests):
start = i * 76
withdrawal_request_rlp = parse_withdrawal_data(
withdrawal_request = parse_withdrawal_data(
evm_call_output[start : start + 76]
)
expected_withdrawal_requests.append(withdrawal_request_rlp)

withdrawal_requests = [
req for req in requests if req[:1] == WITHDRAWAL_REQUEST_TYPE
]
withdrawal_requests += (encode_request(withdrawal_request),)

if withdrawal_requests != expected_withdrawal_requests:
raise InvalidBlock("BlockException.INVALID_REQUESTS")
return withdrawal_requests
42 changes: 22 additions & 20 deletions src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
Log,
Receipt,
Withdrawal,
validate_deposit_requests,
validate_requests,
validate_withdrawal_requests,
encode_receipt,
parse_deposit_requests_from_receipt,
parse_withdrawal_requests_from_system_tx,
)
from .bloom import logs_bloom
from .fork_types import Address, Bloom, Root, VersionedHash
Expand Down Expand Up @@ -469,14 +469,7 @@ def make_receipt(
logs=logs,
)

if isinstance(tx, AccessListTransaction):
return b"\x01" + rlp.encode(receipt)
elif isinstance(tx, FeeMarketTransaction):
return b"\x02" + rlp.encode(receipt)
elif isinstance(tx, BlobTransaction):
return b"\x03" + rlp.encode(receipt)
else:
return receipt
return encode_receipt(tx, receipt)


@dataclass
Expand Down Expand Up @@ -600,6 +593,11 @@ def process_system_transaction(

system_tx_output = process_message_call(system_tx_message, system_tx_env)

# TODO: Empty accounts in post-merge forks are impossible
# see Ethereum Improvement Proposal 7523.
# This line is only included to support invalid tests in the test suite
# and will have to be removed in the future.
# See https://github.com/ethereum/execution-specs/issues/955
destroy_touched_empty_accounts(
system_tx_env.state, system_tx_output.touched_accounts
)
Expand Down Expand Up @@ -684,7 +682,7 @@ def apply_body(
secured=False, default=None
)
block_logs: Tuple[Log, ...] = ()
receipts: Tuple[Receipt, ...] = ()
requests_from_execution: Tuple[Bytes, ...] = ()

process_system_transaction(
BEACON_ROOTS_ADDRESS,
Expand Down Expand Up @@ -748,8 +746,9 @@ def apply_body(
rlp.encode(Uint(i)),
receipt,
)
if isinstance(receipt, Receipt):
receipts += (receipt,)

deposit_requests = parse_deposit_requests_from_receipt(receipt)
requests_from_execution += deposit_requests

block_logs += logs
blob_gas_used += calculate_total_blob_gas(tx)
Expand All @@ -768,9 +767,6 @@ def apply_body(
destroy_account(state, wd.address)

# Requests are to be in ascending order of request type
validate_requests(requests)

validate_deposit_requests(receipts, requests)

system_withdrawal_tx_output = process_system_transaction(
WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS,
Expand All @@ -786,10 +782,16 @@ def apply_body(
excess_blob_gas,
)

validate_withdrawal_requests(
system_withdrawal_tx_output.return_data, requests
withdrawal_requests = parse_withdrawal_requests_from_system_tx(
system_withdrawal_tx_output.return_data
)
for i, request in enumerate(requests):

requests_from_execution += withdrawal_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(
Expand Down
14 changes: 0 additions & 14 deletions src/ethereum_spec_tools/evm_tools/loaders/fixture_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,6 @@ def json_to_withdrawals(self, raw: Any) -> Any:

return self.fork.Withdrawal(*parameters)

def json_to_request(self, raw: Any) -> Any:
"""Converts json requests data to a request object"""
deposit_request = self.fork.DepositRequest(
pubkey=hex_to_bytes(raw.get("pubkey")),
withdrawal_credentials=hex_to_bytes32(
raw.get("withdrawalCredentials")
),
amount=hex_to_u64(raw.get("amount")),
signature=hex_to_bytes(raw.get("signature")),
index=hex_to_u64(raw.get("index")),
)

return self.fork.encode_request(deposit_request)

def json_to_block(
self,
json_block: Any,
Expand Down
27 changes: 6 additions & 21 deletions src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,29 +133,14 @@ def Block(self) -> Any:
return self._module("blocks").Block

@property
def validate_requests(self) -> Any:
"""validate_requests function of the fork"""
return self._module("blocks").validate_requests
def parse_withdrawal_requests_from_system_tx(self) -> Any:
"""parse_withdrawal_requests_from_system_tx function of the fork"""
return self._module("blocks").parse_withdrawal_requests_from_system_tx

@property
def validate_deposit_requests(self) -> Any:
"""validate_deposit_requests function of the fork"""
return self._module("blocks").validate_deposit_requests

@property
def validate_withdrawal_requests(self) -> Any:
"""validate_withdrawal_requests function of the fork"""
return self._module("blocks").validate_withdrawal_requests

@property
def DepositRequest(self) -> Any:
"""Deposit request class of the fork"""
return self._module("blocks").DepositRequest

@property
def encode_request(self) -> Any:
"""encode_request function of the fork"""
return self._module("blocks").encode_request
def parse_deposit_requests_from_receipt(self) -> Any:
"""parse_deposit_requests_from_receipt function of the fork"""
return self._module("blocks").parse_deposit_requests_from_receipt

@property
def Bloom(self) -> Any:
Expand Down
Loading

0 comments on commit 7b72f83

Please sign in to comment.