Skip to content

Commit

Permalink
test all opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed Aug 21, 2024
1 parent 4b51585 commit 544568b
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
5 changes: 5 additions & 0 deletions converted-ethereum-tests.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
([#748](https://github.com/ethereum/execution-spec-tests/pull/748))
GeneralStateTests/stBadOpcode/undefinedOpcodeFirstByte.json
GeneralStateTests/stBadOpcode/badOpcodes.json
GeneralStateTests/stBugs/evmBytecode.json

([#497](https://github.com/ethereum/execution-spec-tests/pull/497))
GeneralStateTests/stCreate2/call_outsize_then_create2_successful_then_returndatasize.json
GeneralStateTests/stCreate2/call_then_create2_successful_then_returndatasize.json
Expand Down
205 changes: 205 additions & 0 deletions tests/frontier/opcodes/test_all_opcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
"""
Call every possible opcode to see if it is recognized by the evm
If opcode is undefined the subcall will fail
"""

from typing import Dict, List

import pytest

from ethereum_test_forks import (
Berlin,
Byzantium,
Cancun,
Constantinople,
ConstantinopleFix,
Fork,
Frontier,
Homestead,
Istanbul,
London,
Paris,
Shanghai,
)
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"
all_opcodes = set(Op)
undefined_opcodes = set(UndefinedOpcodes)

opcodes_by_fork: Dict[Fork, List[Opcode]] = {}
opcodes_by_fork[Frontier] = [
Op.STOP,
Op.ADD,
Op.MUL,
Op.SUB,
Op.DIV,
Op.SDIV,
Op.MOD,
Op.SMOD,
Op.ADDMOD,
Op.MULMOD,
Op.EXP,
Op.SIGNEXTEND,
Op.LT,
Op.GT,
Op.SLT,
Op.SGT,
Op.EQ,
Op.ISZERO,
Op.AND,
Op.OR,
Op.XOR,
Op.NOT,
Op.BYTE,
Op.SHA3,
Op.ADDRESS,
Op.BALANCE,
Op.ORIGIN,
Op.CALLER,
Op.CALLVALUE,
Op.CALLDATALOAD,
Op.CALLDATASIZE,
Op.CALLDATACOPY,
Op.CODESIZE,
Op.CODECOPY,
Op.GASPRICE,
Op.EXTCODESIZE,
Op.EXTCODECOPY,
Op.BLOCKHASH,
Op.COINBASE,
Op.TIMESTAMP,
Op.NUMBER,
Op.PREVRANDAO,
Op.GASLIMIT,
Op.POP,
Op.MLOAD,
Op.MSTORE,
Op.MSTORE8,
Op.SLOAD,
Op.SSTORE,
Op.PC,
Op.MSIZE,
Op.GAS,
Op.JUMPDEST,
*[Opcode(code) for code in range(0x60, 0x80)], # PUSH1-32
*[Opcode(code) for code in range(0x80, 0x90)], # DUP1-16
*[Opcode(code) for code in range(0x90, 0xA0)], # SWAP1-16
Op.LOG0,
Op.LOG1,
Op.LOG2,
Op.LOG3,
Op.LOG4,
Op.CREATE,
Op.CALL,
Op.CALLCODE,
Op.RETURN,
Op.SELFDESTRUCT,
]
opcodes_by_fork[Homestead] = opcodes_by_fork[Frontier] + [Op.DELEGATECALL]
opcodes_by_fork[Byzantium] = opcodes_by_fork[Homestead] + [Op.RETURNDATASIZE, Op.STATICCALL]
opcodes_by_fork[Constantinople] = opcodes_by_fork[Byzantium] + [
Op.SHL,
Op.SHR,
Op.SAR,
Op.EXTCODEHASH,
Op.CREATE2,
]
opcodes_by_fork[ConstantinopleFix] = opcodes_by_fork[Constantinople]
opcodes_by_fork[Istanbul] = opcodes_by_fork[ConstantinopleFix] + [Op.CHAINID, Op.SELFBALANCE]
opcodes_by_fork[Berlin] = opcodes_by_fork[Istanbul]
opcodes_by_fork[London] = opcodes_by_fork[Berlin] + [Op.BASEFEE]
opcodes_by_fork[Paris] = opcodes_by_fork[London]
opcodes_by_fork[Shanghai] = opcodes_by_fork[Paris] + [Op.PUSH0]
opcodes_by_fork[Cancun] = opcodes_by_fork[Shanghai] + [
Op.BLOBHASH,
Op.BLOBBASEFEE,
Op.TLOAD,
Op.TSTORE,
Op.MCOPY,
]


def prepare_stack(opcode: Opcode) -> Bytecode:
"""Prepare the stack for opcode"""
if opcode == Op.CREATE:
return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5)
if opcode == Op.CREATE2:
return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(1) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5)
return Op.PUSH1(0x01) * 32


@pytest.mark.valid_from("Frontier")
def test_all_opcodes(state_test: StateTestFiller, pre: Alloc, fork: Fork):
"""Check if the opcode supported on given fork"""
code_worked = 1000

code_contract: Dict[Opcode, Address] = {}
for opcode in sorted(all_opcodes | undefined_opcodes):
code_contract[opcode] = pre.deploy_contract(
balance=10,
code=prepare_stack(opcode) + opcode,
storage={},
)

# EVM code to make the call and store the result
caller = pre.deploy_contract(
code=sum(
Op.SSTORE(
Op.PUSH1(opcode.int()),
Op.CALL(1_000_000, opcode_address, 0, 0, 0, 0, 0),
)
for opcode, opcode_address in code_contract.items()
)
+ Op.SSTORE(code_worked, 1)
+ Op.STOP,
)

post = {
caller: Account(
storage={**{opcode.int(): 1 for opcode in opcodes_by_fork[fork]}, code_worked: 1}
),
}

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

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


@pytest.mark.valid_from("Cancun")
def test_cover_revert(state_test: StateTestFiller, pre: Alloc):
"""Cover state revert from original tests"""
caller = pre.deploy_contract(
code=Op.SSTORE(1, 1) + Op.REVERT(0, 0),
)

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

post = {}
state_test(env=Environment(), pre=pre, post=post, tx=tx)

0 comments on commit 544568b

Please sign in to comment.