Skip to content

Commit e203df7

Browse files
feat(tests): add codecopy and extcodecopy for clz opcode (#1858)
* feat(tests): add codecopy and extcodecopy for clz opcode * fix: resolve rebase issue * refactor: combine codecopy operation test * feat(tests): load memory for clz opcode parameter * fix(tests): correct clz result storage in opcode tests * fix(tests): add prestate storage for CLZ opcode tests
1 parent dac366d commit e203df7

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

tests/osaka/eip7939_count_leading_zeros/spec.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ReferenceSpec:
1818
class Spec:
1919
"""Constants and helpers for the CLZ opcode."""
2020

21+
CLZ = 0x1E
2122
CLZ_GAS_COST = 5
2223

2324
@classmethod

tests/osaka/eip7939_count_leading_zeros/test_count_leading_zeros.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77

8+
from ethereum_test_base_types import Storage
89
from ethereum_test_forks import Fork
910
from ethereum_test_tools import (
1011
Account,
@@ -310,3 +311,101 @@ def test_clz_jump_operation(
310311
post[callee_address] = Account(storage={"0x00": expected_clz})
311312

312313
state_test(pre=pre, post=post, tx=tx)
314+
315+
316+
@pytest.mark.valid_from("Osaka")
317+
@pytest.mark.parametrize("bits", [0, 64, 255])
318+
@pytest.mark.parametrize("opcode", [Op.CODECOPY, Op.EXTCODECOPY])
319+
def test_clz_code_copy_operation(state_test: StateTestFiller, pre: Alloc, bits: int, opcode: Op):
320+
"""Test CLZ opcode with code copy operation."""
321+
storage = Storage()
322+
323+
expected_value = 255 - bits
324+
clz_code_offset = len(Op.CLZ(1 << bits)) - 1 # Offset to CLZ opcode
325+
326+
mload_value = Spec.CLZ << 248 # CLZ opcode in MSB position (0x1E000...000)
327+
328+
target_address = pre.deploy_contract(code=Op.CLZ(1 << bits))
329+
330+
clz_contract_address = pre.deploy_contract(
331+
code=(
332+
Op.CLZ(1 << bits) # Calculate CLZ of the value
333+
+ Op.SSTORE(storage.store_next(expected_value), Op.CLZ(1 << bits)) # Store CLZ result
334+
+ ( # Load CLZ byte from code with CODECOPY or EXTCODECOPY
335+
Op.CODECOPY(dest_offset=0, offset=clz_code_offset, size=1)
336+
if opcode == Op.CODECOPY
337+
else Op.EXTCODECOPY(
338+
address=target_address, dest_offset=0, offset=clz_code_offset, size=1
339+
)
340+
)
341+
+ Op.SSTORE(storage.store_next(mload_value), Op.MLOAD(0)) # Store loaded CLZ byte
342+
),
343+
storage={"0x00": "0xdeadbeef"},
344+
)
345+
346+
post = {
347+
clz_contract_address: Account(
348+
storage={
349+
"0x00": expected_value,
350+
"0x01": mload_value,
351+
}
352+
)
353+
}
354+
tx = Transaction(
355+
to=clz_contract_address,
356+
sender=pre.fund_eoa(),
357+
gas_limit=200_000,
358+
)
359+
360+
state_test(pre=pre, post=post, tx=tx)
361+
362+
363+
@pytest.mark.valid_from("Osaka")
364+
@pytest.mark.parametrize("bits", [0, 64, 255])
365+
@pytest.mark.parametrize("opcode", [Op.CODECOPY, Op.EXTCODECOPY])
366+
def test_clz_with_memory_operation(state_test: StateTestFiller, pre: Alloc, bits: int, opcode: Op):
367+
"""Test CLZ opcode with memory operation."""
368+
storage = Storage()
369+
370+
expected_value = 255 - bits
371+
372+
# Target code pattern:
373+
# PUSH32 (1 << bits)
374+
# PUSH0
375+
# MSTORE
376+
#
377+
# This sequence stores a 32-byte value in memory.
378+
# Later, we copy the immediate value from the PUSH32 instruction into memory
379+
# using CODECOPY or EXTCODECOPY, and then load it with MLOAD for the CLZ test.
380+
target_code = Op.PUSH32(1 << bits)
381+
offset = 1
382+
383+
target_address = pre.deploy_contract(code=target_code)
384+
385+
clz_contract_address = pre.deploy_contract(
386+
code=(
387+
target_code
388+
+ Op.SSTORE(storage.store_next(expected_value), Op.CLZ(1 << bits)) # Store CLZ result
389+
+ (
390+
Op.CODECOPY(dest_offset=0, offset=offset, size=0x20)
391+
if opcode == Op.CODECOPY
392+
else Op.EXTCODECOPY(
393+
address=target_address, dest_offset=0, offset=offset, size=0x20
394+
)
395+
)
396+
+ Op.SSTORE(storage.store_next(expected_value), Op.CLZ(Op.MLOAD(0)))
397+
),
398+
storage={"0x00": "0xdeadbeef"},
399+
)
400+
401+
post = {
402+
clz_contract_address: Account(storage={"0x00": expected_value, "0x01": expected_value}),
403+
}
404+
405+
tx = Transaction(
406+
to=clz_contract_address,
407+
sender=pre.fund_eoa(),
408+
gas_limit=200_000,
409+
)
410+
411+
state_test(pre=pre, post=post, tx=tx)

0 commit comments

Comments
 (0)