Blockchain Tests Source Code

Location: /src/BlockchainTestsFiller

Blockchain tests can include multiple blocks and each of those blocks can include multiple transactions. These blocks can be either valid or invalid.

Subfolders

InvalidBlocks Tests containing blocks that are expected to fail on import
ValidBlocks Normal blockchain tests
TransitionTests Blockchain tests with exotic network rules switching forks at block #5

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

Genesis Block

This section contains the genesis block that starts the chain being tested.

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      genesisBlockHeader: {
         "bloom" : "0x0 <<lots more 0s>>"
         "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1",
         "difficulty" : "0x020000",
         "extraData" : "0x42",
         "gasLimit" : "0x2fefd8",
         "gasUsed" : "0x00",
         "mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
         "nonce" : "0x0000000000000000",
         "number" : "0x00",
         "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
         "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
         "stateRoot" : "0x14f0692d8daa55f0eb56a1cf1e2b07746d66ddfa3f8bae21fece76d1421b5d47",
         "timestamp" : "0x54c98c81",
         "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
         "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
         "baseFeePerGas" : "1000"
      }
   }
}
name-of-test:
   <other sections>
   genesisBlockHeader:
      bloom: 0x0 <<lots more 0s>>
      coinbase: 0x8888f1f195afa192cfee860698584c030f4c9db1
      difficulty: 131072
      extraData: 0x42
      gasLimit: 3141592
      gasUsed: 0
      mixHash: 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
      nonce: 0x0102030405060708
      number: 0
      parentHash: 0x0000000000000000000000000000000000000000000000000000000000000000
      receiptTrie: 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
      stateRoot: 0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a
      timestamp: 0x54c98c81
      transactionsTrie: 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
      uncleHash: 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
      baseFeePerGas: 1000

Fields

Name in Block Header Sections Meaning
bloom bloom filter to speed searches
coinbase beneficiary of mining fee
extraData data added to the block, ignored by retesteth
difficulty (pre-merge) difficulty of previous block
difficulty (post-merge) not used anymore (value zero), identifies a block as pre-merge
gasLimit limit of gas usage per block
gasUsed gas used by this block
mixHash and nonce (pre-merge) used by the proof of work algorithm, ignored by retesteth.
mixHash (post-merge) block random value, has to be 32 bytes (it is not automatically zero padded)
number number of ancestor blocks
parentHash hash of previous block
receiptTrie The root of the receipt trie after this block
stateRoot The root of the state trie after this block
timestamp Unix time
transactionTrie The root of the transaction trie after this block
uncleHash hash of uncle block or blocks
baseFeePerGas The base fee per gas required of transactions (London and later, because of EIP 1559)

You can read more about the block header fields here.

Interaction with The Merge

The transition from proof of work (PoW) to proof of stake (PoS) changes the meaning of some genesis fields.

  • difficulty is set to zero for proof of stake genesis blocks. If you try to run a PoS test on an older fork that uses PoW, the default difficulty is 0x020000.
  • mixHash is used for the random value that in production comes from the beacon chain. If this value is specified in the genesis block, that value is the “random” value until there is a blockheader with mixHash. When that happens, that mixHash value is the random value until the next block with a mixHash.

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
      

Blocks

This section contains the blocks of the blockchain that are supposed to modify the state from the one in the pre section to the one in the expect section.

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      blocks: [
        { transactions: [
            { <transaction> },
            { <transaction> }
          ]
        },
        { transactions: [
            { <transaction> },
            { <transaction> }
          ]
          blockHeader: {
             "extraData" : "0x42",
             "gasLimit" : "0x2fefd8",
             "gasUsed" : "0x5208",
          },
          uncleHeaders: [ <values here> ]
        }
      ]
   }
}
name-of-test:
   <other sections>
   blocks:
   - transactions:
     - <transaction>
     - <transaction>
   - blockHeader:
         extraData: 42
         gasLimit: 100_000
         gasUsed: 2_000
     uncleHeaders:
       <values here>
     transactions:
     - <transaction>
     - <transaction>

Fields

The fields in each block are optional. Only include those fields you need.

  • blockHeader:

    This field contains the block header parameters. Parameters that are missing are copied from the genesis block.

    Name in Block Header Sections Meaning
    bloom bloom filter to speed searches
    coinbase beneficiary of mining fee
    extraData data added to the block, ignored by retesteth
    difficulty (pre-merge) difficulty of previous block
    difficulty (post-merge) not used anymore (value zero), identifies a block as pre-merge
    gasLimit limit of gas usage per block
    gasUsed gas used by this block
    mixHash and nonce (pre-merge) used by the proof of work algorithm, ignored by retesteth.
    mixHash (post-merge) block random value, has to be 32 bytes (it is not automatically zero padded)
    number number of ancestor blocks
    parentHash hash of previous block
    receiptTrie The root of the receipt trie after this block
    stateRoot The root of the state trie after this block
    timestamp Unix time
    transactionTrie The root of the transaction trie after this block
    uncleHash hash of uncle block or blocks
    baseFeePerGas The base fee per gas required of transactions (London and later, because of EIP 1559)

    You can read more about the block header fields here.

    One field inside the block header which is not standard in Ethereum is expectException. That field, which is only used in invalid block tests, identifies the exception we expect to receive for the block on different forks of Ethereum. You can read more about it in the Invalid Block Tests section of the Blockchain Tests tutorial.

    Note that starting with London gasLimit cannot be changed by more than 1/1024 from the previous value because of EIP 1559. You can specify baseFeePerGas, but the block is only valid if it is the same value that was calculated from the previous block.

  • blocknumber and chainname:

    If you are testing behavior in the presence of multiple competing chains, these fields let you specify the chain and the block’s location within it.

  • uncleHeaders:

    A list of the uncle blocks (blocks mined at the same time). Each item in the list has two fields:

    • chainname: The name of the chain from which the uncle block comes
    • populateFromBlock: The block number within that chain for the block that is an uncle of the block you are specifying.

    However, if you write a test with uncles, you need to run it twice, once to get the state hash values to write them in the test filler file, and again to actually run the test.

  • transactions:

    A list of transaction objects in the block.

Transaction

This is the data of a transaction. Every block contains a list of transactions

Format

JSON YAML
{
    "name-of-test":
    {
       <other sections>
       "blocks": [
          {
            transactions: [
              {
                data: "0xDA7A",
                gasLimit: "0x6a506a50",
                gasPrice: 1,
                value: 1,
                to: "add13ess01233210add13ess01233210",
                secretKey: "5ec13e7 ... 5ec13e7"
                nonce: '0x909ce'
              },
              {
                data: "0xDA7A",
                accessList: [
                  {
                     "address": "0xcccccccccccccccccccccccccccccccccccccccd",
                     "storageKeys": ["0x1000", "0x60A7"]
                  },
                  {
                     "address": "0xccccccccccccccccccccccccccccccccccccccce",
                     "storageKeys": []
                  }
                ],
                gasLimit: "0x6a506a50",
                maxFeePerGas: 1000,
                maxPriorityFeePerGas: 10,
                value: 1,
                to: "add13ess01233210add13ess01233210",
                secretKey: "5ec13e7 ... 5ec13e7"
                nonce: '0x909ce'
              },
              <other transactions>
            ]
            <other block fields>
          },
          <other blocks>
       ]
   }
<test-name>:
  <other sections>
  blocks:
  - transactions:
    - data: 0xDA7A
      gasLimit: '0x6a506a50'
      maxFeePerGas: 1000
      maxPriorityFeePerGas: 10
      value: 1
      to: "add13ess01233210add13ess01233210"
      secretKey: "5ec13e7 ... 5ec13e7"
      nonce: '0x909ce'
    - data: 0xDA7A
      accessList:
      - address: 0xcccccccccccccccccccccccccccccccccccccccd
        storageKeys:
        - 0x1000
      - address: 0xcccccccccccccccccccccccccccccccccccccccc
        storageKeys: []
      gasLimit: '0x6a506a50'
      gasPrice: "1"
      value: 1
      to: "add13ess01233210add13ess01233210"
      secretKey: "5ec13e7 ... 5ec13e7"
      nonce: '0x909ce'
    - <another transaction>
    <other block fields>
  - <another block>

Fields

  • data: The data, either in hexadecimal or an ABI call with this format: :abi <function signature> <function parameters separated by spaces>.
  • accessList: An optional EIP2930 access list. The accessList is a list of structures, each of which has to have an address and a list of storageKeys (which may be empty).
  • gasLimit: Gas limit for the transaction
  • gasPrice: Gas price in Wei, prior to London (changed by EIP 1559).
  • maxFeePerGas: Maximum acceptable gas price in Wei. Available in London and later.
  • maxPriorityFeePerGas: Tip to give the miner (per gas, in Wei). The real tip is either this value or maxFeePerGas-baseFeePerGas (the lower of the two). Available in London and later.
  • value: The value the transaction transmits in Wei
  • 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. Alternatively, if you replace all the nonce values with auto, the tool does this for you.
  • invalid: If the transaction is invalid, meaning clients should reject it, set this value to “1”
  • expectException: .. include:: ../test_filler/test_expect_exception.rst

Expect

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

Format

JSON YAML
{
   "name-of-test": {
      <other sections>,
      "expect": [
        {
           "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:
   - 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

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