github.com/theQRL/go-zond@v0.2.1/cmd/zvm/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 # ZVM tool 29 30 The ZVM tool provides a few useful subcommands to facilitate testing at the ZVM 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 `zvm 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 \`gzond\`-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 ./zvm 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 Seed []byte `json:"seed"` 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 CurrentRandom *big.Int `json:"currentRandom"` 107 CurrentBaseFee *big.Int `json:"currentBaseFee"` 108 ParentGasUsed uint64 `json:"parentGasUsed"` 109 ParentGasLimit uint64 `json:"parentGasLimit"` 110 ParentTimestamp uint64 `json:"parentTimestamp"` 111 BlockHashes map[uint64]common.Hash `json:"blockHashes"` 112 } 113 type Withdrawal struct { 114 Index uint64 `json:"index"` 115 ValidatorIndex uint64 `json:"validatorIndex"` 116 Recipient common.Address `json:"recipient"` 117 Amount *big.Int `json:"amount"` 118 } 119 ``` 120 121 ##### `txs` 122 123 The `txs` object is an array of any of the transaction types: `DynamicFeeTx`. 124 125 ```go 126 type AccessList []AccessTuple 127 type AccessTuple struct { 128 Address common.Address `json:"address" gencodec:"required"` 129 StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"` 130 } 131 type DynamicFeeTx struct { 132 ChainID *big.Int `json:"chainId"` 133 Nonce uint64 `json:"nonce"` 134 GasTipCap *big.Int `json:"maxPriorityFeePerGas"` 135 GasFeeCap *big.Int `json:"maxFeePerGas"` 136 Gas uint64 `json:"gas"` 137 To *common.Address `json:"to"` 138 Value *big.Int `json:"value"` 139 Data []byte `json:"data"` 140 AccessList AccessList `json:"accessList"` 141 PublicKey []byte `json:"publicKey"` 142 Signature []byte `json:"signature"` 143 Seed *common.Hash `json:"seed"` 144 } 145 ``` 146 147 ##### `result` 148 149 The `result` object is output after a transition is executed. It includes 150 information about the post-transition environment. 151 152 ```go 153 type ExecutionResult struct { 154 StateRoot common.Hash `json:"stateRoot"` 155 TxRoot common.Hash `json:"txRoot"` 156 ReceiptRoot common.Hash `json:"receiptsRoot"` 157 LogsHash common.Hash `json:"logsHash"` 158 Bloom types.Bloom `json:"logsBloom"` 159 Receipts types.Receipts `json:"receipts"` 160 Rejected []*rejectedTx `json:"rejected,omitempty"` 161 GasUsed uint64 `json:"gasUsed"` 162 BaseFee *big.Int `json:"currentBaseFee,omitempty"` 163 } 164 ``` 165 166 #### Error codes and output 167 168 All logging should happen against the `stderr`. 169 There are a few (not many) errors that can occur, those are defined below. 170 171 ##### ZVM-based errors (`2` to `9`) 172 173 - Other ZVM error. Exit code `2` 174 - Failed configuration: when a non-supported or invalid fork was specified. Exit code `3`. 175 - Block history is not supplied, but needed for a `BLOCKHASH` operation. If `BLOCKHASH` 176 is invoked targeting a block which history has not been provided for, the program will 177 exit with code `4`. 178 179 ##### IO errors (`10`-`20`) 180 181 - Invalid input json: the supplied data could not be marshalled. 182 The program will exit with code `10` 183 - IO problems: failure to load or save files, the program will exit with code `11` 184 185 ``` 186 # This should exit with 3 187 ./zvm 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 188 EOF 189 ./zvm 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 190 exitcode=$? 191 if [ $exitcode != 3 ]; then 192 echo "Failed, exitcode should be 3,was $exitcode" 193 else 194 echo "exitcode:$exitcode OK" 195 fi 196 cat << "EOF" 197 ``` 198 #### Forks 199 ### Basic usage 200 201 The chain configuration to be used for a transition is specified via the 202 `--state.fork` CLI flag. A list of possible values and configurations can be 203 found in [`tests/init.go`](tests/init.go). 204 205 #### Examples 206 ##### Basic usage 207 208 Invoking it with the provided example files 209 EOF 210 cmd="./zvm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Berlin" 211 tick;echo "$cmd"; tick 212 $cmd 2>/dev/null 213 echo "Two resulting files:" 214 echo "" 215 showjson alloc.json 216 showjson result.json 217 echo "" 218 219 echo "We can make them spit out the data to e.g. \`stdout\` like this:" 220 cmd="./zvm 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" 221 tick;echo "$cmd"; tick 222 output=`$cmd 2>/dev/null` 223 echo "Output:" 224 echo "${ticks}json" 225 echo "$output" 226 echo "$ticks" 227 228 echo "#### Future EIPS" 229 echo "" 230 echo "It is also possible to experiment with future eips that are not yet defined in a hard fork." 231 echo "Example, putting EIP-1344 into Frontier: " 232 cmd="./zvm t8n --state.fork=Frontier+1344 --input.pre=./testdata/1/pre.json --input.txs=./testdata/1/txs.json --input.env=/testdata/1/env.json" 233 tick;echo "$cmd"; tick 234 echo "" 235 236 echo "#### Block history" 237 echo "" 238 echo "The \`BLOCKHASH\` opcode requires blockhashes to be provided by the caller, inside the \`env\`." 239 echo "If a required blockhash is not provided, the exit code should be \`4\`:" 240 echo "Example where blockhashes are provided: " 241 demo "./zvm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace --state.fork=Shanghai" 242 cmd="cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2" 243 tick && echo $cmd && tick 244 echo "$ticks" 245 cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 246 echo "$ticks" 247 echo "" 248 249 echo "In this example, the caller has not provided the required blockhash:" 250 cmd="./zvm t8n --input.alloc=./testdata/4/alloc.json --input.txs=./testdata/4/txs.json --input.env=./testdata/4/env.json --trace --state.fork=Shanghai" 251 tick && echo $cmd && $cmd 2>&1 252 errc=$? 253 tick 254 echo "Error code: $errc" 255 echo "" 256 257 echo "#### Chaining" 258 echo "" 259 echo "Another thing that can be done, is to chain invocations:" 260 cmd1="./zvm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --state.fork=Shanghai --output.alloc=stdout" 261 cmd2="./zvm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json --state.fork=Shanghai" 262 echo "$ticks" 263 echo "$cmd1 | $cmd2" 264 output=$($cmd1 | $cmd2 ) 265 echo $output 266 echo "$ticks" 267 echo "What happened here, is that we first applied two identical transactions, so the second one was rejected. " 268 echo "Then, taking the poststate alloc as the input for the next state, we tried again to include" 269 echo "the same two transactions: this time, both failed due to too low nonce." 270 echo "" 271 echo "In order to meaningfully chain invocations, one would need to provide meaningful new \`env\`, otherwise the" 272 echo "actual blocknumber (exposed to the ZVM) would not increase." 273 echo "" 274 275 echo "#### Transactions in RLP form" 276 echo "" 277 echo "It is possible to provide already-signed transactions as input to, using an \`input.txs\` which ends with the \`rlp\` suffix." 278 echo "The input format for RLP-form transactions is _identical_ to the _output_ format for block bodies. Therefore, it's fully possible" 279 echo "to use the zvm to go from \`json\` input to \`rlp\` input." 280 echo "" 281 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\`.:" 282 cmd="./zvm t8n --state.fork=Shanghai --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" 283 echo "$ticks" 284 echo $cmd 285 $cmd 2>&1 286 echo "$ticks" 287 echo "" 288 echo "The \`output.body\` is the rlp-list of transactions, encoded in hex and placed in a string a'la \`json\` encoding rules:" 289 demo "cat signed_txs.rlp" 290 echo "We can use \`rlpdump\` to check what the contents are: " 291 echo "$ticks" 292 echo "rlpdump -hex \$(cat signed_txs.rlp | jq -r )" 293 rlpdump -hex $(cat signed_txs.rlp | jq -r ) 294 echo "$ticks" 295 echo "Now, we can now use those (or any other already signed transactions), as input, like so: " 296 cmd="./zvm t8n --state.fork=Shanghai --input.alloc=./testdata/13/alloc.json --input.txs=./signed_txs.rlp --input.env=./testdata/13/env.json --output.result=alloc_rlptx.json" 297 echo "$ticks" 298 echo $cmd 299 $cmd 2>&1 300 echo "$ticks" 301 echo "You might have noticed that the results from these two invocations were stored in two separate files. " 302 echo "And we can now finally check that they match." 303 echo "$ticks" 304 echo "cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot" 305 cat alloc_jsontx.json | jq .stateRoot && cat alloc_rlptx.json | jq .stateRoot 306 echo "$ticks" 307 308 cat << "EOF" 309 310 ## Transaction tool 311 312 The transaction tool is used to perform static validity checks on transactions such as: 313 * intrinsic gas calculation 314 * max values on integers 315 * fee semantics, such as `maxFeePerGas < maxPriorityFeePerGas` 316 * newer tx types on old forks 317 318 ### Examples 319 320 EOF 321 322 cmd="./zvm t9n --state.fork Shanghai --input.txs testdata/15/signed_txs.rlp" 323 tick;echo "$cmd"; 324 $cmd 2>/dev/null 325 tick 326 327 cat << "EOF" 328 ## Block builder tool (b11r) 329 330 The `zvm b11r` tool is used to assemble and seal full block rlps. 331 332 ### Specification 333 334 #### Command line params 335 336 Command line params that need to be supported are: 337 338 ``` 339 --input.header value `stdin` or file name of where to find the block header to use. (default: "header.json") 340 --input.txs value `stdin` or file name of where to find the transactions list in RLP form. (default: "txs.rlp") 341 --output.basedir value Specifies where output files are placed. Will be created if it does not exist. 342 --output.block value Determines where to put the alloc of the post-state. (default: "block.json") 343 <file> - into the file <file> 344 `stdout` - into the stdout output 345 `stderr` - into the stderr output 346 --verbosity value Sets the verbosity level. (default: 3) 347 ``` 348 349 #### Objects 350 351 ##### `header` 352 353 The `header` object is a consensus header. 354 355 ```go= 356 type Header struct { 357 ParentHash common.Hash `json:"parentHash"` 358 Coinbase *common.Address `json:"miner"` 359 Root common.Hash `json:"stateRoot" gencodec:"required"` 360 TxHash *common.Hash `json:"transactionsRoot"` 361 ReceiptHash *common.Hash `json:"receiptsRoot"` 362 Bloom types.Bloom `json:"logsBloom"` 363 Number *big.Int `json:"number" gencodec:"required"` 364 GasLimit uint64 `json:"gasLimit" gencodec:"required"` 365 GasUsed uint64 `json:"gasUsed"` 366 Time uint64 `json:"timestamp" gencodec:"required"` 367 Extra []byte `json:"extraData"` 368 Random common.Hash `json:"prevRandao"` 369 Nonce *types.BlockNonce `json:"nonce"` 370 BaseFee *big.Int `json:"baseFeePerGas"` 371 } 372 ``` 373 #### `txs` 374 375 The `txs` object is a list of RLP-encoded transactions in hex representation. 376 377 ```go= 378 type Txs []string 379 ``` 380 381 #### `output` 382 383 The `output` object contains two values, the block RLP and the block hash. 384 385 ```go= 386 type BlockInfo struct { 387 Rlp []byte `json:"rlp"` 388 Hash common.Hash `json:"hash"` 389 } 390 ``` 391 392 ## A Note on Encoding 393 394 The encoding of values for `zvm` utility attempts to be relatively flexible. It 395 generally supports hex-encoded or decimal-encoded numeric values, and 396 hex-encoded byte values (like `common.Address`, `common.Hash`, etc). When in 397 doubt, the [`execution-apis`](https://github.com/ethereum/execution-apis) way 398 of encoding should always be accepted. 399 400 ## Testing 401 402 There are many test cases in the [`cmd/zvm/testdata`](./testdata) directory. 403 These fixtures are used to power the `t8n` tests in 404 [`t8n_test.go`](./t8n_test.go). The best way to verify correctness of new `zvm` 405 implementations is to execute these and verify the output and error codes match 406 the expected values. 407 408 EOF