github.com/jimmyx0x/go-ethereum@v1.10.28/cmd/evm/transition-test.sh (about) 1 #!/bin/bash 2 ticks="\`\`\`" 3 4 function showjson(){ 5 echo "\`$1\`:" 6 echo "${ticks}json" 7 cat $1 8 echo "" 9 echo "$ticks" 10 } 11 function demo(){ 12 echo "$ticks" 13 echo "$1" 14 $1 15 echo "" 16 echo "$ticks" 17 echo "" 18 } 19 function tick(){ 20 echo "$ticks" 21 } 22 23 function code(){ 24 echo "$ticks$1" 25 } 26 27 cat << "EOF" 28 # EVM tool 29 30 The EVM tool provides a few useful subcommands to facilitate testing at the EVM 31 layer. 32 33 * transition tool (`t8n`) : a stateless state transition utility 34 * transaction tool (`t9n`) : a transaction validation utility 35 * block builder tool (`b11r`): a block assembler utility 36 37 ## State transition tool (`t8n`) 38 39 40 The `evm t8n` tool is a stateless state transition utility. It is a utility 41 which can 42 43 1. Take a prestate, including 44 - Accounts, 45 - Block context information, 46 - Previous blockshashes (*optional) 47 2. Apply a set of transactions, 48 3. Apply a mining-reward (*optional), 49 4. And generate a post-state, including 50 - State root, transaction root, receipt root, 51 - Information about rejected transactions, 52 - Optionally: a full or partial post-state dump 53 54 ### Specification 55 56 The idea is to specify the behaviour of this binary very _strict_, so that other 57 node implementors can build replicas based on their own state-machines, and the 58 state generators can swap between a \`geth\`-based implementation and a \`parityvm\`-based 59 implementation. 60 61 #### Command line params 62 63 Command line params that need to be supported are 64 65 ``` 66 EOF 67 ./evm t8n -h | grep "\-\-trace\.\|\-\-output\.\|\-\-state\.\|\-\-input" 68 cat << "EOF" 69 ``` 70 #### Objects 71 72 The transition tool uses JSON objects to read and write data related to the transition operation. The 73 following object definitions are required. 74 75 ##### `alloc` 76 77 The `alloc` object defines the prestate that transition will begin with. 78 79 ```go 80 // Map of address to account definition. 81 type Alloc map[common.Address]Account 82 // Genesis account. Each field is optional. 83 type Account struct { 84 Code []byte `json:"code"` 85 Storage map[common.Hash]common.Hash `json:"storage"` 86 Balance *big.Int `json:"balance"` 87 Nonce uint64 `json:"nonce"` 88 SecretKey []byte `json:"secretKey"` 89 } 90 ``` 91 92 ##### `env` 93 94 The `env` object defines the environmental context in which the transition will 95 take place. 96 97 ```go 98 type Env struct { 99 // required 100 CurrentCoinbase common.Address `json:"currentCoinbase"` 101 CurrentGasLimit uint64 `json:"currentGasLimit"` 102 CurrentNumber uint64 `json:"currentNumber"` 103 CurrentTimestamp uint64 `json:"currentTimestamp"` 104 Withdrawals []*Withdrawal `json:"withdrawals"` 105 // optional 106 CurrentDifficulty *big.Int `json:"currentDifficuly"` 107 CurrentRandom *big.Int `json:"currentRandom"` 108 CurrentBaseFee *big.Int `json:"currentBaseFee"` 109 ParentDifficulty *big.Int `json:"parentDifficulty"` 110 ParentGasUsed uint64 `json:"parentGasUsed"` 111 ParentGasLimit uint64 `json:"parentGasLimit"` 112 ParentTimestamp uint64 `json:"parentTimestamp"` 113 BlockHashes map[uint64]common.Hash `json:"blockHashes"` 114 ParentUncleHash common.Hash `json:"parentUncleHash"` 115 Ommers []Ommer `json:"ommers"` 116 } 117 type Ommer struct { 118 Delta uint64 `json:"delta"` 119 Address common.Address `json:"address"` 120 } 121 type Withdrawal struct { 122 Index uint64 `json:"index"` 123 ValidatorIndex uint64 `json:"validatorIndex"` 124 Recipient common.Address `json:"recipient"` 125 Amount *big.Int `json:"amount"` 126 } 127 ``` 128 129 ##### `txs` 130 131 The `txs` object is an array of any of the transaction types: `LegacyTx`, 132 `AccessListTx`, or `DynamicFeeTx`. 133 134 ```go 135 type LegacyTx struct { 136 Nonce uint64 `json:"nonce"` 137 GasPrice *big.Int `json:"gasPrice"` 138 Gas uint64 `json:"gas"` 139 To *common.Address `json:"to"` 140 Value *big.Int `json:"value"` 141 Data []byte `json:"data"` 142 V *big.Int `json:"v"` 143 R *big.Int `json:"r"` 144 S *big.Int `json:"s"` 145 SecretKey *common.Hash `json:"secretKey"` 146 } 147 type AccessList []AccessTuple 148 type AccessTuple struct { 149 Address common.Address `json:"address" gencodec:"required"` 150 StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` 151 } 152 type AccessListTx struct { 153 ChainID *big.Int `json:"chainId"` 154 Nonce uint64 `json:"nonce"` 155 GasPrice *big.Int `json:"gasPrice"` 156 Gas uint64 `json:"gas"` 157 To *common.Address `json:"to"` 158 Value *big.Int `json:"value"` 159 Data []byte `json:"data"` 160 AccessList AccessList `json:"accessList"` 161 V *big.Int `json:"v"` 162 R *big.Int `json:"r"` 163 S *big.Int `json:"s"` 164 SecretKey *common.Hash `json:"secretKey"` 165 } 166 type DynamicFeeTx struct { 167 ChainID *big.Int `json:"chainId"` 168 Nonce uint64 `json:"nonce"` 169 GasTipCap *big.Int `json:"maxPriorityFeePerGas"` 170 GasFeeCap *big.Int `json:"maxFeePerGas"` 171 Gas uint64 `json:"gas"` 172 To *common.Address `json:"to"` 173 Value *big.Int `json:"value"` 174 Data []byte `json:"data"` 175 AccessList AccessList `json:"accessList"` 176 V *big.Int `json:"v"` 177 R *big.Int `json:"r"` 178 S *big.Int `json:"s"` 179 SecretKey *common.Hash `json:"secretKey"` 180 } 181 ``` 182 183 ##### `result` 184 185 The `result` object is output after a transition is executed. It includes 186 information about the post-transition environment. 187 188 ```go 189 type ExecutionResult struct { 190 StateRoot common.Hash `json:"stateRoot"` 191 TxRoot common.Hash `json:"txRoot"` 192 ReceiptRoot common.Hash `json:"receiptsRoot"` 193 LogsHash common.Hash `json:"logsHash"` 194 Bloom types.Bloom `json:"logsBloom"` 195 Receipts types.Receipts `json:"receipts"` 196 Rejected []*rejectedTx `json:"rejected,omitempty"` 197 Difficulty *big.Int `json:"currentDifficulty"` 198 GasUsed uint64 `json:"gasUsed"` 199 BaseFee *big.Int `json:"currentBaseFee,omitempty"` 200 } 201 ``` 202 203 #### Error codes and output 204 205 All logging should happen against the `stderr`. 206 There are a few (not many) errors that can occur, those are defined below. 207 208 ##### EVM-based errors (`2` to `9`) 209 210 - Other EVM error. Exit code `2` 211 - Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`. 212 - Block history is not supplied, but needed for a `BLOCKHASH` operation. If `BLOCKHASH` 213 is invoked targeting a block which history has not been provided for, the program will 214 exit with code `4`. 215 216 ##### IO errors (`10`-`20`) 217 218 - Invalid input json: the supplied data could not be marshalled. 219 The program will exit with code `10` 220 - IO problems: failure to load or save files, the program will exit with code `11` 221 222 ``` 223 # This should exit with 3 224 ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Frontier+1346 2>/dev/null 225 EOF 226 ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Frontier+1346 2>/dev/null 227 exitcode=$? 228 if [ $exitcode != 3 ]; then 229 echo "Failed, exitcode should be 3,was $exitcode" 230 else 231 echo "exitcode:$exitcode OK" 232 fi 233 cat << "EOF" 234 ``` 235 #### Forks 236 ### Basic usage 237 238 The chain configuration to be used for a transition is specified via the 239 `--state.fork` CLI flag. A list of possible values and configurations can be 240 found in [`tests/init.go`](tests/init.go). 241 242 #### Examples 243 ##### Basic usage 244 245 Invoking it with the provided example files 246 EOF 247 cmd="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin" 248 tick;echo "$cmd"; tick 249 $cmd 2>/dev/null 250 echo "Two resulting files:" 251 echo "" 252 showjson alloc.json 253 showjson result.json 254 echo "" 255 256 echo "We can make them spit out the data to e.g. \`stdout\` like this:" 257 cmd="./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 --state.fork=Berlin" 258 tick;echo "$cmd"; tick 259 output=`$cmd 2>/dev/null` 260 echo "Output:" 261 echo "${ticks}json" 262 echo "$output" 263 echo "$ticks" 264 265 cat << "EOF" 266 267 #### About Ommers 268 269 Mining rewards and ommer rewards might need to be added. This is how those are applied: 270 271 - `block_reward` is the block mining reward for the miner (`0xaa`), of a block at height `N`. 272 - For each ommer (mined by `0xbb`), with blocknumber `N-delta` 273 - (where `delta` is the difference between the current block and the ommer) 274 - The account `0xbb` (ommer miner) is awarded `(8-delta)/ 8 * block_reward` 275 - The account `0xaa` (block miner) is awarded `block_reward / 32` 276 277 To make `t8n` apply these, the following inputs are required: 278 279 - `--state.reward` 280 - For ethash, it is `5000000000000000000` `wei`, 281 - If this is not defined, mining rewards are not applied, 282 - A value of `0` is valid, and causes accounts to be 'touched'. 283 - For each ommer, the tool needs to be given an `addres\` and a `delta`. This 284 is done via the `ommers` field in `env`. 285 286 Note: the tool does not verify that e.g. the normal uncle rules apply, 287 and allows e.g two uncles at the same height, or the uncle-distance. This means that 288 the tool allows for negative uncle reward (distance > 8) 289 290 Example: 291 EOF 292 293 showjson ./testdata/5/env.json 294 295 echo "When applying this, using a reward of \`0x08\`" 296 cmd="./evm t8n --input.alloc=./testdata/5/alloc.json -input.txs=./testdata/5/txs.json --input.env=./testdata/5/env.json --output.alloc=stdout --state.reward=0x80 --state.fork=Berlin" 297 output=`$cmd 2>/dev/null` 298 echo "Output:" 299 echo "${ticks}json" 300 echo "$output" 301 echo "$ticks" 302 303 echo "#### Future EIPS" 304 echo "" 305 echo "It is also possible to experiment with future eips that are not yet defined in a hard fork." 306 echo "Example, putting EIP-1344 into Frontier: " 307 cmd="./evm t8n --state.fork=Frontier+1344 --input.pre=./testdata/1/pre.json --input.txs=./testdata/1/txs.json --input.env=/testdata/1/env.json" 308 tick;echo "$cmd"; tick 309 echo "" 310 311 echo "#### Block history" 312 echo "" 313 echo "The \`BLOCKHASH\` opcode requires blockhashes to be provided by the caller, inside the \`env\`." 314 echo "If a required blockhash is not provided, the exit code should be \`4\`:" 315 echo "Example where blockhashes are provided: " 316 demo "./evm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace --state.fork=Berlin" 317 cmd="cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2" 318 tick && echo $cmd && tick 319 echo "$ticks" 320 cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 321 echo "$ticks" 322 echo "" 323 324 echo "In this example, the caller has not provided the required blockhash:" 325 cmd="./evm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace --state.fork=Berlin" 326 tick && echo $cmd && $cmd 2>&1 327 errc=$? 328 tick 329 echo "Error code: $errc" 330 echo "" 331 332 echo "#### Chaining" 333 echo "" 334 echo "Another thing that can be done, is to chain invocations:" 335 cmd1="./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin --output.alloc=stdout" 336 cmd2="./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json --state.fork=Berlin" 337 echo "$ticks" 338 echo "$cmd1 | $cmd2" 339 output=$($cmd1 | $cmd2 ) 340 echo $output 341 echo "$ticks" 342 echo "What happened here, is that we first applied two identical transactions, so the second one was rejected. " 343 echo "Then, taking the poststate alloc as the input for the next state, we tried again to include" 344 echo "the same two transactions: this time, both failed due to too low nonce." 345 echo "" 346 echo "In order to meaningfully chain invocations, one would need to provide meaningful new \`env\`, otherwise the" 347 echo "actual blocknumber (exposed to the EVM) would not increase." 348 echo "" 349 350 echo "#### Transactions in RLP form" 351 echo "" 352 echo "It is possible to provide already-signed transactions as input to, using an \`input.txs\` which ends with the \`rlp\` suffix." 353 echo "The input format for RLP-form transactions is _identical_ to the _output_ format for block bodies. Therefore, it's fully possible" 354 echo "to use the evm to go from \`json\` input to \`rlp\` input." 355 echo "" 356 echo "The following command takes **json** the transactions in \`./testdata/13/txs.json\` and signs them. After execution, they are output to \`signed_txs.rlp\`.:" 357 cmd="./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" 358 echo "$ticks" 359 echo $cmd 360 $cmd 2>&1 361 echo "$ticks" 362 echo "" 363 echo "The \`output.body\` is the rlp-list of transactions, encoded in hex and placed in a string a'la \`json\` encoding rules:" 364 demo "cat signed_txs.rlp" 365 echo "We can use \`rlpdump\` to check what the contents are: " 366 echo "$ticks" 367 echo "rlpdump -hex \$(cat signed_txs.rlp | jq -r )" 368 rlpdump -hex $(cat signed_txs.rlp | jq -r ) 369 echo "$ticks" 370 echo "Now, we can now use those (or any other already signed transactions), as input, like so: " 371 cmd="./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" 372 echo "$ticks" 373 echo $cmd 374 $cmd 2>&1 375 echo "$ticks" 376 echo "You might have noticed that the results from these two invocations were stored in two separate files. " 377 echo "And we can now finally check that they match." 378 echo "$ticks" 379 echo "cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot" 380 cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot 381 echo "$ticks" 382 383 cat << "EOF" 384 385 ## Transaction tool 386 387 The transaction tool is used to perform static validity checks on transactions such as: 388 * intrinsic gas calculation 389 * max values on integers 390 * fee semantics, such as `maxFeePerGas < maxPriorityFeePerGas` 391 * newer tx types on old forks 392 393 ### Examples 394 395 EOF 396 397 cmd="./evm t9n --state.fork Homestead --input.txs testdata/15/signed_txs.rlp" 398 tick;echo "$cmd"; 399 $cmd 2>/dev/null 400 tick 401 402 cmd="./evm t9n --state.fork London --input.txs testdata/15/signed_txs.rlp" 403 tick;echo "$cmd"; 404 $cmd 2>/dev/null 405 tick 406 407 cat << "EOF" 408 ## Block builder tool (b11r) 409 410 The `evm b11r` tool is used to assemble and seal full block rlps. 411 412 ### Specification 413 414 #### Command line params 415 416 Command line params that need to be supported are: 417 418 ``` 419 --input.header value `stdin` or file name of where to find the block header to use. (default: "header.json") 420 --input.ommers value `stdin` or file name of where to find the list of ommer header RLPs to use. 421 --input.txs value `stdin` or file name of where to find the transactions list in RLP form. (default: "txs.rlp") 422 --output.basedir value Specifies where output files are placed. Will be created if it does not exist. 423 --output.block value Determines where to put the alloc of the post-state. (default: "block.json") 424 <file> - into the file <file> 425 `stdout` - into the stdout output 426 `stderr` - into the stderr output 427 --seal.clique value Seal block with Clique. `stdin` or file name of where to find the Clique sealing data. 428 --seal.ethash Seal block with ethash. (default: false) 429 --seal.ethash.dir value Path to ethash DAG. If none exists, a new DAG will be generated. 430 --seal.ethash.mode value Defines the type and amount of PoW verification an ethash engine makes. (default: "normal") 431 --verbosity value Sets the verbosity level. (default: 3) 432 ``` 433 434 #### Objects 435 436 ##### `header` 437 438 The `header` object is a consensus header. 439 440 ```go= 441 type Header struct { 442 ParentHash common.Hash `json:"parentHash"` 443 OmmerHash *common.Hash `json:"sha3Uncles"` 444 Coinbase *common.Address `json:"miner"` 445 Root common.Hash `json:"stateRoot" gencodec:"required"` 446 TxHash *common.Hash `json:"transactionsRoot"` 447 ReceiptHash *common.Hash `json:"receiptsRoot"` 448 Bloom types.Bloom `json:"logsBloom"` 449 Difficulty *big.Int `json:"difficulty"` 450 Number *big.Int `json:"number" gencodec:"required"` 451 GasLimit uint64 `json:"gasLimit" gencodec:"required"` 452 GasUsed uint64 `json:"gasUsed"` 453 Time uint64 `json:"timestamp" gencodec:"required"` 454 Extra []byte `json:"extraData"` 455 MixDigest common.Hash `json:"mixHash"` 456 Nonce *types.BlockNonce `json:"nonce"` 457 BaseFee *big.Int `json:"baseFeePerGas"` 458 } 459 ``` 460 #### `ommers` 461 462 The `ommers` object is a list of RLP-encoded ommer blocks in hex 463 representation. 464 465 ```go= 466 type Ommers []string 467 ``` 468 469 #### `txs` 470 471 The `txs` object is a list of RLP-encoded transactions in hex representation. 472 473 ```go= 474 type Txs []string 475 ``` 476 477 #### `clique` 478 479 The `clique` object provides the neccesary information to complete a clique 480 seal of the block. 481 482 ```go= 483 var CliqueInfo struct { 484 Key *common.Hash `json:"secretKey"` 485 Voted *common.Address `json:"voted"` 486 Authorize *bool `json:"authorize"` 487 Vanity common.Hash `json:"vanity"` 488 } 489 ``` 490 491 #### `output` 492 493 The `output` object contains two values, the block RLP and the block hash. 494 495 ```go= 496 type BlockInfo struct { 497 Rlp []byte `json:"rlp"` 498 Hash common.Hash `json:"hash"` 499 } 500 ``` 501 502 ## A Note on Encoding 503 504 The encoding of values for `evm` utility attempts to be relatively flexible. It 505 generally supports hex-encoded or decimal-encoded numeric values, and 506 hex-encoded byte values (like `common.Address`, `common.Hash`, etc). When in 507 doubt, the [`execution-apis`](https://github.com/ethereum/execution-apis) way 508 of encoding should always be accepted. 509 510 ## Testing 511 512 There are many test cases in the [`cmd/evm/testdata`](./testdata) directory. 513 These fixtures are used to power the `t8n` tests in 514 [`t8n_test.go`](./t8n_test.go). The best way to verify correctness of new `evm` 515 implementations is to execute these and verify the output and error codes match 516 the expected values. 517 518 EOF