Skip to content

Commit 85ac1ff

Browse files
committed
macro MSTORE now used instead of manually splitting into chunks
1 parent c1e9fc9 commit 85ac1ff

File tree

1 file changed

+38
-90
lines changed

1 file changed

+38
-90
lines changed

tests/prague/eip7002_el_triggerable_withdrawals/test_modified_withdrawal_contract.py

Lines changed: 38 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Bytecode,
1717
Transaction,
1818
)
19+
from ethereum_test_tools import Macros as Om
1920
from ethereum_test_tools import Opcodes as Op
2021
from ethereum_test_types import Requests
2122

@@ -32,12 +33,15 @@
3233
REFERENCE_SPEC_VERSION: str = ref_spec_7002.version
3334

3435

35-
def single_withdrawal_with_custom_fee(i: int) -> WithdrawalRequest: # noqa: D103
36-
return WithdrawalRequest(
37-
validator_pubkey=i + 1,
38-
amount=0,
39-
fee=Spec_EIP7002.get_fee(0),
40-
)
36+
def withdrawal_list_with_custom_fee(n: int) -> List[WithdrawalRequest]: # noqa: D103
37+
return [
38+
WithdrawalRequest(
39+
validator_pubkey=i + 1,
40+
amount=0,
41+
fee=Spec_EIP7002.get_fee(0),
42+
)
43+
for i in range(n)
44+
]
4145

4246

4347
@pytest.mark.parametrize(
@@ -48,54 +52,32 @@ def single_withdrawal_with_custom_fee(i: int) -> WithdrawalRequest: # noqa: D10
4852
id="empty_request_list",
4953
),
5054
pytest.param(
51-
[single_withdrawal_with_custom_fee(0)],
55+
[
56+
*withdrawal_list_with_custom_fee(1),
57+
],
5258
id="1_withdrawal_request",
5359
),
5460
pytest.param(
5561
[
56-
*[
57-
single_withdrawal_with_custom_fee(i)
58-
for i in range(
59-
0,
60-
15,
61-
)
62-
],
62+
*withdrawal_list_with_custom_fee(15),
6363
],
6464
id="15_withdrawal_requests",
6565
),
6666
pytest.param(
6767
[
68-
*[
69-
single_withdrawal_with_custom_fee(i)
70-
for i in range(
71-
0,
72-
16,
73-
)
74-
],
68+
*withdrawal_list_with_custom_fee(16),
7569
],
7670
id="16_withdrawal_requests",
7771
),
7872
pytest.param(
7973
[
80-
*[
81-
single_withdrawal_with_custom_fee(i)
82-
for i in range(
83-
0,
84-
17,
85-
)
86-
],
74+
*withdrawal_list_with_custom_fee(17),
8775
],
8876
id="17_withdrawal_requests",
8977
),
9078
pytest.param(
9179
[
92-
*[
93-
single_withdrawal_with_custom_fee(i)
94-
for i in range(
95-
0,
96-
18,
97-
)
98-
],
80+
*withdrawal_list_with_custom_fee(18),
9981
],
10082
id="18_withdrawal_requests",
10183
),
@@ -106,7 +88,8 @@ def test_extra_withdrawals(
10688
pre: Alloc,
10789
requests_list: List[WithdrawalRequest],
10890
):
109-
"""Test how clients were to behave when more than 16 withdrawals would be allowed per block."""
91+
"""Test how clients were to behave when more than 16 withdrawals (here: 18 withdrawals) would be allowed per block.""" # noqa: E501
92+
# 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
11093
modified_code: bytes = b"3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060121160df575060125b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd" # noqa: E501
11194
pre[Spec_EIP7002.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS] = Account(
11295
code=modified_code,
@@ -141,54 +124,32 @@ def test_extra_withdrawals(
141124
id="empty_request_list",
142125
),
143126
pytest.param(
144-
[single_withdrawal_with_custom_fee(0)],
127+
[
128+
*withdrawal_list_with_custom_fee(1),
129+
],
145130
id="1_withdrawal_request",
146131
),
147132
pytest.param(
148133
[
149-
*[
150-
single_withdrawal_with_custom_fee(i)
151-
for i in range(
152-
0,
153-
15,
154-
)
155-
],
134+
*withdrawal_list_with_custom_fee(15),
156135
],
157136
id="15_withdrawal_requests",
158137
),
159138
pytest.param(
160139
[
161-
*[
162-
single_withdrawal_with_custom_fee(i)
163-
for i in range(
164-
0,
165-
16,
166-
)
167-
],
140+
*withdrawal_list_with_custom_fee(16),
168141
],
169142
id="16_withdrawal_requests",
170143
),
171144
pytest.param(
172145
[
173-
*[
174-
single_withdrawal_with_custom_fee(i)
175-
for i in range(
176-
0,
177-
17,
178-
)
179-
],
146+
*withdrawal_list_with_custom_fee(17),
180147
],
181148
id="17_withdrawal_requests",
182149
),
183150
pytest.param(
184151
[
185-
*[
186-
single_withdrawal_with_custom_fee(i)
187-
for i in range(
188-
0,
189-
18,
190-
)
191-
],
152+
*withdrawal_list_with_custom_fee(18),
192153
],
193154
id="18_withdrawal_requests",
194155
),
@@ -204,37 +165,24 @@ def test_extra_withdrawals_pseudo_contract(
204165
memory_offset: int = 0
205166
amount_of_requests: int = 0
206167

207-
# Goal: Have contract return a bunch of withdrawal requests
208-
# Problem: EVM has no concept of withdrawal request, it just return bytes from memory
209-
# Problem: How to get __bytes__ from withdrawal request
210-
# Problem: How to know exact size of withdrawal requests byte representation
211-
# Problem: If size larger than 32 bytes how to split across multiple MSTOREs?
212168

213-
# what size does a withdrawal_request bytes representation have?
214-
# withdrawal_request.__bytes__:
215-
# bytes(self.source_address) -> 20 bytes
216-
# + bytes(self.validator_pubkey) -> 48 bytes
217-
# + self.amount.to_bytes(8, "little") -> 8 bytes
218-
# -> Total: 76 bytes
219169
for withdrawal_request in requests_list:
220-
withdrawal_request_chunk_1_3_32bytes: bytes = withdrawal_request.__bytes__()[:32]
221-
withdrawal_request_chunk_2_3_32bytes: bytes = withdrawal_request.__bytes__()[32:64]
222-
withdrawal_request_chunk_3_3_12bytes: bytes = withdrawal_request.__bytes__()[64:]
223-
224-
modified_code += Op.MSTORE(memory_offset, withdrawal_request_chunk_1_3_32bytes)
225-
memory_offset += 32
226-
227-
modified_code += Op.MSTORE(memory_offset, withdrawal_request_chunk_2_3_32bytes)
228-
memory_offset += 32
229-
230-
modified_code += Op.MSTORE(memory_offset, withdrawal_request_chunk_3_3_12bytes)
231-
# memory_offset += 32 # MSTORE ALWAYS writes 32 bytes, no need to update memory offset tho
232-
170+
# update memory_offset with the correct value
171+
withdrawal_request_bytes_amount: int = len(bytes(withdrawal_request))
172+
assert withdrawal_request_bytes_amount == 76, f"Expected withdrawal request to be of size 76 but got size {withdrawal_request_bytes_amount}" # noqa: E501
173+
memory_offset += withdrawal_request_bytes_amount
174+
175+
# TODO: in opcodes.py the argument order and names of arguments are different from those
176+
# on evm.codes website. this is dangerous, especially since with the macro I am not allowed
177+
# to provide the parameters as named parameters like
178+
# Om.MSTORE(data=bytes(withdrawal_request), offset=memory_offset)
179+
# due to 'unexpected keyword argument.. for __call__ of'
180+
modified_code += Om.MSTORE(bytes(withdrawal_request), memory_offset)
233181
amount_of_requests += 1
234182

235183
modified_code += Op.RETURN(
236184
0, 76 * amount_of_requests
237-
) # don't care about the zeroes added by MSTORE at [76,96] bytes
185+
)
238186

239187
pre[Spec_EIP7002.WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS] = Account(
240188
code=modified_code,

0 commit comments

Comments
 (0)