Skip to content

Commit

Permalink
test opcode programs in different scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed Sep 20, 2024
1 parent 2f2d356 commit 2729f06
Show file tree
Hide file tree
Showing 10 changed files with 564 additions and 0 deletions.
116 changes: 116 additions & 0 deletions converted-ethereum-tests.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,119 @@
GeneralStateTests/stBadOpcode/opc0CDiffPlaces.json
GeneralStateTests/stBadOpcode/opc0DDiffPlaces.json
GeneralStateTests/stBadOpcode/opc0EDiffPlaces.json
GeneralStateTests/stBadOpcode/opc0FDiffPlaces.json
GeneralStateTests/stBadOpcode/opc1EDiffPlaces.json
GeneralStateTests/stBadOpcode/opc1FDiffPlaces.json
GeneralStateTests/stBadOpcode/opc2ADiffPlaces.json
GeneralStateTests/stBadOpcode/opc2BDiffPlaces.json
GeneralStateTests/stBadOpcode/opc2CDiffPlaces.json
GeneralStateTests/stBadOpcode/opc2DDiffPlaces.json
GeneralStateTests/stBadOpcode/opc2EDiffPlaces.json
GeneralStateTests/stBadOpcode/opc2FDiffPlaces.json
GeneralStateTests/stBadOpcode/opc4ADiffPlaces.json
GeneralStateTests/stBadOpcode/opc4BDiffPlaces.json
GeneralStateTests/stBadOpcode/opc4CDiffPlaces.json
GeneralStateTests/stBadOpcode/opc4DDiffPlaces.json
GeneralStateTests/stBadOpcode/opc4EDiffPlaces.json
GeneralStateTests/stBadOpcode/opc4FDiffPlaces.json
GeneralStateTests/stBadOpcode/opc5CDiffPlaces.json
GeneralStateTests/stBadOpcode/opc5DDiffPlaces.json
GeneralStateTests/stBadOpcode/opc5EDiffPlaces.json
GeneralStateTests/stBadOpcode/opc5FDiffPlaces.json
GeneralStateTests/stBadOpcode/opc21DiffPlaces.json
GeneralStateTests/stBadOpcode/opc22DiffPlaces.json
GeneralStateTests/stBadOpcode/opc23DiffPlaces.json
GeneralStateTests/stBadOpcode/opc24DiffPlaces.json
GeneralStateTests/stBadOpcode/opc25DiffPlaces.json
GeneralStateTests/stBadOpcode/opc26DiffPlaces.json
GeneralStateTests/stBadOpcode/opc27DiffPlaces.json
GeneralStateTests/stBadOpcode/opc28DiffPlaces.json
GeneralStateTests/stBadOpcode/opc29DiffPlaces.json
GeneralStateTests/stBadOpcode/opc49DiffPlaces.json
GeneralStateTests/stBadOpcode/opcA5DiffPlaces.json
GeneralStateTests/stBadOpcode/opcA6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcA7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcA8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcA9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcAADiffPlaces.json
GeneralStateTests/stBadOpcode/opcABDiffPlaces.json
GeneralStateTests/stBadOpcode/opcACDiffPlaces.json
GeneralStateTests/stBadOpcode/opcADDiffPlaces.json
GeneralStateTests/stBadOpcode/opcAEDiffPlaces.json
GeneralStateTests/stBadOpcode/opcAFDiffPlaces.json
GeneralStateTests/stBadOpcode/opcB0DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB1DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB2DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB3DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB4DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB5DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcB9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcBADiffPlaces.json
GeneralStateTests/stBadOpcode/opcBBDiffPlaces.json
GeneralStateTests/stBadOpcode/opcBCDiffPlaces.json
GeneralStateTests/stBadOpcode/opcBDDiffPlaces.json
GeneralStateTests/stBadOpcode/opcBEDiffPlaces.json
GeneralStateTests/stBadOpcode/opcBFDiffPlaces.json
GeneralStateTests/stBadOpcode/opcC0DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC1DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC2DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC3DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC4DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC5DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcC9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcCADiffPlaces.json
GeneralStateTests/stBadOpcode/opcCBDiffPlaces.json
GeneralStateTests/stBadOpcode/opcCCDiffPlaces.json
GeneralStateTests/stBadOpcode/opcCDDiffPlaces.json
GeneralStateTests/stBadOpcode/opcCEDiffPlaces.json
GeneralStateTests/stBadOpcode/opcCFDiffPlaces.json
GeneralStateTests/stBadOpcode/opcD0DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD1DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD2DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD3DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD4DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD5DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcD9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcDADiffPlaces.json
GeneralStateTests/stBadOpcode/opcDBDiffPlaces.json
GeneralStateTests/stBadOpcode/opcDCDiffPlaces.json
GeneralStateTests/stBadOpcode/opcDDDiffPlaces.json
GeneralStateTests/stBadOpcode/opcDEDiffPlaces.json
GeneralStateTests/stBadOpcode/opcDFDiffPlaces.json
GeneralStateTests/stBadOpcode/opcE0DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE1DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE2DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE3DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE4DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE5DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcE9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcEADiffPlaces.json
GeneralStateTests/stBadOpcode/opcEBDiffPlaces.json
GeneralStateTests/stBadOpcode/opcECDiffPlaces.json
GeneralStateTests/stBadOpcode/opcEDDiffPlaces.json
GeneralStateTests/stBadOpcode/opcEEDiffPlaces.json
GeneralStateTests/stBadOpcode/opcEFDiffPlaces.json
GeneralStateTests/stBadOpcode/opcF6DiffPlaces.json
GeneralStateTests/stBadOpcode/opcF7DiffPlaces.json
GeneralStateTests/stBadOpcode/opcF8DiffPlaces.json
GeneralStateTests/stBadOpcode/opcF9DiffPlaces.json
GeneralStateTests/stBadOpcode/opcFBDiffPlaces.json
GeneralStateTests/stBadOpcode/opcFCDiffPlaces.json
GeneralStateTests/stBadOpcode/opcFEDiffPlaces.json


([#748](https://github.com/ethereum/execution-spec-tests/pull/748))
GeneralStateTests/stBadOpcode/badOpcodes.json
GeneralStateTests/stBugs/evmBytecode.json
Expand Down
3 changes: 3 additions & 0 deletions tests/frontier/scenarios/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Scenarios common import
"""
37 changes: 37 additions & 0 deletions tests/frontier/scenarios/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Define Scenario class for test_scenarios test
"""
from typing import Optional

from ethereum_test_forks import Byzantium, Constantinople, Fork, Frontier, Homestead
from ethereum_test_tools import Address
from ethereum_test_tools.vm.opcode import Opcode
from ethereum_test_tools.vm.opcode import Opcodes as Op


class Scenario:
"""
Describe test scenario that will be run in test and it's conditions
"""

name: str
code: Address
fork: Fork
not_reverting: bool

def __init__(self, name: str, code: Address, fork: Fork, reverts: bool = False):
self.name = name
self.code = code
self.fork = fork
self.not_reverting = not reverts


def get_valid_fork_for_call(call: Opcode, second_call: Optional[Opcode] = Op.CALL) -> Fork:
"""Return fork for which this call will be valid"""
if call == Op.CREATE2 or second_call == Op.CREATE2:
return Constantinople
if call == Op.STATICCALL or second_call == Op.STATICCALL:
return Byzantium
if call == Op.DELEGATECALL or second_call == Op.DELEGATECALL:
return Homestead
return Frontier
3 changes: 3 additions & 0 deletions tests/frontier/scenarios/programs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Scenarios common import
"""
81 changes: 81 additions & 0 deletions tests/frontier/scenarios/programs/all_frontier_opcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""
Define a program for scenario test that executes all frontier opcodes and entangles it's result
"""
import pytest

from ethereum_test_tools import Bytecode
from ethereum_test_tools.vm.opcode import Opcodes as Op


def make_all_opcode_program() -> Bytecode:
"""Make a program that call each Frontier opcode and tangles it's results"""
code: Bytecode = (
Op.MSTORE(0, Op.ADD(1, 1)) # 2
+ Op.MSTORE(0, Op.MUL(3, Op.MLOAD(0))) # 6
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), 1)) # 5
+ Op.MSTORE(0, Op.DIV(Op.MLOAD(0), 2)) # 2
+ Op.MSTORE(0, Op.SDIV(Op.MLOAD(0), 2)) # 1
+ Op.MSTORE(0, Op.ADD(Op.MLOAD(0), 19)) # 20
+ Op.MSTORE(0, Op.SMOD(Op.MLOAD(0), 3)) # 2
+ Op.MSTORE(0, Op.ADDMOD(Op.MLOAD(0), 3, 2)) # 1
+ Op.MSTORE(0, Op.MULMOD(Op.MLOAD(0), 10, 2)) # 0
+ Op.MSTORE(0, Op.ADD(Op.MLOAD(0), 3)) # 3
+ Op.MSTORE(0, Op.EXP(Op.MLOAD(0), 2)) # 9
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), 9)) # 0
+ Op.MSTORE(0, Op.SIGNEXTEND(Op.MLOAD(0), 0xFF)) # MAX
+ Op.MSTORE(0, Op.LT(11, Op.MLOAD(0))) # 1
+ Op.MSTORE(0, Op.GT(0, Op.MLOAD(0))) # 0
+ Op.MSTORE(0, Op.SLT(Op.SUB(0, 1), Op.MLOAD(0))) # 1
+ Op.MSTORE(0, Op.SGT(Op.MLOAD(0), Op.SUB(0, 1))) # 1
+ Op.MSTORE(0, Op.EQ(Op.MLOAD(0), 0)) # 0
+ Op.MSTORE(0, Op.ISZERO(Op.MLOAD(0))) # 1
+ Op.MSTORE(0, Op.AND(Op.MLOAD(0), 1)) # 1
+ Op.MSTORE(0, Op.OR(Op.MLOAD(0), 0)) # 1
+ Op.MSTORE(0, Op.XOR(Op.MLOAD(0), 2)) # 3
+ Op.MSTORE(0, Op.NOT(Op.MLOAD(0))) # 0xFFF....FFC
+ Op.MSTORE(0, Op.BYTE(31, Op.MLOAD(0))) # 0xFC
+ Op.MSTORE(0, Op.SHA3(0, 32)) # 0x371f36870d18f32a11fea0f144b021c8b407bb50f8e...
+ Op.MSTORE(0, Op.DIV(Op.MLOAD(0), Op.ADD(Op.CALLVALUE, 1))) # same
+ Op.MSTORE(0, Op.DIV(Op.MLOAD(0), Op.GASPRICE)) # 0x5831f0d814f4b8434ffdce4ed44...
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH1(1)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH2(0x0FFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH3(0x0FFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH4(0x0FFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH5(0x0FFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH6(0x0FFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH7(0x0FFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH8(0x0FFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH9(0x0FFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH10(0x0FFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH11(0x0FFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH12(0x0FFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH13(0x0FFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH14(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH15(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH16(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH17(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH18(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH19(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH20(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH21(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH22(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH23(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH24(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH25(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH26(0x0FFFFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH27(0x0FFFFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH28(0x0FFFFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH29(0x0FFFFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH30(0x0FFFFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH31(0x0FFFFFFFFFFFFFFFFF)))
+ Op.MSTORE(0, Op.SUB(Op.MLOAD(0), Op.PUSH32(0x0FFFFFFFFFFFFFFF)))
+ Op.RETURN(0, 32)
)
return code


program_all_frontier_opcodes = pytest.param(
make_all_opcode_program(),
0x5831F0D814F4B8434FFDCE4DD24B00D8B7A3F67F8C316EC51A4D9EEC535AD4A,
id="program_ALL_FRONTIER_OPCODES",
)
3 changes: 3 additions & 0 deletions tests/frontier/scenarios/scenarios/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Scenarios common import
"""
63 changes: 63 additions & 0 deletions tests/frontier/scenarios/scenarios/call_combinations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Define Scenario that will put a given program in all call contexts
"""
from typing import List

from ethereum_test_tools import Address, Alloc
from ethereum_test_tools.vm.opcode import Opcode
from ethereum_test_tools.vm.opcode import Opcodes as Op

from ..common import Scenario, get_valid_fork_for_call


def scenarios_call_combinations(pre: Alloc, operation_contract: Address) -> List[Scenario]:
"""
Generate Scenarios for call combinations
This is the actual test case. We take code that we want to test at operation_contract
and put it in the context of call combinations.
Example: scenario_contract -> [callcode -> delegatecall]* -> code
We assume that code always returns it's result
That we pass as return value in scenario_contract for the post state verification
"""
list: List[Scenario] = []
max_scenario_gas = 500000
first_calls: List[Opcode] = [Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL]
second_calls: List[Opcode] = [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL, Op.NOOP]

for first_call in first_calls:
for second_call in second_calls:
if second_call == Op.NOOP:
"""Only one call"""
scenario_contract = pre.deploy_contract(
code=first_call(gas=max_scenario_gas, address=operation_contract, ret_size=32)
+ Op.RETURN(0, 32)
)
list.append(
Scenario(
name=f"scenario_{first_call}",
code=scenario_contract,
fork=get_valid_fork_for_call(first_call),
)
)
else:
"""Call combination"""
sub_contract = pre.deploy_contract(
code=second_call(
gas=Op.SUB(Op.GAS, 100000), address=operation_contract, ret_size=32
)
+ Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=first_call(gas=Op.SUB(Op.GAS, 100000), address=sub_contract, ret_size=32)
+ Op.RETURN(0, 32)
)
list.append(
Scenario(
name=f"scenario_{first_call}_{second_call}",
code=scenario_contract,
fork=get_valid_fork_for_call(first_call, second_call),
)
)

return list
65 changes: 65 additions & 0 deletions tests/frontier/scenarios/scenarios/create_combinations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
Define Scenario that will put a given program in create contexts
"""
from typing import List

from ethereum_test_forks import Constantinople, Frontier
from ethereum_test_tools import Address, Alloc, Bytecode
from ethereum_test_tools.vm.opcode import Macros as Om
from ethereum_test_tools.vm.opcode import Opcode
from ethereum_test_tools.vm.opcode import Opcodes as Op

from ..common import Scenario, get_valid_fork_for_call


def scenarios_create_combinations(pre: Alloc, operation_contract: Address) -> List[Scenario]:
"""Generate Scenarios for create combinations"""
list: List[Scenario] = []
max_scenario_gas = 100000
create_types: List[Opcode] = [Op.CREATE, Op.CREATE2]

# run code in create constructor
for create in create_types:
salt = [0] if create == Op.CREATE2 else []

# the code result in init code will be actually code of a deployed contract
scenario_contract = pre.deploy_contract(
code=Op.EXTCODECOPY(operation_contract, 0, 0, Op.EXTCODESIZE(operation_contract))
+ Op.MSTORE(0, create(0, 0, Op.EXTCODESIZE(operation_contract), *salt))
+ Op.EXTCODECOPY(Op.MLOAD(0), 0, 0, 32)
+ Op.RETURN(0, 32)
)
list.append(
Scenario(
name=f"scenario_{create}_constructor",
code=scenario_contract,
fork=Frontier if create == Op.CREATE else Constantinople,
)
)

# create a contract with test code and call it
deploy_code = Bytecode(
Op.EXTCODECOPY(operation_contract, 0, 0, Op.EXTCODESIZE(operation_contract))
+ Op.RETURN(0, Op.EXTCODESIZE(operation_contract))
)
deploy_code_size: int = int(len(deploy_code.hex()) / 2)
call_types: List[Opcode] = [Op.CALL, Op.CALLCODE, Op.DELEGATECALL, Op.STATICCALL]

for create in create_types:
for call in call_types:
salt = [0] if create == Op.CREATE2 else []
scenario_contract = pre.deploy_contract(
code=Om.MSTORE(deploy_code, 0)
+ Op.MSTORE(0, create(0, 0, deploy_code_size, *salt))
+ call(gas=max_scenario_gas, address=Op.MLOAD(0), ret_size=32)
+ Op.RETURN(0, 32)
)
list.append(
Scenario(
name=f"scenario_{create}_then_{call}",
code=scenario_contract,
fork=get_valid_fork_for_call(call, create),
)
)

return list
Loading

0 comments on commit 2729f06

Please sign in to comment.