Skip to content

Commit

Permalink
feat(test): opcode diff places test
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed Sep 16, 2024
1 parent 2f2d356 commit 1761a66
Showing 1 changed file with 216 additions and 0 deletions.
216 changes: 216 additions & 0 deletions tests/frontier/opcodes/test_diff_places.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
"""
Call every possible opcode and test that the subcall is successful
if the opcode is supported by the fork supports and fails otherwise.
"""

from typing import Dict, List, Tuple

import pytest

from ethereum_test_forks import Byzantium, Fork, Frontier, Homestead
from ethereum_test_tools import (
Account,
Address,
Alloc,
Bytecode,
Environment,
StateTestFiller,
Transaction,
)
from ethereum_test_tools.vm.opcode import Opcode
from ethereum_test_tools.vm.opcode import Opcodes as Op
from ethereum_test_tools.vm.opcode import UndefinedOpcodes

REFERENCE_SPEC_GIT_PATH = "N/A"
REFERENCE_SPEC_VERSION = "N/A"


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

name: str
code: Address
fork: Fork

def __init__(self, name: str, code: Address, fork: Fork):
self.name = name
self.code = code
self.fork = fork


@pytest.fixture
def scenarios(pre: Alloc, operation: Bytecode) -> List[Scenario]:
"""Define list of contracts that execute scenarios for a given operation"""
list: List[Scenario] = []
operation_contract = pre.deploy_contract(code=operation)
max_scenario_gas = 100000

"""Scenario: Call"""
scenario_contract = pre.deploy_contract(
code=Op.CALL(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_call", code=scenario_contract, fork=Frontier))

"""Scenario: Callcode"""
scenario_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_callcode", code=scenario_contract, fork=Frontier))

"""Scenario: DelegateCall"""
scenario_contract = pre.deploy_contract(
code=Op.DELEGATECALL(max_scenario_gas, operation_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_delegatecall", code=scenario_contract, fork=Homestead))

"""Scenario: StaticCall"""
scenario_contract = pre.deploy_contract(
code=Op.STATICCALL(max_scenario_gas, operation_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_staticcall", code=scenario_contract, fork=Byzantium))

"""Scenario: Callcode a contract that CALLs"""
sub_contract = pre.deploy_contract(
code=Op.CALL(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, sub_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_callcode_call", code=scenario_contract, fork=Frontier))

"""Scenario: Delegatecall a contract that CALLs"""
sub_contract = pre.deploy_contract(
code=Op.CALL(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.DELEGATECALL(max_scenario_gas, sub_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(
Scenario(name="scenario_delegatecall_call", code=scenario_contract, fork=Homestead)
)

"""Scenario: Staticcall a contract that CALLs"""
sub_contract = pre.deploy_contract(
code=Op.CALL(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.STATICCALL(max_scenario_gas, sub_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_staticcall_call", code=scenario_contract, fork=Byzantium))

"""Scenario: Callcode a contract that CALLCODEs"""
sub_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, sub_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(Scenario(name="scenario_callcode_callcode", code=scenario_contract, fork=Frontier))

"""Scenario: Delegatecall a contract that CALLCODEs"""
sub_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.DELEGATECALL(max_scenario_gas, sub_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(
Scenario(name="scenario_delegatecall_callcode", code=scenario_contract, fork=Homestead)
)

"""Scenario: Staticcall a contract that CALLCODEs"""
sub_contract = pre.deploy_contract(
code=Op.CALLCODE(max_scenario_gas, operation_contract, 0, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
scenario_contract = pre.deploy_contract(
code=Op.STATICCALL(max_scenario_gas, sub_contract, 0, 0, 0, 32) + Op.RETURN(0, 32)
)
list.append(
Scenario(name="scenario_staticcall_callcode", code=scenario_contract, fork=Byzantium)
)
"""
// 13. 0xF1F4 CALL a contract that DELEGATECALLs a contract ...
// 14. 0xF2F4 CALLCODE a contract that DELEGATECALLs ...
// 15. 0xF4F4 DELEGATECALL ... DELEGATECALL
// 16. 0xFAF4 STATICCALL ... DELEGATECALL
// 17. 0xF1FA CALL a contract that STATICCALLs a contract ...
// 18. 0xF2FA CALLCODE a contract that STATICCALLs ...
// 19. 0xF4FA DELEGATECALL ... STATICCALL
// 20. 0xFAFA STATICCALL ... STATICCALL
// 21. 0x00FD Run the code, call a contract that reverts, then run again
// 22. 0x00FE Run the code, call a contract that goes out of gas, then run again
// 23. 0x00FF Run the code, call a contract that self-destructs, then run again
// 24. 0x00F0 CREATE a contract, run the code in the constructor
// 25. 0x00F5 CREATE2 a contract, run the code in the constructor
// 26. 0xF0F1 CREATE a contract with the code and then CALL it
// 27. 0xF5F1 CREATE2 a contract with the code and then CALL it
// 28. 0xF0F2 CREATE a contract with the code and then CALLCODE it
// 29. 0xF5F2 CREATE2 a contract with the code and then CALLCODE it
// 30. 0xF0F4 CREATE a contract with the code and then DELEGATECALL it
// 31. 0xF5F4 CREATE2 a contract with the code and then DELEGATECALL it
// 32. 0xF0FA CREATE a contract with the code and then STATICCALL it
// 33. 0xF5FA CREATE2 a contract with the code and then STATICCALL it
// 34. 0x60BACCFA57 Call recurse to the limit
"""

return list


@pytest.mark.valid_from("Frontier")
@pytest.mark.parametrize(
"operation, result",
[
pytest.param(Op.MSTORE(0, Op.ADD(1, 1)) + Op.RETURN(0, 32), 2, id="ADD_1_1"),
],
)
def test_diff_places(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
result: int,
scenarios,
):
"""
Test given operation in different scenarios
Verify that it's return value equal to expected result on every scenario,
that is valid for the given fork
"""
code_worked = 1000

runner_contract = pre.deploy_contract(
code=sum(
Op.MSTORE(0, 0)
+ Op.CALL(200000, scenario.code, 0, 0, 0, 0, 32)
+ Op.SSTORE(index, Op.MLOAD(0))
for index, (scenario) in enumerate(scenarios)
)
+ Op.SSTORE(code_worked, 1)
)
post = {
runner_contract: Account(
storage={
**{
index: result if fork >= scenario.fork else 0
for index, (scenario) in enumerate(scenarios)
},
code_worked: 1,
}
),
}

hint: Dict[int, str] = {}
for index, (scenario) in enumerate(scenarios):
hint[index] = scenario.name

tx = Transaction(
sender=pre.fund_eoa(),
gas_limit=500_000_000,
to=runner_contract,
data=b"",
value=0,
protected=False,
)

state_test(env=Environment(), pre=pre, post=post, tx=tx, post_hint=hint)

0 comments on commit 1761a66

Please sign in to comment.