github.com/aquanetwork/aquachain@v1.7.8/aqua/tracers/tracers_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // +build gccgo cgo !nocgo 18 19 package tracers 20 21 import ( 22 "encoding/json" 23 "io/ioutil" 24 "math/big" 25 "path/filepath" 26 "reflect" 27 "strings" 28 "testing" 29 30 "gitlab.com/aquachain/aquachain/aquadb" 31 "gitlab.com/aquachain/aquachain/common" 32 "gitlab.com/aquachain/aquachain/common/hexutil" 33 "gitlab.com/aquachain/aquachain/common/math" 34 "gitlab.com/aquachain/aquachain/core" 35 "gitlab.com/aquachain/aquachain/core/types" 36 "gitlab.com/aquachain/aquachain/core/vm" 37 "gitlab.com/aquachain/aquachain/opt/tests" 38 "gitlab.com/aquachain/aquachain/rlp" 39 ) 40 41 // To generate a new callTracer test, copy paste the makeTest method below into 42 // a Geth console and call it with a transaction hash you which to export. 43 44 /* 45 // makeTest generates a callTracer test by running a prestate reassembled and a 46 // call trace run, assembling all the gathered information into a test case. 47 var makeTest = function(tx, rewind) { 48 // Generate the genesis block from the block, transaction and prestate data 49 var block = eth.getBlock(eth.getTransaction(tx).blockHash); 50 var genesis = eth.getBlock(block.parentHash); 51 52 delete genesis.gasUsed; 53 delete genesis.logsBloom; 54 delete genesis.parentHash; 55 delete genesis.receiptsRoot; 56 delete genesis.sha3Uncles; 57 delete genesis.size; 58 delete genesis.transactions; 59 delete genesis.transactionsRoot; 60 delete genesis.uncles; 61 62 genesis.gasLimit = genesis.gasLimit.toString(); 63 genesis.number = genesis.number.toString(); 64 genesis.timestamp = genesis.timestamp.toString(); 65 66 genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind}); 67 for (var key in genesis.alloc) { 68 genesis.alloc[key].nonce = genesis.alloc[key].nonce.toString(); 69 } 70 genesis.config = admin.nodeInfo.protocols.eth.config; 71 72 // Generate the call trace and produce the test input 73 var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind}); 74 delete result.time; 75 76 console.log(JSON.stringify({ 77 genesis: genesis, 78 context: { 79 number: block.number.toString(), 80 difficulty: block.difficulty, 81 timestamp: block.timestamp.toString(), 82 gasLimit: block.gasLimit.toString(), 83 miner: block.miner, 84 }, 85 input: eth.getRawTransaction(tx), 86 result: result, 87 }, null, 2)); 88 } 89 */ 90 91 // callTrace is the result of a callTracer run. 92 type callTrace struct { 93 Type string `json:"type"` 94 From common.Address `json:"from"` 95 To common.Address `json:"to"` 96 Input hexutil.Bytes `json:"input"` 97 Output hexutil.Bytes `json:"output"` 98 Gas *hexutil.Uint64 `json:"gas,omitempty"` 99 GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` 100 Value *hexutil.Big `json:"value,omitempty"` 101 Error string `json:"error,omitempty"` 102 Calls []callTrace `json:"calls,omitempty"` 103 } 104 105 type callContext struct { 106 Number math.HexOrDecimal64 `json:"number"` 107 Difficulty *math.HexOrDecimal256 `json:"difficulty"` 108 Time math.HexOrDecimal64 `json:"timestamp"` 109 GasLimit math.HexOrDecimal64 `json:"gasLimit"` 110 Miner common.Address `json:"miner"` 111 } 112 113 // callTracerTest defines a single test to check the call tracer against. 114 type callTracerTest struct { 115 Genesis *core.Genesis `json:"genesis"` 116 Context *callContext `json:"context"` 117 Input string `json:"input"` 118 Result *callTrace `json:"result"` 119 } 120 121 // Iterates over all the input-output datasets in the tracer test harness and 122 // runs the JavaScript tracers against them. 123 func TestCallTracer(t *testing.T) { 124 files, err := ioutil.ReadDir("testdata") 125 if err != nil { 126 t.Fatalf("failed to retrieve tracer test suite: %v", err) 127 } 128 for _, file := range files { 129 if !strings.HasPrefix(file.Name(), "call_tracer_") { 130 continue 131 } 132 file := file // capture range variable 133 t.Run(camel(strings.TrimSuffix(strings.TrimPrefix(file.Name(), "call_tracer_"), ".json")), func(t *testing.T) { 134 t.Parallel() 135 136 // Call tracer test found, read if from disk 137 blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name())) 138 if err != nil { 139 t.Fatalf("failed to read testcase: %v", err) 140 } 141 test := new(callTracerTest) 142 if err := json.Unmarshal(blob, test); err != nil { 143 t.Fatalf("failed to parse testcase: %v", err) 144 } 145 // Configure a blockchain with the given prestate 146 tx := new(types.Transaction) 147 if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { 148 t.Fatalf("failed to parse testcase input: %v", err) 149 } 150 signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) 151 origin, _ := signer.Sender(tx) 152 153 context := vm.Context{ 154 CanTransfer: core.CanTransfer, 155 Transfer: core.Transfer, 156 Origin: origin, 157 Coinbase: test.Context.Miner, 158 BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), 159 Time: new(big.Int).SetUint64(uint64(test.Context.Time)), 160 Difficulty: (*big.Int)(test.Context.Difficulty), 161 GasLimit: uint64(test.Context.GasLimit), 162 GasPrice: tx.GasPrice(), 163 } 164 statedb := tests.MakePreState(aquadb.NewMemDatabase(), test.Genesis.Alloc) 165 166 // Create the tracer, the EVM environment and run it 167 tracer, err := New("callTracer") 168 if err != nil { 169 t.Fatalf("failed to create call tracer: %v", err) 170 } 171 evm := vm.NewEVM(context, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) 172 173 msg, err := tx.AsMessage(signer) 174 if err != nil { 175 t.Fatalf("failed to prepare transaction for tracing: %v", err) 176 } 177 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 178 if _, _, _, err = st.TransitionDb(); err != nil { 179 t.Fatalf("failed to execute transaction: %v", err) 180 } 181 // Retrieve the trace result and compare against the etalon 182 res, err := tracer.GetResult() 183 if err != nil { 184 t.Fatalf("failed to retrieve trace result: %v", err) 185 } 186 ret := new(callTrace) 187 if err := json.Unmarshal(res, ret); err != nil { 188 t.Fatalf("failed to unmarshal trace result: %v", err) 189 } 190 if !reflect.DeepEqual(ret, test.Result) { 191 t.Fatalf("trace mismatch: have %+v, want %+v", ret, test.Result) 192 } 193 }) 194 } 195 }