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)) }
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>.
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 |
<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.