Builder Tools

The JSON test fillers found in eth.tools.fixtures is a set of tools which facilitate creating standard JSON consensus tests as found in the ethereum/tests repository.

Note

Only VM and state tests are supported right now.

State Test Fillers

Tests are generated in two steps.

  • First, a test filler is written that contains a high level description of the test case.

  • Subsequently, the filler is compiled to the actual test in a process called filling, mainly consisting of calculating the resulting state root.

The test builder represents each stage as a nested dictionary. Helper functions are provided to assemble the filler file step by step in the correct format. The fill_test() function handles compilation and takes additional parameters that can’t be inferred from the filler.

Creating a Filler

Fillers are generated in a functional fashion by piping a dictionary through a sequence of functions.

filler = pipe(
    setup_main_filler("test"),
    pre_state(
        (sender, "balance", 1),
        (receiver, "balance", 0),
    ),
    expect(
        networks=["Frontier"],
        transaction={
            "to": receiver,
            "value": 1,
            "secretKey": sender_key,
        },
        post_state=[
            [sender, "balance", 0],
            [receiver, "balance", 1],
        ]
    )
)

Note

Note that setup_filler() returns a dictionary, whereas all of the following functions such as pre_state(), expect(), expect to be passed a dictionary as their single argument and return an updated version of the dictionary.

eth.tools.fixtures.fillers.common.setup_main_filler(name: str, environment: Dict[Any, Any] | None = None) Dict[str, Dict[str, Any]]

Kick off the filler generation process by creating the general filler scaffold with a test name and general information about the testing environment.

For tests for the main chain, the environment parameter is expected to be a dictionary with some or all of the following keys:

key

description

"currentCoinbase"

the coinbase address

"currentNumber"

the block number

"previousHash"

the hash of the parent block

"currentDifficulty"

the block’s difficulty

"currentGasLimit"

the block’s gas limit

"currentTimestamp"

the timestamp of the block

eth.tools.fixtures.fillers.pre_state(*raw_state: Dict[Address, AccountDetails] | List[Tuple[Address, Dict[str, int | bytes | Dict[int, int]]]], filler: Dict[str, Any]) None

Specify the state prior to the test execution. Multiple invocations don’t override the state but extend it instead.

In general, the elements of state_definitions are nested dictionaries of the following form:

{
    address: {
        "nonce": <account nonce>,
        "balance": <account balance>,
        "code": <account code>,
        "storage": {
            <storage slot>: <storage value>
        }
    }
}

To avoid unnecessary nesting especially if only few fields per account are specified, the following and similar formats are possible as well:

(address, "balance", <account balance>)
(address, "storage", <storage slot>, <storage value>)
(address, "storage", {<storage slot>: <storage value>})
(address, {"balance", <account balance>})
eth.tools.fixtures.fillers.execution(execution: Dict[str, Any] = '__no__default__', filler: Dict[str, Any] = '__no__default__') Dict[str, Any]

For VM tests, specify the code that is being run as well as the current state of the EVM. State tests don’t support this object. The parameter is a dictionary specifying some or all of the following keys:

key

description

"address"

the address of the account executing the code

"caller"

the caller address

"origin"

the origin address (defaulting to the caller address)

"value"

the value of the call

"data"

the data passed with the call

"gasPrice"

the gas price of the call

"gas"

the amount of gas allocated for the call

"code"

the bytecode to execute

"vyperLLLCode"

the code in Vyper LLL (compiled to bytecode automatically)

eth.tools.fixtures.fillers.expect(post_state: Dict[str, Any] | None = None, networks: Any | None = None, transaction: TransactionDict | None = None) Callable[[...], Dict[str, Any]]

Specify the expected result for the test.

For state tests, multiple expectations can be given, differing in the transaction data, gas limit, and value, in the applicable networks, and as a result also in the post state. VM tests support only a single expectation with no specified network and no transaction. (here, its role is played by execution()).

  • post_state is a list of state definition in the same form as expected by pre_state(). State items that are not set explicitly default to their pre state.

  • networks defines the forks under which the expectation is applicable. It

    should be a sublist of the following identifiers (also available in ALL_FORKS):

    • "Frontier"

    • "Homestead"

    • "EIP150"

    • "EIP158"

    • "Byzantium"

  • transaction is a dictionary coming in two variants. For the main shard:

    key

    description

    "data"

    the transaction data,

    "gasLimit"

    the transaction gas limit,

    "gasPrice"

    the gas price,

    "nonce"

    the transaction nonce,

    "value"

    the transaction value

In addition, one should specify either the signature itself (via keys "v", "r", and "s") or a private key used for signing (via "secretKey").