Skip to content

docs: add getting started guide for EEST opcode minilang #1818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 7, 2025
55 changes: 54 additions & 1 deletion docs/writing_tests/writing_a_new_test.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,63 @@ The code can be in either of the following formats:

- `bytes` object, representing the raw opcodes in binary format.
- `str`, representing an hexadecimal format of the opcodes.
- `Code` compilable object.
- `Code` compilable object (see below for supported types).

`Code` objects can be concatenated together by using the `+` operator.

### Using the Python Opcode Minilang (RECOMMENDED)

The recommended way to write EVM bytecode for tests is to use the Python-based minilang provided by the [Opcodes][ethereum_test_vm.opcode.Opcodes] class. This allows you to construct bytecode using symbolic opcodes as Python objects.

#### Example: Simple Addition Contract

```python
from ethereum_test_vm.opcode import Opcodes

code = (
Opcodes.PUSH1(0x02)
+ Opcodes.PUSH1(0x03)
+ Opcodes.ADD()
+ Opcodes.PUSH1(0x00)
+ Opcodes.SSTORE()
+ Opcodes.STOP()
)
```

You can assign this `code` to the `code` field of an account in your test's `pre` or `post` state.

For a full list of available opcodes and their usage, see the [Opcodes][ethereum_test_vm.opcode.Opcodes] reference.

### Higher-Level Constructs

For more complex control flow, you can use constructs like [Switch][ethereum_test_tools.code.generators.Switch] and [Case][ethereum_test_tools.code.generators.Case] from the [ethereum_test_tools.code.generators][ethereum_test_tools.code.generators] module:

```python
from ethereum_test_tools.code.generators import Switch, Case
from ethereum_test_vm.opcode import Opcodes as Op

code = Switch(
cases=[
Case(condition=Op.EQ(Op.CALLDATALOAD(0), 1), action=Op.PUSH1(0x01) + Op.STOP()),
Case(condition=Op.EQ(Op.CALLDATALOAD(0), 2), action=Op.PUSH1(0x02) + Op.STOP()),
],
default_action=Op.PUSH1(0x00) + Op.STOP(),
)
```

See the [ethereum_test_tools.code.generators][ethereum_test_tools.code.generators] reference for more details and additional constructs like [While][ethereum_test_tools.code.generators.While] and [Conditional][ethereum_test_tools.code.generators.Conditional].

### Converting Bytecode to Minilang

If you have EVM bytecode (as hex or binary), you can use the [`evm_bytes` CLI tool](../library/cli/evm_bytes.md) to convert it to the EEST Python opcode minilang automatically:

- [evm_bytes CLI documentation](../library/cli/evm_bytes.md)
- [Online reference](https://eest.ethereum.org/main/library/cli/evm_bytes/)

### Restrictions: No Yul in Python Test Cases

**Note:** As of [PR #1779](https://github.com/ethereum/execution-spec-tests/pull/1779), the use of Yul source in Python test cases is forbidden. All new tests must use the Python opcode minilang as shown above.

## Verifying the Accounts' Post States

The state of the accounts after all blocks/transactions have been executed is
Expand Down