Skip to content

Commit 0fc6bd8

Browse files
new(tests): EIP-7685: add more test cases for request types (#1340)
* new(tests): added more cases (two contract req, one EOA req) in test_valid_deposit_withdrawal_consolidation_requests * fixed comments * rename test_deposits_withdrawals_consolidations.py to test_multi_type_requests.py * changed type from ParameterSet to a union of the three request types, added mypy silencer for type warning * added draft test of trying out a modified withdrawal contract that allows 18 withdrawals per block * fixed docstrings * tried to implement marios feedback * moved test to a better suited folder (eip7002) * parameterized test and bugfixes * added pseudo contract that just returns withdrawals requests * removed unnecessary offset update * macro MSTORE now used instead of manually splitting into chunks * Update tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py * Datatype is ParameterSet Co-authored-by: Mario Vega <[email protected]> * added pytest marker for prague, and some minor fixes * removed comment and updated CHANGELOG.md --------- Co-authored-by: Mario Vega <[email protected]>
1 parent 801c0ff commit 0fc6bd8

File tree

4 files changed

+355
-43
lines changed

4 files changed

+355
-43
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ The following changes may be potentially breaking (all clients were tested with
101101
- ✨ Add gas cost of delegation access in CALL opcode ([#1208](https://github.com/ethereum/execution-spec-tests/pull/1208)).
102102
- ✨ Add EIP-7698 failed nonce and short data tests ([#1211](https://github.com/ethereum/execution-spec-tests/pull/1211)).
103103
- ✨ Add EIP-2537 additional pairing precompile tests cases, and then update all BLS12 test vectors ([#1275](https://github.com/ethereum/execution-spec-tests/pull/1275), [#1289](https://github.com/ethereum/execution-spec-tests/pull/1289)).
104+
- ✨ Add EIP-7685 and EIP-7002 test cases for additional request type combinations and modified withdrawal contract that allows more withdrawals ([#1340](https://github.com/ethereum/execution-spec-tests/pull/1340)).
104105

105106
## [v4.0.0](https://github.com/ethereum/execution-spec-tests/releases/tag/v4.0.0) - 2025-02-14 - 💕
106107

tests/prague/eip7002_el_triggerable_withdrawals/helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def valid_requests(self, current_minimum_fee: int) -> List[WithdrawalRequest]:
121121

122122
@dataclass(kw_only=True)
123123
class WithdrawalRequestContract(WithdrawalRequestInteractionBase):
124-
"""Class used to describe a deposit originated from a contract."""
124+
"""Class used to describe a withdrawal originated from a contract."""
125125

126126
tx_gas_limit: int = 1_000_000
127127
"""
@@ -176,7 +176,7 @@ def contract_code(self) -> Bytecode:
176176
return code + self.extra_code
177177

178178
def transactions(self) -> List[Transaction]:
179-
"""Return a transaction for the deposit request."""
179+
"""Return a transaction for the withdrawal request."""
180180
assert self.entry_address is not None, "Entry address not initialized"
181181
return [
182182
Transaction(
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
"""
2+
abstract: Tests [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002)
3+
Test execution layer triggered exits [EIP-7002: Execution layer triggerable withdrawals](https://eips.ethereum.org/EIPS/eip-7002).
4+
5+
""" # noqa: E501
6+
7+
from typing import List
8+
9+
import pytest
10+
11+
from ethereum_test_tools import (
12+
Account,
13+
Alloc,
14+
Block,
15+
BlockchainTestFiller,
16+
Bytecode,
17+
Transaction,
18+
)
19+
from ethereum_test_tools import Macros as Om
20+
from ethereum_test_tools import Opcodes as Op
21+
from ethereum_test_types import Requests
22+
23+
from .helpers import (
24+
WithdrawalRequest,
25+
# WithdrawalRequestBase,
26+
# WithdrawalRequestContract,
27+
WithdrawalRequestTransaction,
28+
)
29+
from .spec import Spec as Spec_EIP7002
30+
from .spec import ref_spec_7002
31+
32+
REFERENCE_SPEC_GIT_PATH: str = ref_spec_7002.git_path
33+
REFERENCE_SPEC_VERSION: str = ref_spec_7002.version
34+
35+
pytestmark: pytest.MarkDecorator = pytest.mark.valid_from("Prague")
36+
37+
38+
def withdrawal_list_with_custom_fee(n: int) -> List[WithdrawalRequest]: # noqa: D103
39+
return [
40+
WithdrawalRequest(
41+
validator_pubkey=i + 1,
42+
amount=0,
43+
fee=Spec_EIP7002.get_fee(0),
44+
)
45+
for i in range(n)
46+
]
47+
48+
49+
@pytest.mark.parametrize(
50+
"requests_list",
51+
[
52+
pytest.param(
53+
[],
54+
id="empty_request_list",
55+
),
56+
pytest.param(
57+
[
58+
*withdrawal_list_with_custom_fee(1),
59+
],
60+
id="1_withdrawal_request",
61+
),
62+
pytest.param(
63+
[
64+
*withdrawal_list_with_custom_fee(15),
65+
],
66+
id="15_withdrawal_requests",
67+
),
68+
pytest.param(
69+
[
70+
*withdrawal_list_with_custom_fee(16),
71+
],
72+
id="16_withdrawal_requests",
73+
),
74+
pytest.param(
75+
[
76+
*withdrawal_list_with_custom_fee(17),
77+
],
78+
id="17_withdrawal_requests",
79+
),
80+
pytest.param(
81+
[
82+
*withdrawal_list_with_custom_fee(18),
83+
],
84+
id="18_withdrawal_requests",
85+
),
86+
],
87+
)
88+
def test_extra_withdrawals(
89+
blockchain_test: BlockchainTestFiller,
90+
pre: Alloc,
91+
requests_list: List[WithdrawalRequest],
92+
):
93+
"""Test how clients were to behave when more than 16 withdrawals (here: 18 withdrawals) would be allowed per block.""" # noqa: E501
94+
# Source of code (change value of this line to 18 and re-compile with fjl/geas): https://github.com/lightclient/sys-asm/blob/f1c13e285b6aeef2b19793995e00861bf0f32c9a/src/withdrawals/main.eas#L37 # noqa: E501, W291
95+
modified_code: bytes = b"3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060121160df575060125b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd" # noqa: E501
96+
pre[Spec_EIP7002.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS] = Account(
97+
code=modified_code,
98+
nonce=1,
99+
balance=0,
100+
)
101+
102+
# given a list of withdrawal requests construct a withdrawal request transaction
103+
withdrawal_request_transaction = WithdrawalRequestTransaction(requests=requests_list)
104+
# prepare withdrawal senders
105+
withdrawal_request_transaction.update_pre(pre=pre)
106+
# get transaction list
107+
txs: List[Transaction] = withdrawal_request_transaction.transactions()
108+
109+
blockchain_test(
110+
pre=pre,
111+
blocks=[
112+
Block(
113+
txs=txs,
114+
requests_hash=Requests(*requests_list),
115+
),
116+
],
117+
post={},
118+
)
119+
120+
121+
@pytest.mark.parametrize(
122+
"requests_list",
123+
[
124+
pytest.param(
125+
[],
126+
id="empty_request_list",
127+
),
128+
pytest.param(
129+
[
130+
*withdrawal_list_with_custom_fee(1),
131+
],
132+
id="1_withdrawal_request",
133+
),
134+
pytest.param(
135+
[
136+
*withdrawal_list_with_custom_fee(15),
137+
],
138+
id="15_withdrawal_requests",
139+
),
140+
pytest.param(
141+
[
142+
*withdrawal_list_with_custom_fee(16),
143+
],
144+
id="16_withdrawal_requests",
145+
),
146+
pytest.param(
147+
[
148+
*withdrawal_list_with_custom_fee(17),
149+
],
150+
id="17_withdrawal_requests",
151+
),
152+
pytest.param(
153+
[
154+
*withdrawal_list_with_custom_fee(18),
155+
],
156+
id="18_withdrawal_requests",
157+
),
158+
],
159+
)
160+
def test_extra_withdrawals_pseudo_contract(
161+
blockchain_test: BlockchainTestFiller,
162+
pre: Alloc,
163+
requests_list: List[WithdrawalRequest],
164+
):
165+
"""Test how clients were to behave when more than 16 withdrawals would be allowed per block."""
166+
modified_code: Bytecode = Bytecode()
167+
memory_offset: int = 0
168+
amount_of_requests: int = 0
169+
170+
for withdrawal_request in requests_list:
171+
# update memory_offset with the correct value
172+
withdrawal_request_bytes_amount: int = len(bytes(withdrawal_request))
173+
assert withdrawal_request_bytes_amount == 76, (
174+
"Expected withdrawal request to be of size 76 but got size "
175+
f"{withdrawal_request_bytes_amount}"
176+
)
177+
memory_offset += withdrawal_request_bytes_amount
178+
179+
modified_code += Om.MSTORE(bytes(withdrawal_request), memory_offset)
180+
amount_of_requests += 1
181+
182+
modified_code += Op.RETURN(0, Op.MSIZE())
183+
184+
pre[Spec_EIP7002.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS] = Account(
185+
code=modified_code,
186+
nonce=1,
187+
balance=0,
188+
)
189+
190+
# given a list of withdrawal requests construct a withdrawal request transaction
191+
withdrawal_request_transaction = WithdrawalRequestTransaction(requests=requests_list)
192+
# prepare withdrawal senders
193+
withdrawal_request_transaction.update_pre(pre=pre)
194+
# get transaction list
195+
txs: List[Transaction] = withdrawal_request_transaction.transactions()
196+
197+
blockchain_test(
198+
pre=pre,
199+
blocks=[
200+
Block(
201+
txs=txs,
202+
requests_hash=Requests(*requests_list),
203+
),
204+
],
205+
post={},
206+
)

0 commit comments

Comments
 (0)