State Transition Tests Source Code

Location: src/GeneralStateTestsFiller

State transition tests include a single transaction that is supposed to change the state of the blockchain from the pre state to the expect state.

Note

Except for the values in the indexes section, all the field values in the tests’ source code are strings. In YAML string is the default field type. In JSON string values are enclosed by quotes.

When a value is numeric, such as a value in storage or an address’s balance, it can be specified either in hexademical (starting with 0x), or in decimal (starting with a digit). For the sake of legibility, numeric values can also have underscores. For example, you can use 1_000_000_000 for 10^9, which is a lot more readable than 1000000000.

When a numeric field exceeds 256 bits, you can specify it using the syntax 0x:bigint 0x1000….00001.

Test Structure

You can write tests either in JSON format or in YAML format. All tests are inside a structure with their name

Format

Format JSON YAML
Filename name-of-testFiller.json name-of-testFiller.yml
Format
{
   "name-of-test": {
       Sections go here
   }
}
name-of-test:
   Sections go here

Env

This section contains the environment, the block just before the one that runs the VM or executes the transaction.

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      "env" : {
         "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
         "currentDifficulty" : "0x020000",
         "currentGasLimit" : "0x05f5e100",
         "currentNumber" : "0x01",
         "currentTimestamp" : "0x03e8",
         "previousHash" : "0x5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",,
         "currentBaseFee" : "1000"
      }
   }
}
name-of-test:
   <other sections>
   env:
      currentCoinbase: 2adc25665018aa1fe0e6bc666dac8fc2697ff9ba
      currentDifficulty: 0x20000
      currentGasLimit: 100000000
      currentNumber: 1
      currentTimestamp: 1000
      previousHash: 5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6
      currentBaseFee: 1000

Fields

You can read the definition of Ethereum block header fields here.

Note that this section only contains the fields that are relevant to single transaction tests.

Name in Env Section Meaning
currentCoinbase beneficiary of mining fee
currentDifficulty difficulty of previous block (pre Merge)
currentRandom random value that is supposed to come from the beacon chain (post Merge)
currentGasLimit limit of gas usage per block
currentNumber number of ancestor blocks
currentTimestamp Unix time
previousHash hash of previous block
currentBaseFee London and afterwards, the block base fee

Pre

This section contains the initial information of the blockchain.

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      "pre": {
         "address 1": {
             "balance": "0xba1a9ce000",
             "nonce": "0",
             "code": ":raw 0x600160010160005500"
             "storage: {
                     "0":       "12345",
                     "0x12": "0x121212"
         },
         "address 2": {
             <address fields go here>
         }
      }
   }
}
name-of-test:
   <other sections>
   pre:
     address 1:
       balance: 0xba1a9ce000,
       nonce: 0,
       code: :raw 0x600160010160005500
       storage:
         0:       12345
         0x12: 0x121212
     address 2:
       <address fields go here>

Address Fields

  • balance:

    Wei balance at the start of the test

  • code:

    The code of the contract. In the expect: section this has to be raw virtual machine code.

  • nonce:

    The nonce counter for the address. This value is used to make sure each transaction is processed only once. The first transaction the address sends has a nonce equal to this value, the second one is the nonce plus one, etc.

  • storage:

    Values in the storage of the address

    JSON YAML
    storage: {
        "1": 5,
        "0x20": 0x10
    }
    
    storage:
       1: 5
       0x20: 0x10
    
  • code:

    The code of the contract. There are several possibilities:

    • If the account is not a contract, this value is 0x

    • Raw virtual machine code. This is for cases where it is impossible to provide source code, or the source code is in a language retesteth does not recognize, such as Vyper.

      :raw 0x600160010160005500
      
    • Lisp Like Language (lll), for example:

      {
         ; Add 2+2 and store the value in storage location 0
         [[0]] (ADD 2 2)
      }
      
    • Yul, which is documented here, for example:

      :yul {
         // Add 2+2 and store the value in storage location 0
         sstore(0, add(2,2))
      }
      

      Optionally, you can specify the hard fork for which to compile the code

      :yul berlin {
         // Add 2+2 and store the value in storage location 0.
         // Because we compile using the Berlin hardfork,
         // there is no PUSH0, and we can use the code to check
         // forks prior to Shanghai.
         sstore(0, add(2,2))
      }
      
    • Solidity, which you can learn here. Solidity code can be provided to a test in two ways:

      • Put the solidity code itself in the contract definition (same place as the LLL or Yul code).
      • Put a :solidity section with the contract source code. In that case, the value in code: is :solidity <name of contract>.

      In either case, you can specify the hardfork to use using this syntax:

      // RETESTETH_SOLC_EVM_VERSION=berlin
      

Transaction

This is the data of the transaction.

Format

JSON YAML
{
    "name-of-test": {
       <other sections>,
       "transaction":
          {
             "data": ["0xDA7A", "0xDA7A", ":label hex 0xDA7A",
                  ":abi f(uint) 0xDA7A",
                  {
                       "data": "0xDA7A",
                       "accessList": [
                          {
                             "address": "0x0000000000000000000000000000000000000101",
                             "storageKeys": [0x60A7, 0xBEEF]
                          },
                          {
                             "address": "0x0000000000000000000000000000000000000102"
                          }
                       ]
                   }
             ],
             "gasLimit": ["0x6a506a50"],
             "value": ["1"],
             "to": "add13ess01233210add13ess01233210",
             "secretKey": "5ec13e7 ... 5ec13e7"
             "nonce": '0x909ce'
             "maxPriorityFeePerGas": "10",
             "maxFeePerGas": "2000",
}
name-of-test:
  <other sections>
  transaction:
    data:
    - 0xDA7A
    - 0xDA7A
    - :label hex 0xDA7A
    - :abi f(uint) 0xDA7A
    - data: :label acl 0xDA7A
      accessList:
      - address: 0x0000000000000000000000000000000000000101
        storageKeys:
        - 0x60A7
        - 0xBEEF
      - address: 0x0000000000000000000000000000000000000102
    gasLimit:
    - '0xga50ga50'
    value:
    - "1"
    to: "add13ess01233210add13ess01233210"
    secretKey: "5ec13e7 ... 5ec13e7"
    nonce: '0x909ce'
    maxPriorityFeePerGas: 10
    maxFeePerGas: 2000

Fields

  • data: The data, either in hexadecimal or an ABI call with this format: :abi <function signature> <function parameters separated by spaces>. The value can also be labeled: :label <value>. This value is specified as a list to enable files with multiple tests

    The data can also have an EIP2930 access list. In that case the data field itself is a structure with two fields: data (the data) and accessList. The accessList is a list of structures, each of which has to have an address and may have a list of storageKeys.

  • gasLimit: Gas limit for the transaction. This value is specified as a list to enable files with multiple tests

  • gasPrice: Gas price in Wei, only in Berlin and earlier (replaced by maxFeePerGas in London)

  • value: The value the transaction transmits in Wei. This value is specified as a list to enable files with multiple tests

  • to: The destination address, typically a contract. If you want to submit a create transaction, put an empty string here (and the data segment is the constructor).

  • secretKey: The secret key for the sending address. That address is derived from the secret key and therefore does not need to be specified explicitely (see here).

  • nonce: The nonce value for the transaction. The first transaction for an address has the nonce value of the address itself, the second transaction has the nonce plus one, etc.

  • maxPriorityFeePerGas: The maximum priority fee per gas (a.k.a. tip) the transaction is willing to pay to be included in the block (London and later, added by eip 1559).

  • maxFeePerGas: The maximum total fee per gas the transaction is willing to pay to be included in the block (London and later, added by eip 1559).

Expect

This section contains the information we expect to see after the test is concluded.

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      "expect": [
        {
           "indexes": {
             "data": [0, "2-3", ":label foo"],
             "gas": -1,
             "value": -1
           },
           "network": ["Istanbul", <other forks, see below>],
           "result": {
                "address 1": {
                    "balance": "0xba1a9ce000",
                    "nonce": "0",
                    "storage: {
                        "0x0":     12345,
                        "10" : "0x121212"
                    },
                    "code": "0x00"
                },
                "address 2": {
                    <address fields go here>
                }
        },
        { <forks & results> }
      ]
   }
}
name-of-test:
   <other sections>
   expect:
   - indexes:
       data:
       - !!int 0
       - 2-3
       - :label foo
       gas: !!int -1
       value: !!int -1
     network:
     - Istanbul
     - <another fork>
     result:
       address 1:
         balance: 0xba1a9ce000,
         nonce: 0,
         storage:
           0x0:  12345
           10: 0x121212
         code: 0x00
       address 2:
          <address fields go here>
   - <forks & results>

The Network Specification

The string that identifies a fork (version) within a network: list is one of three option:

  • The specific version: Istanbul
  • The version or anything later: >=Frontier
  • Anything up to (but not including) the version <Constantinople

The Indexes

The transaction can have multiple values for data, gasLimit, and value. The indexes: section specifies which of these values are covered by a particular item in expect, for each field it can be either a single specification or a list of specifications. Each of those specifications uses any of these options:

JSON YAML Meaning
-1 !!int -1 All the (data, gas, or value) values in the transaction. Note that this line can be omitted, -1 is the default value.
<n> !!int <n> The n’th value in the list (counting from zero)
“<a>-<b>” a-b Everthing from the a’th value to the b’th value (counting from zero)
“:label foo” :label foo Any value in the list that is specified as :label foo <value>

Address Fields

It is not necessary to include all fields for every address. Only include those fields you wish to test.

  • balance:

    Wei balance at the start of the test

  • code:

    The code of the contract. In the expect: section this has to be raw virtual machine code.

  • nonce:

    The nonce counter for the address. This value is used to make sure each transaction is processed only once. The first transaction the address sends has a nonce equal to this value, the second one is the nonce plus one, etc.

  • storage:

    Values in the storage of the address

    JSON YAML
    storage: {
        "1": 5,
        "0x20": 0x10
    }
    
    storage:
       1: 5
       0x20: 0x10
    

Expect Exception

This field specifies the exception we expect to see raised by for this transaction. It is optional - you only add it if an exception is expected.

JSON YAML
"expectException": {
   ">=London": TR_TipGtFeeCap
}
expectException:
   ">=London": TR_TipGtFeeCap

The fields are fork specifications:

Type of specification Example
Specific fork Berlin
A specific fork and all forks after it >=London
Anything prior to a specific fork (not including that fork) <Berlin

The value is an exception name. You can see the list in the retesteth code.