github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/cmd/evm/README.md (about)

     1  ## EVM state transition tool
     2  
     3  The `evm t8n` tool is a stateless state transition utility. It is a utility
     4  which can
     5  
     6  1. Take a prestate, including
     7  - Accounts,
     8  - Block context information,
     9  - Previous blockshashes (*optional)
    10  2. Apply a set of transactions,
    11  3. Apply a mining-reward (*optional),
    12  4. And generate a post-state, including
    13  - State root, transaction root, receipt root,
    14  - Information about rejected transactions,
    15  - Optionally: a full or partial post-state dump
    16  
    17  ## Specification
    18  
    19  The idea is to specify the behaviour of this binary very _strict_, so that other
    20  node implementors can build replicas based on their own state-machines, and the
    21  state generators can swap between a `geth`-based implementation and a `parityvm`-based
    22  implementation.
    23  
    24  ### Command line params
    25  
    26  Command line params that has to be supported are
    27  ```
    28  
    29     --trace                            Output full trace logs to files <txhash>.jsonl
    30     --trace.nomemory                   Disable full memory dump in traces
    31     --trace.nostack                    Disable stack output in traces
    32     --trace.noreturndata               Disable return data output in traces
    33     --output.basedir value             Specifies where output files are placed. Will be created if it does not exist.
    34     --output.alloc alloc               Determines where to put the alloc of the post-state.
    35                                        `stdout` - into the stdout output
    36                                        `stderr` - into the stderr output
    37     --output.result result             Determines where to put the result (stateroot, txroot etc) of the post-state.
    38                                        `stdout` - into the stdout output
    39                                        `stderr` - into the stderr output
    40     --output.body value                If set, the RLP of the transactions (block body) will be written to this file.
    41     --input.txs stdin                  stdin or file name of where to find the transactions to apply. If the file prefix is '.rlp', then the data is interpreted as an RLP list of signed transactions.The '.rlp' format is identical to the output.body format. (default: "txs.json")
    42     --state.fork value                 Name of ruleset to use.
    43     --state.chainid value              ChainID to use (default: 1)
    44     --state.reward value               Mining reward. Set to -1 to disable (default: 0)
    45  
    46  ```
    47  
    48  ### Error codes and output
    49  
    50  All logging should happen against the `stderr`.
    51  There are a few (not many) errors that can occur, those are defined below.
    52  
    53  #### EVM-based errors (`2` to `9`)
    54  
    55  - Other EVM error. Exit code `2`
    56  - Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`.
    57  - Block history is not supplied, but needed for a `BLOCKHASH` operation. If `BLOCKHASH`
    58    is invoked targeting a block which history has not been provided for, the program will
    59    exit with code `4`.
    60  
    61  #### IO errors (`10`-`20`)
    62  
    63  - Invalid input json: the supplied data could not be marshalled.
    64    The program will exit with code `10`
    65  - IO problems: failure to load or save files, the program will exit with code `11`
    66  
    67  ## Examples
    68  ### Basic usage
    69  
    70  Invoking it with the provided example files
    71  ```
    72  ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json
    73  ```
    74  Two resulting files:
    75  
    76  `alloc.json`:
    77  ```json
    78  {
    79   "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": {
    80    "balance": "0xfeed1a9d",
    81    "nonce": "0x1"
    82   },
    83   "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
    84    "balance": "0x5ffd4878be161d74",
    85    "nonce": "0xac"
    86   },
    87   "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
    88    "balance": "0xa410"
    89   }
    90  }
    91  ```
    92  `result.json`:
    93  ```json
    94  {
    95   "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13",
    96   "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d",
    97   "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
    98   "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    99   "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   100   "receipts": [
   101    {
   102     "root": "0x",
   103     "status": "0x1",
   104     "cumulativeGasUsed": "0x5208",
   105     "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   106     "logs": null,
   107     "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673",
   108     "contractAddress": "0x0000000000000000000000000000000000000000",
   109     "gasUsed": "0x5208",
   110     "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   111     "transactionIndex": "0x0"
   112    }
   113   ],
   114   "rejected": [
   115    {
   116     "index": 1,
   117     "error": "nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
   118    }
   119   ]
   120  }
   121  ```
   122  
   123  We can make them spit out the data to e.g. `stdout` like this:
   124  ```
   125  ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.result=stdout --output.alloc=stdout
   126  ```
   127  Output:
   128  ```json
   129  {
   130   "alloc": {
   131    "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": {
   132     "balance": "0xfeed1a9d",
   133     "nonce": "0x1"
   134    },
   135    "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
   136     "balance": "0x5ffd4878be161d74",
   137     "nonce": "0xac"
   138    },
   139    "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
   140     "balance": "0xa410"
   141    }
   142   },
   143   "result": {
   144    "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13",
   145    "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d",
   146    "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2",
   147    "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
   148    "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   149    "receipts": [
   150     {
   151      "root": "0x",
   152      "status": "0x1",
   153      "cumulativeGasUsed": "0x5208",
   154      "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   155      "logs": null,
   156      "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673",
   157      "contractAddress": "0x0000000000000000000000000000000000000000",
   158      "gasUsed": "0x5208",
   159      "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   160      "transactionIndex": "0x0"
   161     }
   162    ],
   163    "rejected": [
   164     {
   165      "index": 1,
   166      "error": "nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
   167     }
   168    ]
   169   }
   170  }
   171  ```
   172  
   173  ## About Ommers
   174  
   175  Mining rewards and ommer rewards might need to be added. This is how those are applied:
   176  
   177  - `block_reward` is the block mining reward for the miner (`0xaa`), of a block at height `N`.
   178  - For each ommer (mined by `0xbb`), with blocknumber `N-delta`
   179    - (where `delta` is the difference between the current block and the ommer)
   180    - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward`
   181    - The account `0xaa` (block miner) is awarded `block_reward / 32`
   182  
   183  To make `state_t8n` apply these, the following inputs are required:
   184  
   185  - `state.reward`
   186    - For ethash, it is `5000000000000000000` `wei`,
   187    - If this is not defined, mining rewards are not applied,
   188    - A value of `0` is valid, and causes accounts to be 'touched'.
   189  - For each ommer, the tool needs to be given an `address` and a `delta`. This
   190    is done via the `env`.
   191  
   192  Note: the tool does not verify that e.g. the normal uncle rules apply,
   193  and allows e.g two uncles at the same height, or the uncle-distance. This means that
   194  the tool allows for negative uncle reward (distance > 8)
   195  
   196  Example:
   197  `./testdata/5/env.json`:
   198  ```json
   199  {
   200    "currentCoinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
   201    "currentDifficulty": "0x20000",
   202    "currentGasLimit": "0x750a163df65e8a",
   203    "currentNumber": "1",
   204    "currentTimestamp": "1000",
   205    "ommers": [
   206      {"delta":  1, "address": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" },
   207      {"delta":  2, "address": "0xcccccccccccccccccccccccccccccccccccccccc" }
   208    ]
   209  }
   210  ```
   211  When applying this, using a reward of `0x80`
   212  Output:
   213  ```json
   214  {
   215   "alloc": {
   216    "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": {
   217     "balance": "0x88"
   218    },
   219    "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": {
   220     "balance": "0x70"
   221    },
   222    "0xcccccccccccccccccccccccccccccccccccccccc": {
   223     "balance": "0x60"
   224    }
   225   }
   226  }
   227  ```
   228  ### Future EIPS
   229  
   230  It is also possible to experiment with future eips that are not yet defined in a hard fork.
   231  Example, putting EIP-1344 into Frontier:
   232  ```
   233  ./evm t8n --state.fork=Frontier+1344 --input.pre=./testdata/1/pre.json --input.txs=./testdata/1/txs.json --input.env=/testdata/1/env.json
   234  ```
   235  
   236  ### Block history
   237  
   238  The `BLOCKHASH` opcode requires blockhashes to be provided by the caller, inside the `env`.
   239  If a required blockhash is not provided, the exit code should be `4`:
   240  Example where blockhashes are provided:
   241  ```
   242  ./evm --verbosity=1 t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json  --trace
   243  INFO [07-27|11:53:40.960] Trie dumping started                     root=b7341d..857ea1
   244  INFO [07-27|11:53:40.960] Trie dumping complete                    accounts=3 elapsed="103.298µs"
   245  INFO [07-27|11:53:40.960] Wrote file                               file=alloc.json
   246  INFO [07-27|11:53:40.960] Wrote file                               file=result.json
   247  
   248  ```
   249  
   250  ```
   251  cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2
   252  ```
   253  ```
   254  {"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnData":"0x","depth":1,"refund":0,"opName":"PUSH1","error":""}
   255  {"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnData":"0x","depth":1,"refund":0,"opName":"BLOCKHASH","error":""}
   256  {"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnData":"0x","depth":1,"refund":0,"opName":"STOP","error":""}
   257  {"output":"","gasUsed":"0x17","time":156276}
   258  ```
   259  
   260  In this example, the caller has not provided the required blockhash:
   261  ```
   262  ./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace
   263  ERROR(4): getHash(3) invoked, blockhash for that block not provided
   264  ```
   265  Error code: 4
   266  
   267  ### Chaining
   268  
   269  Another thing that can be done, is to chain invocations:
   270  ```
   271  ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json
   272  INFO [07-27|11:53:41.049] rejected tx                              index=1 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
   273  INFO [07-27|11:53:41.050] Trie dumping started                     root=84208a..ae4e13
   274  INFO [07-27|11:53:41.050] Trie dumping complete                    accounts=3 elapsed="59.412µs"
   275  INFO [07-27|11:53:41.050] Wrote file                               file=result.json
   276  INFO [07-27|11:53:41.051] rejected tx                              index=0 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
   277  INFO [07-27|11:53:41.051] rejected tx                              index=1 hash=0557ba..18d673 from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low: address 0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192, tx: 0 state: 1"
   278  INFO [07-27|11:53:41.052] Trie dumping started                     root=84208a..ae4e13
   279  INFO [07-27|11:53:41.052] Trie dumping complete                    accounts=3 elapsed="45.734µs"
   280  INFO [07-27|11:53:41.052] Wrote file                               file=alloc.json
   281  INFO [07-27|11:53:41.052] Wrote file                               file=result.json
   282  
   283  ```
   284  What happened here, is that we first applied two identical transactions, so the second one was rejected.
   285  Then, taking the poststate alloc as the input for the next state, we tried again to include
   286  the same two transactions: this time, both failed due to too low nonce.
   287  
   288  In order to meaningfully chain invocations, one would need to provide meaningful new `env`, otherwise the
   289  actual blocknumber (exposed to the EVM) would not increase.
   290  
   291  ### Transactions in RLP form
   292  
   293  It is possible to provide already-signed transactions as input to, using an `input.txs` which ends with the `rlp` suffix.
   294  The input format for RLP-form transactions is _identical_ to the _output_ format for block bodies. Therefore, it's fully possible
   295  to use the evm to go from `json` input to `rlp` input.
   296  
   297  The following command takes **json** the transactions in `./testdata/13/txs.json` and signs them. After execution, they are output to `signed_txs.rlp`.:
   298  ```
   299  ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./testdata/13/txs.json --input.env=./testdata/13/env.json --output.result=alloc_jsontx.json --output.body=signed_txs.rlp
   300  INFO [07-27|11:53:41.124] Trie dumping started                     root=e4b924..6aef61
   301  INFO [07-27|11:53:41.124] Trie dumping complete                    accounts=3 elapsed="94.284µs"
   302  INFO [07-27|11:53:41.125] Wrote file                               file=alloc.json
   303  INFO [07-27|11:53:41.125] Wrote file                               file=alloc_jsontx.json
   304  INFO [07-27|11:53:41.125] Wrote file                               file=signed_txs.rlp
   305  
   306  ```
   307  
   308  The `output.body` is the rlp-list of transactions, encoded in hex and placed in a string a'la `json` encoding rules:
   309  ```
   310  cat signed_txs.rlp
   311  "0xf8d2b86702f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904b86702f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9"
   312  ```
   313  
   314  We can use `rlpdump` to check what the contents are:
   315  ```
   316  rlpdump -hex $(cat signed_txs.rlp | jq -r )
   317  [
   318    02f864010180820fa08284d09411111111111111111111111111111111111111118080c001a0b7dfab36232379bb3d1497a4f91c1966b1f932eae3ade107bf5d723b9cb474e0a06261c359a10f2132f126d250485b90cf20f30340801244a08ef6142ab33d1904,
   319    02f864010280820fa08284d09411111111111111111111111111111111111111118080c080a0d4ec563b6568cd42d998fc4134b36933c6568d01533b5adf08769270243c6c7fa072bf7c21eac6bbeae5143371eef26d5e279637f3bd73482b55979d76d935b1e9,
   320  ]
   321  ```
   322  Now, we can now use those (or any other already signed transactions), as input, like so:
   323  ```
   324  ./evm t8n --state.fork=London --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json
   325  INFO [07-27|11:53:41.253] Trie dumping started                     root=e4b924..6aef61
   326  INFO [07-27|11:53:41.253] Trie dumping complete                    accounts=3 elapsed="128.445µs"
   327  INFO [07-27|11:53:41.253] Wrote file                               file=alloc.json
   328  INFO [07-27|11:53:41.255] Wrote file                               file=alloc_rlptx.json
   329  
   330  ```
   331  
   332  You might have noticed that the results from these two invocations were stored in two separate files.
   333  And we can now finally check that they match.
   334  ```
   335  cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot
   336  "0xe4b924a6adb5959fccf769d5b7bb2f6359e26d1e76a2443c5a91a36d826aef61"
   337  "0xe4b924a6adb5959fccf769d5b7bb2f6359e26d1e76a2443c5a91a36d826aef61"
   338  ```