Skip to content

Commit 8da7485

Browse files
committed
Implement EIP-7805
1 parent 5a49b2f commit 8da7485

File tree

6 files changed

+120
-1
lines changed

6 files changed

+120
-1
lines changed

src/ethereum/osaka/fork.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,11 @@ def get_last_256_block_hashes(chain: BlockChain) -> List[Hash32]:
189189
return recent_block_hashes
190190

191191

192-
def state_transition(chain: BlockChain, block: Block) -> None:
192+
def state_transition(
193+
chain: BlockChain,
194+
block: Block,
195+
inclusion_list_transactions: Tuple[LegacyTransaction | Bytes, ...] = (),
196+
) -> None:
193197
"""
194198
Attempts to apply a block to an existing block chain.
195199
@@ -210,6 +214,8 @@ def state_transition(chain: BlockChain, block: Block) -> None:
210214
History and current state.
211215
block :
212216
Block to apply to `chain`.
217+
inclusion_list_transactions :
218+
Inclusion list transactions against which the block will be validated.
213219
"""
214220
if len(rlp.encode(block)) > MAX_RLP_BLOCK_SIZE:
215221
raise InvalidBlock("Block rlp size exceeds MAX_RLP_BLOCK_SIZE")
@@ -236,6 +242,7 @@ def state_transition(chain: BlockChain, block: Block) -> None:
236242
block_env=block_env,
237243
transactions=block.transactions,
238244
withdrawals=block.withdrawals,
245+
inclusion_list_transactions=inclusion_list_transactions,
239246
)
240247
block_state_root = state_root(block_env.state)
241248
transactions_root = root(block_output.transactions_trie)
@@ -727,6 +734,7 @@ def apply_body(
727734
block_env: vm.BlockEnvironment,
728735
transactions: Tuple[LegacyTransaction | Bytes, ...],
729736
withdrawals: Tuple[Withdrawal, ...],
737+
inclusion_list_transactions: Tuple[LegacyTransaction | Bytes, ...],
730738
) -> vm.BlockOutput:
731739
"""
732740
Executes a block.
@@ -746,6 +754,8 @@ def apply_body(
746754
Transactions included in the block.
747755
withdrawals :
748756
Withdrawals to be processed in the current block.
757+
inclusion_list_transactions :
758+
Inclusion list transactions against which the block will be validated.
749759
750760
Returns
751761
-------
@@ -769,6 +779,13 @@ def apply_body(
769779
for i, tx in enumerate(map(decode_transaction, transactions)):
770780
process_transaction(block_env, block_output, tx, Uint(i))
771781

782+
validate_inclusion_list_transactions(
783+
block_env=block_env,
784+
block_output=block_output,
785+
transactions=transactions,
786+
inclusion_list_transactions=inclusion_list_transactions,
787+
)
788+
772789
process_withdrawals(block_env, block_output, withdrawals)
773790

774791
process_general_purpose_requests(
@@ -1053,3 +1070,61 @@ def check_gas_limit(gas_limit: Uint, parent_gas_limit: Uint) -> bool:
10531070
return False
10541071

10551072
return True
1073+
1074+
1075+
def validate_inclusion_list_transactions(
1076+
block_env: vm.BlockEnvironment,
1077+
block_output: vm.BlockOutput,
1078+
transactions: Tuple[LegacyTransaction | Bytes, ...],
1079+
inclusion_list_transactions: Tuple[LegacyTransaction | Bytes, ...],
1080+
) -> None:
1081+
"""
1082+
Validate whether the block satisfies inclusion list constraints.
1083+
1084+
It checks if each inclusion list transaction is present in the block.
1085+
For those not included, it checks if there was sufficient gas remaining
1086+
to include the transaction and whether the transaction is valid against
1087+
the nonce and balance of the sender. If any inclusion list transaction
1088+
could have been included but was not, the block is marked as not
1089+
satisfying inclusion list constraints. Any inclusion list transaction
1090+
that is a blob transaction is ignored.
1091+
1092+
Compliance with inclusion list constraints does not affect any other
1093+
block outputs.
1094+
1095+
[EIP-7805]: https://eips.ethereum.org/EIPS/eip-7805
1096+
1097+
Parameters
1098+
----------
1099+
block_env :
1100+
Environment for the Ethereum Virtual Machine.
1101+
block_output :
1102+
The block output for the current block.
1103+
transactions :
1104+
Transactions included in the block.
1105+
inclusion_list_transactions :
1106+
Inclusion list transactions against which the block will be validated.
1107+
"""
1108+
for inclusion_list_transaction in inclusion_list_transactions:
1109+
# Skip if an inclusion list transaction is present in the block.
1110+
if inclusion_list_transaction in transactions:
1111+
continue
1112+
1113+
tx = decode_transaction(inclusion_list_transaction)
1114+
1115+
# Ignore blob transactions.
1116+
if isinstance(tx, BlobTransaction):
1117+
continue
1118+
1119+
try:
1120+
# Run the tests of intrinsic validity.
1121+
validate_transaction(tx)
1122+
check_transaction(block_env, block_output, tx)
1123+
except EthereumException:
1124+
# This inclusion list transaction could not be included.
1125+
continue
1126+
else:
1127+
# This inclusion list transaction could have been included.
1128+
# Mark the block as not satisfying inclusion list constraints.
1129+
block_output.is_inclusion_list_satisfied = False
1130+
break

src/ethereum/osaka/vm/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ class BlockOutput:
7474
Total blob gas used in the block.
7575
requests : `Bytes`
7676
Hash of all the requests in the block.
77+
is_inclusion_list_satisfied : `bool`
78+
Whether the block satisfies the inclusion list constraints.
7779
"""
7880

7981
block_gas_used: Uint = Uint(0)
@@ -90,6 +92,7 @@ class BlockOutput:
9092
)
9193
blob_gas_used: U64 = U64(0)
9294
requests: List[Bytes] = field(default_factory=list)
95+
is_inclusion_list_satisfied: bool = True
9396

9497

9598
@dataclass

src/ethereum_spec_tools/evm_tools/loaders/fork_loader.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ def process_transaction(self) -> Any:
152152
"""process_transaction function of the fork"""
153153
return self._module("fork").process_transaction
154154

155+
@property
156+
def validate_inclusion_list_transactions(self) -> Any:
157+
"""validate_inclusion_list_transactions function of the fork"""
158+
return self._module("fork").validate_inclusion_list_transactions
159+
155160
@property
156161
def MAX_BLOB_GAS_PER_BLOCK(self) -> Any:
157162
"""MAX_BLOB_GAS_PER_BLOCK parameter of the fork"""

src/ethereum_spec_tools/evm_tools/t8n/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,14 @@ def _run_blockchain_test(self, block_env: Any, block_output: Any) -> None:
255255
U256(self.options.state_reward), block_env
256256
)
257257

258+
if self.fork.is_after_fork("ethereum.osaka"):
259+
self.fork.validate_inclusion_list_transactions(
260+
block_env,
261+
block_output,
262+
self.txs.transactions,
263+
self.env.inclusion_list_transactions,
264+
)
265+
258266
if self.fork.is_after_fork("ethereum.shanghai"):
259267
self.fork.process_withdrawals(
260268
block_env, block_output, self.env.withdrawals

src/ethereum_spec_tools/evm_tools/t8n/env.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ethereum.crypto.hash import Hash32, keccak256
1313
from ethereum.utils.byte import left_pad_zero_bytes
1414
from ethereum.utils.hexadecimal import hex_to_bytes
15+
from ethereum_spec_tools.evm_tools.t8n.t8n_types import Txs
1516

1617
from ..utils import parse_hex_or_int
1718

@@ -54,6 +55,7 @@ class Env:
5455
parent_blob_gas_used: Optional[U64]
5556
excess_blob_gas: Optional[U64]
5657
requests: Any
58+
inclusion_list_transactions: Any
5759

5860
def __init__(self, t8n: "T8N", stdin: Optional[Dict] = None):
5961
if t8n.options.input_env == "stdin":
@@ -74,6 +76,7 @@ def __init__(self, t8n: "T8N", stdin: Optional[Dict] = None):
7476
self.read_block_hashes(data, t8n)
7577
self.read_ommers(data, t8n)
7678
self.read_withdrawals(data, t8n)
79+
self.read_inclusion_list_transactions(data, t8n)
7780

7881
self.parent_beacon_block_root = None
7982
if t8n.fork.is_after_fork("ethereum.cancun"):
@@ -328,3 +331,19 @@ def read_ommers(self, data: Any, t8n: "T8N") -> None:
328331
)
329332
)
330333
self.ommers = ommers
334+
335+
def read_inclusion_list_transactions(self, data: Any, t8n: "T8N") -> None:
336+
"""
337+
Read the inclusion lists.
338+
"""
339+
self.inclusion_list_transactions = None
340+
341+
if not t8n.fork.is_after_fork("ethereum.osaka"):
342+
return
343+
344+
inclusion_list_transactions = []
345+
if "inclusionLists" in data:
346+
inclusion_list_transactions = Txs(
347+
t8n, data["inclusionLists"]
348+
).all_txs
349+
self.inclusion_list_transactions = inclusion_list_transactions

src/ethereum_spec_tools/evm_tools/t8n/t8n_types.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ class Result:
268268
requests_hash: Optional[Hash32] = None
269269
requests: Optional[List[Bytes]] = None
270270
block_exception: Optional[str] = None
271+
is_inclusion_list_satisfied: Optional[bool] = None
271272

272273
def get_receipts_from_output(
273274
self,
@@ -323,6 +324,11 @@ def update(self, t8n: "T8N", block_env: Any, block_output: Any) -> None:
323324
self.requests = block_output.requests
324325
self.requests_hash = t8n.fork.compute_requests_hash(self.requests)
325326

327+
if hasattr(block_output, "is_inclusion_list_satisfied"):
328+
self.is_inclusion_list_satisfied = (
329+
block_output.is_inclusion_list_satisfied
330+
)
331+
326332
def json_encode_receipts(self) -> Any:
327333
"""
328334
Encode receipts to JSON.
@@ -390,4 +396,7 @@ def to_json(self) -> Any:
390396
if self.block_exception is not None:
391397
data["blockException"] = self.block_exception
392398

399+
if self.is_inclusion_list_satisfied is not None:
400+
data["isInclusionListSatisfied"] = self.is_inclusion_list_satisfied
401+
393402
return data

0 commit comments

Comments
 (0)