github.com/core-coin/go-core/v2@v2.1.9/cmd/cvm/README.md (about) 1 ## CVM state transition tool 2 3 The `cvm 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 `gocore`-based implementations. 22 23 ### Command line params 24 25 Command line params that has to be supported are 26 ``` 27 28 --trace Output full trace logs to files <txhash>.jsonl 29 --trace.nomemory Disable full memory dump in traces 30 --trace.nostack Disable stack output in traces 31 --trace.noreturndata Disable return data output in traces 32 --output.basedir value Specifies where output files are placed. Will be created if it does not exist. (default: ".") 33 --output.alloc alloc Determines where to put the alloc of the post-state. 34 `stdout` - into the stdout output 35 `stderr` - into the stderr output 36 --output.result result Determines where to put the result (stateroot, txroot etc) of the post-state. 37 `stdout` - into the stdout output 38 `stderr` - into the stderr output 39 --state.fork value Name of ruleset to use. 40 --state.networkid value ChainID to use (default: 1) 41 --state.reward value Mining reward. Set to -1 to disable (default: 0) 42 43 ``` 44 45 ### Error codes and output 46 47 All logging should happen against the `stderr`. 48 There are a few (not many) errors that can occur, those are defined below. 49 50 #### CVM-based errors (`2` to `9`) 51 52 - Other CVM error. Exit code `2` 53 - Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`. 54 - Block history is not supplied, but needed for a `BLOCKHASH` operation. If `BLOCKHASH` 55 is invoked targeting a block which history has not been provided for, the program will 56 exit with code `4`. 57 58 #### IO errors (`10`-`20`) 59 60 - Invalid input json: the supplied data could not be marshalled. 61 The program will exit with code `10` 62 - IO problems: failure to load or save files, the program will exit with code `11` 63 64 ## Examples 65 ### Basic usage 66 67 Invoking it with the provided example files 68 ``` 69 ./cvm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json 70 ``` 71 Two resulting files: 72 73 `alloc.json`: 74 ```json 75 { 76 "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { 77 "balance": "0xfeed1a9d", 78 "nonce": "0x1" 79 }, 80 "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 81 "balance": "0x5ffd4878be161d74", 82 "nonce": "0xac" 83 }, 84 "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 85 "balance": "0xa410" 86 } 87 } 88 ``` 89 `result.json`: 90 ```json 91 { 92 "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13", 93 "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d", 94 "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", 95 "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 96 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 97 "receipts": [ 98 { 99 "root": "0x", 100 "status": "0x1", 101 "cumulativeEnergyUsed": "0x5208", 102 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 103 "logs": null, 104 "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", 105 "contractAddress": "0x0000000000000000000000000000000000000000", 106 "energyUsed": "0x5208", 107 "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 108 "transactionIndex": "0x0" 109 } 110 ], 111 "rejected": [ 112 1 113 ] 114 } 115 ``` 116 117 We can make them spit out the data to e.g. `stdout` like this: 118 ``` 119 ./cvm 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 120 ``` 121 Output: 122 ```json 123 { 124 "alloc": { 125 "0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { 126 "balance": "0xfeed1a9d", 127 "nonce": "0x1" 128 }, 129 "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 130 "balance": "0x5ffd4878be161d74", 131 "nonce": "0xac" 132 }, 133 "0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { 134 "balance": "0xa410" 135 } 136 }, 137 "result": { 138 "stateRoot": "0x84208a19bc2b46ada7445180c1db162be5b39b9abc8c0a54b05d32943eae4e13", 139 "txRoot": "0xc4761fd7b87ff2364c7c60b6c5c8d02e522e815328aaea3f20e3b7b7ef52c42d", 140 "receiptRoot": "0x056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2", 141 "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", 142 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 143 "receipts": [ 144 { 145 "root": "0x", 146 "status": "0x1", 147 "cumulativeEnergyUsed": "0x5208", 148 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 149 "logs": null, 150 "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", 151 "contractAddress": "0x0000000000000000000000000000000000000000", 152 "energyUsed": "0x5208", 153 "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 154 "transactionIndex": "0x0" 155 } 156 ], 157 "rejected": [ 158 1 159 ] 160 } 161 } 162 ``` 163 164 ## About Ommers 165 166 Mining rewards and ommer rewards might need to be added. This is how those are applied: 167 168 - `block_reward` is the block mining reward for the miner (`0xaa`), of a block at height `N`. 169 - For each ommer (mined by `0xbb`), with blocknumber `N-delta` 170 - (where `delta` is the difference between the current block and the ommer) 171 - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward` 172 - The account `0xaa` (block miner) is awarded `block_reward / 32` 173 174 To make `state_t8n` apply these, the following inputs are required: 175 176 - `state.reward` 177 - For cryptore, it is `5000000000000000000` `ore`, 178 - If this is not defined, mining rewards are not applied, 179 - A value of `0` is valid, and causes accounts to be 'touched'. 180 - For each ommer, the tool needs to be given an `address` and a `delta`. This 181 is done via the `env`. 182 183 Note: the tool does not verify that e.g. the normal uncle rules apply, 184 and allows e.g two uncles at the same height, or the uncle-distance. This means that 185 the tool allows for negative uncle reward (distance > 8) 186 187 Example: 188 `./testdata/5/env.json`: 189 ```json 190 { 191 "currentCoinbase": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 192 "currentDifficulty": "0x20000", 193 "currentEnergyLimit": "0x750a163df65e8a", 194 "currentNumber": "1", 195 "currentTimestamp": "1000", 196 "ommers": [ 197 {"delta": 1, "address": "cb27de521e43741cf785cbad450d5649187b9612018f" }, 198 {"delta": 2, "address": "cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba" } 199 ] 200 } 201 ``` 202 When applying this, using a reward of `0x08` 203 Output: 204 ```json 205 { 206 "alloc": { 207 "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": { 208 "balance": "0x88" 209 }, 210 "cb27de521e43741cf785cbad450d5649187b9612018f": { 211 "balance": "0x70" 212 }, 213 "cb375a538daf54f2e568bb4237357b1cee1aa3cb7eba": { 214 "balance": "0x60" 215 } 216 } 217 } 218 ``` 219 ### Future CIPS 220 221 It is also possible to experiment with future cips that are not yet defined in a hard fork. 222 Example, putting CIP-1344: 223 ``` 224 ./cvm t8n --input.pre=./testdata/1/pre.json --input.txs=./testdata/1/txs.json --input.env=/testdata/1/env.json 225 ``` 226 227 ### Block history 228 229 The `BLOCKHASH` opcode requires blockhashes to be provided by the caller, inside the `env`. 230 If a required blockhash is not provided, the exit code should be `4`: 231 Example where blockhashes are provided: 232 ``` 233 ./cvm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace 234 ``` 235 ``` 236 cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 237 ``` 238 ``` 239 {"pc":0,"op":96,"energy":"0x5f58ef8","energyCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"PUSH1","error":""} 240 {"pc":2,"op":64,"energy":"0x5f58ef5","energyCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"BLOCKHASH","error":""} 241 {"pc":3,"op":0,"energy":"0x5f58ee1","energyCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"STOP","error":""} 242 {"output":"","energyUsed":"0x17","time":112885} 243 ``` 244 245 In this example, the caller has not provided the required blockhash: 246 ``` 247 ./cvm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace 248 ``` 249 ``` 250 ERROR(4): getHash(3) invoked, blockhash for that block not provided 251 ``` 252 Error code: 4 253 ### Chaining 254 255 Another thing that can be done, is to chain invocations: 256 ``` 257 ./cvm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./cvm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json 258 INFO [08-03|15:25:15.168] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" 259 INFO [08-03|15:25:15.169] rejected tx index=0 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" 260 INFO [08-03|15:25:15.169] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" 261 262 ``` 263 What happened here, is that we first applied two identical transactions, so the second one was rejected. 264 Then, taking the poststate alloc as the input for the next state, we tried again to include 265 the same two transactions: this time, both failed due to too low nonce. 266 267 In order to meaningfully chain invocations, one would need to provide meaningful new `env`, otherwise the 268 actual blocknumber (exposed to the CVM) would not increase. 269