github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/eth/tracers/tracers_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package tracers 19 20 import ( 21 "crypto/ecdsa" 22 "crypto/rand" 23 "encoding/json" 24 "io/ioutil" 25 "math/big" 26 "path/filepath" 27 "reflect" 28 "strings" 29 "testing" 30 31 "github.com/AigarNetwork/aigar/common" 32 "github.com/AigarNetwork/aigar/common/hexutil" 33 "github.com/AigarNetwork/aigar/common/math" 34 "github.com/AigarNetwork/aigar/core" 35 "github.com/AigarNetwork/aigar/core/rawdb" 36 "github.com/AigarNetwork/aigar/core/types" 37 "github.com/AigarNetwork/aigar/core/vm" 38 "github.com/AigarNetwork/aigar/crypto" 39 "github.com/AigarNetwork/aigar/params" 40 "github.com/AigarNetwork/aigar/rlp" 41 "github.com/AigarNetwork/aigar/tests" 42 ) 43 44 // To generate a new callTracer test, copy paste the makeTest method below into 45 // a Geth console and call it with a transaction hash you which to export. 46 47 /* 48 // makeTest generates a callTracer test by running a prestate reassembled and a 49 // call trace run, assembling all the gathered information into a test case. 50 var makeTest = function(tx, rewind) { 51 // Generate the genesis block from the block, transaction and prestate data 52 var block = eth.getBlock(eth.getTransaction(tx).blockHash); 53 var genesis = eth.getBlock(block.parentHash); 54 55 delete genesis.gasUsed; 56 delete genesis.logsBloom; 57 delete genesis.parentHash; 58 delete genesis.receiptsRoot; 59 delete genesis.sha3Uncles; 60 delete genesis.size; 61 delete genesis.transactions; 62 delete genesis.transactionsRoot; 63 delete genesis.uncles; 64 65 genesis.gasLimit = genesis.gasLimit.toString(); 66 genesis.number = genesis.number.toString(); 67 genesis.timestamp = genesis.timestamp.toString(); 68 69 genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); 70 for (var key in genesis.alloc) { 71 genesis.alloc[key].nonce = genesis.alloc[key].nonce.toString(); 72 } 73 genesis.config = admin.nodeInfo.protocols.eth.config; 74 75 // Generate the call trace and produce the test input 76 var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); 77 delete result.time; 78 79 console.log(JSON.stringify({ 80 genesis: genesis, 81 context: { 82 number: block.number.toString(), 83 difficulty: block.difficulty, 84 timestamp: block.timestamp.toString(), 85 gasLimit: block.gasLimit.toString(), 86 miner: block.miner, 87 }, 88 input: eth.getRawTransaction(tx), 89 result: result, 90 }, null, 2)); 91 } 92 */ 93 94 // callTrace is the result of a callTracer run. 95 type callTrace struct { 96 Type string `json:"type"` 97 From common.Address `json:"from"` 98 To common.Address `json:"to"` 99 Input hexutil.Bytes `json:"input"` 100 Output hexutil.Bytes `json:"output"` 101 Gas *hexutil.Uint64 `json:"gas,omitempty"` 102 GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` 103 Value *hexutil.Big `json:"value,omitempty"` 104 Error string `json:"error,omitempty"` 105 Calls []callTrace `json:"calls,omitempty"` 106 } 107 108 type callContext struct { 109 Number math.HexOrDecimal64 `json:"number"` 110 Difficulty *math.HexOrDecimal256 `json:"difficulty"` 111 Time math.HexOrDecimal64 `json:"timestamp"` 112 GasLimit math.HexOrDecimal64 `json:"gasLimit"` 113 Miner common.Address `json:"miner"` 114 } 115 116 // callTracerTest defines a single test to check the call tracer against. 117 type callTracerTest struct { 118 Genesis *core.Genesis `json:"genesis"` 119 Context *callContext `json:"context"` 120 Input string `json:"input"` 121 Result *callTrace `json:"result"` 122 } 123 124 func TestPrestateTracerCreate2(t *testing.T) { 125 unsignedTx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), 126 new(big.Int), 5000000, big.NewInt(1), []byte{}) 127 128 privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) 129 if err != nil { 130 t.Fatalf("err %v", err) 131 } 132 signer := types.NewEIP155Signer(big.NewInt(1)) 133 tx, err := types.SignTx(unsignedTx, signer, privateKeyECDSA) 134 if err != nil { 135 t.Fatalf("err %v", err) 136 } 137 /** 138 This comes from one of the test-vectors on the Skinny Create2 - EIP 139 140 address 0x00000000000000000000000000000000deadbeef 141 salt 0x00000000000000000000000000000000000000000000000000000000cafebabe 142 init_code 0xdeadbeef 143 gas (assuming no mem expansion): 32006 144 result: 0x60f3f640a8508fC6a86d45DF051962668E1e8AC7 145 */ 146 origin, _ := signer.Sender(tx) 147 context := vm.Context{ 148 CanTransfer: core.CanTransfer, 149 Transfer: core.Transfer, 150 Origin: origin, 151 Coinbase: common.Address{}, 152 BlockNumber: new(big.Int).SetUint64(8000000), 153 Time: new(big.Int).SetUint64(5), 154 Difficulty: big.NewInt(0x30000), 155 GasLimit: uint64(6000000), 156 GasPrice: big.NewInt(1), 157 } 158 alloc := core.GenesisAlloc{} 159 160 // The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns 161 // the address 162 alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{ 163 Nonce: 1, 164 Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"), 165 Balance: big.NewInt(1), 166 } 167 alloc[origin] = core.GenesisAccount{ 168 Nonce: 1, 169 Code: []byte{}, 170 Balance: big.NewInt(500000000000000), 171 } 172 statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc) 173 174 // Create the tracer, the EVM environment and run it 175 tracer, err := New("prestateTracer") 176 if err != nil { 177 t.Fatalf("failed to create call tracer: %v", err) 178 } 179 evm := vm.NewEVM(context, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) 180 181 msg, err := tx.AsMessage(signer) 182 if err != nil { 183 t.Fatalf("failed to prepare transaction for tracing: %v", err) 184 } 185 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 186 if _, _, _, err = st.TransitionDb(); err != nil { 187 t.Fatalf("failed to execute transaction: %v", err) 188 } 189 // Retrieve the trace result and compare against the etalon 190 res, err := tracer.GetResult() 191 if err != nil { 192 t.Fatalf("failed to retrieve trace result: %v", err) 193 } 194 ret := make(map[string]interface{}) 195 if err := json.Unmarshal(res, &ret); err != nil { 196 t.Fatalf("failed to unmarshal trace result: %v", err) 197 } 198 if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has { 199 t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result") 200 } 201 } 202 203 // Iterates over all the input-output datasets in the tracer test harness and 204 // runs the JavaScript tracers against them. 205 func TestCallTracer(t *testing.T) { 206 files, err := ioutil.ReadDir("testdata") 207 if err != nil { 208 t.Fatalf("failed to retrieve tracer test suite: %v", err) 209 } 210 for _, file := range files { 211 if !strings.HasPrefix(file.Name(), "call_tracer_") { 212 continue 213 } 214 file := file // capture range variable 215 t.Run(camel(strings.TrimSuffix(strings.TrimPrefix(file.Name(), "call_tracer_"), ".json")), func(t *testing.T) { 216 t.Parallel() 217 218 // Call tracer test found, read if from disk 219 blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name())) 220 if err != nil { 221 t.Fatalf("failed to read testcase: %v", err) 222 } 223 test := new(callTracerTest) 224 if err := json.Unmarshal(blob, test); err != nil { 225 t.Fatalf("failed to parse testcase: %v", err) 226 } 227 // Configure a blockchain with the given prestate 228 tx := new(types.Transaction) 229 if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { 230 t.Fatalf("failed to parse testcase input: %v", err) 231 } 232 signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) 233 origin, _ := signer.Sender(tx) 234 235 context := vm.Context{ 236 CanTransfer: core.CanTransfer, 237 Transfer: core.Transfer, 238 Origin: origin, 239 Coinbase: test.Context.Miner, 240 BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), 241 Time: new(big.Int).SetUint64(uint64(test.Context.Time)), 242 Difficulty: (*big.Int)(test.Context.Difficulty), 243 GasLimit: uint64(test.Context.GasLimit), 244 GasPrice: tx.GasPrice(), 245 } 246 statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc) 247 248 // Create the tracer, the EVM environment and run it 249 tracer, err := New("callTracer") 250 if err != nil { 251 t.Fatalf("failed to create call tracer: %v", err) 252 } 253 evm := vm.NewEVM(context, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) 254 255 msg, err := tx.AsMessage(signer) 256 if err != nil { 257 t.Fatalf("failed to prepare transaction for tracing: %v", err) 258 } 259 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 260 if _, _, _, err = st.TransitionDb(); err != nil { 261 t.Fatalf("failed to execute transaction: %v", err) 262 } 263 // Retrieve the trace result and compare against the etalon 264 res, err := tracer.GetResult() 265 if err != nil { 266 t.Fatalf("failed to retrieve trace result: %v", err) 267 } 268 ret := new(callTrace) 269 if err := json.Unmarshal(res, ret); err != nil { 270 t.Fatalf("failed to unmarshal trace result: %v", err) 271 } 272 273 if !reflect.DeepEqual(ret, test.Result) { 274 t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) 275 } 276 }) 277 } 278 }