Skip to content

Commit

Permalink
Implement EIP-6110
Browse files Browse the repository at this point in the history
  • Loading branch information
gurukamath committed May 3, 2024
1 parent 3d5c5b4 commit 4dcfb25
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 6 deletions.
11 changes: 11 additions & 0 deletions src/ethereum/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,17 @@ class Bytes64(FixedBytes):
"""


class Bytes96(FixedBytes):
"""
Byte array of exactly 96 elements.
"""

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


class Bytes256(FixedBytes):
"""
Byte array of exactly 256 elements.
Expand Down
76 changes: 76 additions & 0 deletions src/ethereum/prague/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,29 @@
from dataclasses import dataclass
from typing import Tuple, Union

from ethereum.exceptions import InvalidBlock

from .. import rlp
from ..base_types import (
U64,
U256,
Bytes,
Bytes8,
Bytes32,
Bytes48,
Bytes96,
Uint,
slotted_freezable,
)
from ..crypto.hash import Hash32
from .fork_types import Address, Bloom, Root
from .transactions import LegacyTransaction
from .utils.hexadecimal import hex_to_address

DEPOSIT_CONTRACT_ADDRESS = hex_to_address(
"0x00000000219ab540356cbb839cbe05303d7705fa"
)
DEPOSIT_REQUEST_TYPE = b"\x00"


@slotted_freezable
Expand Down Expand Up @@ -117,3 +128,68 @@ def validate_requests(requests: Tuple[Bytes, ...]) -> bool:
return False
current_request_type = request[:1]
return True


@slotted_freezable
@dataclass
class DepositRequest:
"""
Requests for validator deposits on chain (See EIP-6110).
"""

pubkey: Bytes48
withdrawal_credentials: Bytes32
amount: U64
signature: Bytes96
index: U64


Request = DepositRequest


def encode_request(req: Request) -> Bytes:
"""
Encode a request.
"""
if isinstance(req, DepositRequest):
return DEPOSIT_REQUEST_TYPE + rlp.encode(req)
else:
raise Exception("Unknown request type")


def parse_deposit_data(data: Bytes) -> Bytes:
"""
Parses Deposit Request from the DepositContract.DepositEvent data.
"""
deposit_request = DepositRequest(
pubkey=Bytes48(data[192:240]),
withdrawal_credentials=Bytes32(data[288:320]),
amount=U64.from_le_bytes(data[352:360]),
signature=Bytes96(data[416:512]),
index=U64.from_le_bytes(data[544:552]),
)

return encode_request(deposit_request)


def validate_deposit_requests(
receipts: Tuple[Receipt, ...], requests: Tuple[Bytes, ...]
) -> None:
"""
Validate a list of deposit requests.
"""
# 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)

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

if deposit_requests != expected_deposit_requests:
raise InvalidBlock("BlockException.INVALID_REQUESTS")
14 changes: 13 additions & 1 deletion src/ethereum/prague/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@
from .. import rlp
from ..base_types import U64, U256, Bytes, Uint
from . import vm
from .blocks import Block, Header, Log, Receipt, Withdrawal, validate_requests
from .blocks import (
Block,
Header,
Log,
Receipt,
Withdrawal,
validate_deposit_requests,
validate_requests,
)
from .bloom import logs_bloom
from .fork_types import Address, Bloom, Root, VersionedHash
from .state import (
Expand Down Expand Up @@ -587,6 +595,7 @@ def apply_body(
secured=False, default=None
)
block_logs: Tuple[Log, ...] = ()
receipts: Tuple[Receipt, ...] = ()

beacon_block_roots_contract_code = get_account(
state, BEACON_ROOTS_ADDRESS
Expand Down Expand Up @@ -683,6 +692,8 @@ def apply_body(
rlp.encode(Uint(i)),
receipt,
)
if isinstance(receipt, Receipt):
receipts += (receipt,)

block_logs += logs
blob_gas_used += calculate_total_blob_gas(tx)
Expand All @@ -704,6 +715,7 @@ def apply_body(
if not validate_requests(requests):
raise InvalidBlock

validate_deposit_requests(receipts, requests)
for i, request in enumerate(requests):
trie_set(requests_trie, rlp.encode(Uint(i)), request)

Expand Down
14 changes: 14 additions & 0 deletions src/ethereum_spec_tools/evm_tools/loaders/fixture_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@ 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
15 changes: 15 additions & 0 deletions src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,21 @@ def validate_requests(self) -> Any:
"""validate_requests function of the fork"""
return self._module("blocks").validate_requests

@property
def validate_deposit_requests(self) -> Any:
"""validate_deposit_requests function of the fork"""
return self._module("blocks").validate_deposit_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

@property
def Bloom(self) -> Any:
"""Bloom class of the fork"""
Expand Down
7 changes: 6 additions & 1 deletion src/ethereum_spec_tools/evm_tools/t8n/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import json
import os
from functools import partial
from typing import Any, TextIO
from typing import Any, TextIO, Tuple

from ethereum import rlp, trace
from ethereum.base_types import U64, U256, Uint
Expand Down Expand Up @@ -314,6 +314,7 @@ def apply_body(self) -> None:
blob_gas_used = Uint(0)
if self.fork.is_after_fork("ethereum.prague"):
requests_trie = self.fork.Trie(secured=False, default=None)
receipts: Tuple[bytes, ...] = ()

if (
self.fork.is_after_fork("ethereum.cancun")
Expand Down Expand Up @@ -413,6 +414,8 @@ def apply_body(self) -> None:
rlp.encode(Uint(i)),
receipt,
)
if self.fork.is_after_fork("ethereum.prague"):
receipts += (receipt,)

self.txs.add_receipt(tx, gas_consumed)

Expand Down Expand Up @@ -454,6 +457,8 @@ def apply_body(self) -> None:
if not self.fork.validate_requests(self.env.requests):
raise InvalidBlock

self.fork.validate_deposit_requests(receipts, self.env.requests)

for i, request in enumerate(self.env.requests):
self.fork.trie_set(requests_trie, rlp.encode(Uint(i)), request)

Expand Down
15 changes: 11 additions & 4 deletions src/ethereum_spec_tools/evm_tools/t8n/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ def __init__(self, t8n: "T8N", stdin: Optional[Dict] = None):
)
self.read_excess_blob_gas(data, t8n)

if t8n.fork.is_after_fork("ethereum.prague"):
self.requests = tuple(
hex_to_bytes(request) for request in data["requests"]
)
self.read_requests(data, t8n)

def read_excess_blob_gas(self, data: Any, t8n: "T8N") -> None:
"""
Expand Down Expand Up @@ -196,6 +193,16 @@ def read_withdrawals(self, data: Any, t8n: "T8N") -> None:
t8n.json_to_withdrawals(wd) for wd in data["withdrawals"]
)

def read_requests(self, data: Any, t8n: "T8N") -> None:
"""
Read the requests from the data.
"""
self.requests = None
if t8n.fork.is_after_fork("ethereum.prague"):
self.requests = tuple(
t8n.json_to_request(req) for req in data["requests"]
)

def read_block_difficulty(self, data: Any, t8n: "T8N") -> None:
"""
Read the block difficulty from the data.
Expand Down
4 changes: 4 additions & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -431,3 +431,7 @@ uds
appname
appauthor
orelse

Bytes96
pubkey
req

0 comments on commit 4dcfb25

Please sign in to comment.