github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/eth/tracers/tracers_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:39</date> 10 //</624342638492913664> 11 12 13 package tracers 14 15 import ( 16 "encoding/json" 17 "io/ioutil" 18 "math/big" 19 "path/filepath" 20 "reflect" 21 "strings" 22 "testing" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/common/hexutil" 26 "github.com/ethereum/go-ethereum/common/math" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/core/vm" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/rlp" 32 "github.com/ethereum/go-ethereum/tests" 33 ) 34 35 //要生成新的calltracer测试,请将下面的maketest方法复制粘贴到 36 //一个geth控制台,用要导出的事务散列调用它。 37 38 /* 39 //maketest通过运行预状态重新组装和 40 //调用trace run,将收集到的所有信息组装到一个测试用例中。 41 var maketest=功能(tx,倒带) 42 //从块、事务和预存数据生成Genesis块 43 var block=eth.getblock(eth.getTransaction(tx).blockHash); 44 var genesis=eth.getblock(block.parenthash); 45 46 删除genesis.gasused; 47 删除genesis.logsbloom; 48 删除genesis.parenthash; 49 删除genesis.receiptsroot; 50 删除Genesis.sha3uncles; 51 删除genesis.size; 52 删除genesis.transactions; 53 删除genesis.transactionsroot; 54 删除genesis.uncles; 55 56 genesis.gaslimit=genesis.gaslimit.toString(); 57 genesis.number=genesis.number.toString(); 58 genesis.timestamp=genesis.timestamp.toString(); 59 60 genesis.alloc=debug.traceTransaction(tx,tracer:“prestatedtracer”,rewind:rewind); 61 for(genesis.alloc中的var键) 62 genesis.alloc[key].nonce=genesis.alloc[key].nonce.toString(); 63 } 64 genesis.config=admin.nodeinfo.protocols.eth.config; 65 66 //生成调用跟踪并生成测试输入 67 var result=debug.traceTransaction(tx,tracer:“calltracer”,rewind:rewind); 68 删除result.time; 69 70 console.log(json.stringify( 71 创世纪:创世纪, 72 语境:{ 73 编号:block.number.toString(), 74 困难:障碍。困难, 75 timestamp:block.timestamp.toString(), 76 gaslimit:block.gaslimit.toString(), 77 矿工:block.miner, 78 } 79 输入:eth.getrawtransaction(tx) 80 结果: 81 },NULL,2); 82 } 83 **/ 84 85 86 //CallTrace是CallTracer运行的结果。 87 type callTrace struct { 88 Type string `json:"type"` 89 From common.Address `json:"from"` 90 To common.Address `json:"to"` 91 Input hexutil.Bytes `json:"input"` 92 Output hexutil.Bytes `json:"output"` 93 Gas *hexutil.Uint64 `json:"gas,omitempty"` 94 GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` 95 Value *hexutil.Big `json:"value,omitempty"` 96 Error string `json:"error,omitempty"` 97 Calls []callTrace `json:"calls,omitempty"` 98 } 99 100 type callContext struct { 101 Number math.HexOrDecimal64 `json:"number"` 102 Difficulty *math.HexOrDecimal256 `json:"difficulty"` 103 Time math.HexOrDecimal64 `json:"timestamp"` 104 GasLimit math.HexOrDecimal64 `json:"gasLimit"` 105 Miner common.Address `json:"miner"` 106 } 107 108 //CallTracerTest定义一个测试来检查调用跟踪程序。 109 type callTracerTest struct { 110 Genesis *core.Genesis `json:"genesis"` 111 Context *callContext `json:"context"` 112 Input string `json:"input"` 113 Result *callTrace `json:"result"` 114 } 115 116 //迭代跟踪测试工具中的所有输入输出数据集,并 117 //对它们运行javascript跟踪程序。 118 func TestCallTracer(t *testing.T) { 119 files, err := ioutil.ReadDir("testdata") 120 if err != nil { 121 t.Fatalf("failed to retrieve tracer test suite: %v", err) 122 } 123 for _, file := range files { 124 if !strings.HasPrefix(file.Name(), "call_tracer_") { 125 continue 126 } 127 file := file //捕获范围变量 128 t.Run(camel(strings.TrimSuffix(strings.TrimPrefix(file.Name(), "call_tracer_"), ".json")), func(t *testing.T) { 129 t.Parallel() 130 131 //找到呼叫追踪测试,从磁盘读取 132 blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name())) 133 if err != nil { 134 t.Fatalf("failed to read testcase: %v", err) 135 } 136 test := new(callTracerTest) 137 if err := json.Unmarshal(blob, test); err != nil { 138 t.Fatalf("failed to parse testcase: %v", err) 139 } 140 //使用给定的预状态配置区块链 141 tx := new(types.Transaction) 142 if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { 143 t.Fatalf("failed to parse testcase input: %v", err) 144 } 145 signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) 146 origin, _ := signer.Sender(tx) 147 148 context := vm.Context{ 149 CanTransfer: core.CanTransfer, 150 Transfer: core.Transfer, 151 Origin: origin, 152 Coinbase: test.Context.Miner, 153 BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), 154 Time: new(big.Int).SetUint64(uint64(test.Context.Time)), 155 Difficulty: (*big.Int)(test.Context.Difficulty), 156 GasLimit: uint64(test.Context.GasLimit), 157 GasPrice: tx.GasPrice(), 158 } 159 statedb := tests.MakePreState(ethdb.NewMemDatabase(), test.Genesis.Alloc) 160 161 //创建跟踪程序、EVM环境并运行它 162 tracer, err := New("callTracer") 163 if err != nil { 164 t.Fatalf("failed to create call tracer: %v", err) 165 } 166 evm := vm.NewEVM(context, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) 167 168 msg, err := tx.AsMessage(signer) 169 if err != nil { 170 t.Fatalf("failed to prepare transaction for tracing: %v", err) 171 } 172 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 173 if _, _, _, err = st.TransitionDb(); err != nil { 174 t.Fatalf("failed to execute transaction: %v", err) 175 } 176 //检索跟踪结果并与标准具进行比较 177 res, err := tracer.GetResult() 178 if err != nil { 179 t.Fatalf("failed to retrieve trace result: %v", err) 180 } 181 ret := new(callTrace) 182 if err := json.Unmarshal(res, ret); err != nil { 183 t.Fatalf("failed to unmarshal trace result: %v", err) 184 } 185 if !reflect.DeepEqual(ret, test.Result) { 186 t.Fatalf("trace mismatch: have %+v, want %+v", ret, test.Result) 187 } 188 }) 189 } 190 } 191