Skip to content

Commit

Permalink
Modify Cancun's test_rlp and fork to use new Access type
Browse files Browse the repository at this point in the history
  • Loading branch information
richardgreg committed Aug 7, 2024
1 parent 12bf45e commit a91b66b
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 88 deletions.
13 changes: 7 additions & 6 deletions src/ethereum/cancun/fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,10 +754,10 @@ def process_transaction(
if isinstance(
tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
):
for address, keys in tx.access_list:
preaccessed_addresses.add(address)
for key in keys:
preaccessed_storage_keys.add((address, key))
for access in tx.access_list:
preaccessed_addresses.add(access.account)
for key in access.slots:
preaccessed_storage_keys.add((access.account, key))

message = prepare_message(
sender,
Expand Down Expand Up @@ -849,9 +849,10 @@ def calculate_intrinsic_cost(tx: Transaction) -> Uint:
if isinstance(
tx, (AccessListTransaction, FeeMarketTransaction, BlobTransaction)
):
for _address, keys in tx.access_list:
for access in tx.access_list:
access_list_cost += TX_ACCESS_LIST_ADDRESS_COST
access_list_cost += len(keys) * TX_ACCESS_LIST_STORAGE_KEY_COST
slots_cost = len(access.slots) * TX_ACCESS_LIST_STORAGE_KEY_COST
access_list_cost += slots_cost

return Uint(TX_BASE_COST + data_cost + create_cost + access_list_cost)

Expand Down
92 changes: 12 additions & 80 deletions src/ethereum/cancun/transactions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
"""
Transactions are atomic units of work created externally to Ethereum and
submitted to be executed. If Ethereum is viewed as a state machine,
transactions are the events that move between states.
"""
from dataclasses import dataclass
from typing import Tuple, Union

Expand All @@ -19,21 +14,17 @@
from ..exceptions import InvalidBlock
from .fork_types import Address, VersionedHash

TX_BASE_COST = 21000
TX_DATA_COST_PER_NON_ZERO = 16
TX_DATA_COST_PER_ZERO = 4
TX_CREATE_COST = 32000
TX_ACCESS_LIST_ADDRESS_COST = 2400
TX_ACCESS_LIST_STORAGE_KEY_COST = 1900

@slotted_freezable
@dataclass
class Access:
account: Address
slots: Tuple[Bytes32, ...]


@slotted_freezable
@dataclass
class LegacyTransaction:
"""
Atomic operation performed on the block chain.
"""

nonce: U256
gas_price: Uint
gas: Uint
Expand All @@ -45,20 +36,9 @@ class LegacyTransaction:
s: U256


@slotted_freezable
@dataclass
class Access:
account: Address
slots: Tuple[Bytes32, ...]


@slotted_freezable
@dataclass
class AccessListTransaction:
"""
The transaction type added in EIP-2930 to support access lists.
"""

chain_id: U64
nonce: U256
gas_price: Uint
Expand All @@ -75,10 +55,6 @@ class AccessListTransaction:
@slotted_freezable
@dataclass
class FeeMarketTransaction:
"""
The transaction type added in EIP-1559.
"""

chain_id: U64
nonce: U256
max_priority_fee_per_gas: Uint
Expand All @@ -96,10 +72,6 @@ class FeeMarketTransaction:
@slotted_freezable
@dataclass
class BlobTransaction:
"""
The transaction type added in EIP-4844.
"""

chain_id: U64
nonce: U256
max_priority_fee_per_gas: Uint
Expand All @@ -116,28 +88,6 @@ class BlobTransaction:
s: U256


# Helper function to handle the RLP encoding of the Access class instances.
def encode_access_list(
access_list: Tuple[Access, ...]
) -> Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]:
"""
Encode the Access list for RLP encoding.
"""
return tuple((access.account, access.slots) for access in access_list)


# Helper function to handle the RLP decoding of the Access class instances.
def decode_access_list(
encoded_access_list: Tuple[Tuple[Address, Tuple[Bytes32, ...]], ...]
) -> Tuple[Access, ...]:
"""
Decode the Access list from RLP encoding.
"""
return tuple(
Access(account=encoded[0], slots=encoded[1]
) for encoded in encoded_access_list)


Transaction = Union[
LegacyTransaction,
AccessListTransaction,
Expand All @@ -147,44 +97,26 @@ def decode_access_list(


def encode_transaction(tx: Transaction) -> Union[LegacyTransaction, Bytes]:
"""
Encode a transaction. Needed because non-legacy transactions aren't RLP.
"""
if isinstance(tx, LegacyTransaction):
return tx
elif isinstance(tx, AccessListTransaction):
encoded_access_list = encode_access_list(tx.access_list)
return b"\x01" + rlp.encode(tx._replace(
access_list=encoded_access_list))
return b"\x01" + rlp.encode(tx)
elif isinstance(tx, FeeMarketTransaction):
encoded_access_list = encode_access_list(tx.access_list)
return b"\x02" + rlp.encode(tx._replace(
access_list=encoded_access_list))
return b"\x02" + rlp.encode(tx)
elif isinstance(tx, BlobTransaction):
encoded_access_list = encode_access_list(tx.access_list)
return b"\x03" + rlp.encode(tx._replace(
access_list=encoded_access_list))
return b"\x03" + rlp.encode(tx)
else:
raise Exception(f"Unable to encode transaction of type {type(tx)}")


def decode_transaction(tx: Union[LegacyTransaction, Bytes]) -> Transaction:
"""
Decode a transaction. Needed because non-legacy transactions aren't RLP.
"""
if isinstance(tx, Bytes):
if tx[0] == 1:
decoded_tx = rlp.decode_to(AccessListTransaction, tx[1:])
decoded_access_list = decode_access_list(decoded_tx.access_list)
return decoded_tx._replace(access_list=decoded_access_list)
return rlp.decode_to(AccessListTransaction, tx[1:])
elif tx[0] == 2:
decoded_tx = rlp.decode_to(FeeMarketTransaction, tx[1:])
decoded_access_list = decode_access_list(decoded_tx.access_list)
return decoded_tx._replace(access_list=decoded_access_list)
return rlp.decode_to(FeeMarketTransaction, tx[1:])
elif tx[0] == 3:
decoded_tx = rlp.decode_to(BlobTransaction, tx[1:])
decoded_access_list = decode_access_list(decoded_tx.access_list)
return decoded_tx._replace(access_list=decoded_access_list)
return rlp.decode_to(BlobTransaction, tx[1:])
else:
raise InvalidBlock
else:
Expand Down
5 changes: 3 additions & 2 deletions tests/cancun/test_rlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
Transaction,
decode_transaction,
encode_transaction,
Access
)
from ethereum.cancun.utils.hexadecimal import hex_to_address
from ethereum.crypto.hash import keccak256
Expand Down Expand Up @@ -59,7 +60,7 @@
Bytes0(),
U256(4),
Bytes(b"bar"),
((address1, (hash1, hash2)), (address2, tuple())),
(Access(account=address1, slots=(hash1, hash2)), Access(account=address2, slots=tuple())),
U256(27),
U256(5),
U256(6),
Expand All @@ -74,7 +75,7 @@
Bytes0(),
U256(4),
Bytes(b"bar"),
((address1, (hash1, hash2)), (address2, tuple())),
(Access(account=address1, slots=(hash1, hash2)), Access(account=address2, slots=tuple())),
U256(27),
U256(5),
U256(6),
Expand Down

0 comments on commit a91b66b

Please sign in to comment.