github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:37</date> 10 //</624450090005696512> 11 12 13 package tracers 14 15 import ( 16 "crypto/ecdsa" 17 "crypto/rand" 18 "encoding/json" 19 "io/ioutil" 20 "math/big" 21 "path/filepath" 22 "reflect" 23 "strings" 24 "testing" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/common/hexutil" 28 "github.com/ethereum/go-ethereum/common/math" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/ethdb" 34 "github.com/ethereum/go-ethereum/params" 35 "github.com/ethereum/go-ethereum/rlp" 36 "github.com/ethereum/go-ethereum/tests" 37 ) 38 39 //要生成新的calltracer测试,请将下面的maketest方法复制粘贴到 40 //一个geth控制台,用要导出的事务散列调用它。 41 42 /* 43 //maketest通过运行预状态重新组装和 44 //调用trace run,将收集到的所有信息组装到一个测试用例中。 45 var maketest=功能(tx,倒带) 46 //从块、事务和预存数据生成Genesis块 47 var block=eth.getblock(eth.getTransaction(tx).blockHash); 48 var genesis=eth.getblock(block.parenthash); 49 50 删除genesis.gasused; 51 删除genesis.logsbloom; 52 删除genesis.parenthash; 53 删除genesis.receiptsroot; 54 删除Genesis.sha3uncles; 55 删除genesis.size; 56 删除genesis.transactions; 57 删除genesis.transactionsroot; 58 删除genesis.uncles; 59 60 genesis.gaslimit=genesis.gaslimit.toString(); 61 genesis.number=genesis.number.toString(); 62 genesis.timestamp=genesis.timestamp.toString(); 63 64 genesis.alloc=debug.traceTransaction(tx,tracer:“prestatedtracer”,rewind:rewind); 65 for(genesis.alloc中的var键) 66 genesis.alloc[key].nonce=genesis.alloc[key].nonce.toString(); 67 } 68 genesis.config=admin.nodeinfo.protocols.eth.config; 69 70 //生成调用跟踪并生成测试输入 71 var result=debug.traceTransaction(tx,tracer:“calltracer”,rewind:rewind); 72 删除result.time; 73 74 console.log(json.stringify( 75 创世纪:创世纪, 76 语境:{ 77 编号:block.number.toString(), 78 困难:障碍。困难, 79 timestamp:block.timestamp.toString(), 80 gaslimit:block.gaslimit.toString(), 81 矿工:block.miner, 82 } 83 输入:eth.getrawtransaction(tx) 84 结果: 85 },NULL,2); 86 } 87 **/ 88 89 90 //CallTrace是CallTracer运行的结果。 91 type callTrace struct { 92 Type string `json:"type"` 93 From common.Address `json:"from"` 94 To common.Address `json:"to"` 95 Input hexutil.Bytes `json:"input"` 96 Output hexutil.Bytes `json:"output"` 97 Gas *hexutil.Uint64 `json:"gas,omitempty"` 98 GasUsed *hexutil.Uint64 `json:"gasUsed,omitempty"` 99 Value *hexutil.Big `json:"value,omitempty"` 100 Error string `json:"error,omitempty"` 101 Calls []callTrace `json:"calls,omitempty"` 102 } 103 104 type callContext struct { 105 Number math.HexOrDecimal64 `json:"number"` 106 Difficulty *math.HexOrDecimal256 `json:"difficulty"` 107 Time math.HexOrDecimal64 `json:"timestamp"` 108 GasLimit math.HexOrDecimal64 `json:"gasLimit"` 109 Miner common.Address `json:"miner"` 110 } 111 112 //CallTracerTest定义一个测试来检查调用跟踪程序。 113 type callTracerTest struct { 114 Genesis *core.Genesis `json:"genesis"` 115 Context *callContext `json:"context"` 116 Input string `json:"input"` 117 Result *callTrace `json:"result"` 118 } 119 120 func TestPrestateTracerCreate2(t *testing.T) { 121 unsigned_tx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), 122 new(big.Int), 5000000, big.NewInt(1), []byte{}) 123 124 privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) 125 if err != nil { 126 t.Fatalf("err %v", err) 127 } 128 signer := types.NewEIP155Signer(big.NewInt(1)) 129 tx, err := types.SignTx(unsigned_tx, signer, privateKeyECDSA) 130 if err != nil { 131 t.Fatalf("err %v", err) 132 } 133 /* 134 这是来自瘦create2-eip上的一个测试向量 135 136 地址:0x00000000000000000000000000000000标题 137 salt 0x00000000000000000000000000000000000000000000000000000000cafebabe 138 初始化代码0XDeadBeef 139 gas (assuming no mem expansion): 32006 140 结果:0x60f3f640a8508fc6a86d45df051962668e1e8ac7 141 **/ 142 143 origin, _ := signer.Sender(tx) 144 context := vm.Context{ 145 CanTransfer: core.CanTransfer, 146 Transfer: core.Transfer, 147 Origin: origin, 148 Coinbase: common.Address{}, 149 BlockNumber: new(big.Int).SetUint64(8000000), 150 Time: new(big.Int).SetUint64(5), 151 Difficulty: big.NewInt(0x30000), 152 GasLimit: uint64(6000000), 153 GasPrice: big.NewInt(1), 154 } 155 alloc := core.GenesisAlloc{} 156 //代码将“死区”推入内存,然后其他参数,并调用create2,然后返回 157 //住址 158 alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{ 159 Nonce: 1, 160 Code: hexutil.MustDecode("0x63deadbeef60005263cafebabe6004601c6000F560005260206000F3"), 161 Balance: big.NewInt(1), 162 } 163 alloc[origin] = core.GenesisAccount{ 164 Nonce: 1, 165 Code: []byte{}, 166 Balance: big.NewInt(500000000000000), 167 } 168 statedb := tests.MakePreState(ethdb.NewMemDatabase(), alloc) 169 //创建跟踪程序、EVM环境并运行它 170 tracer, err := New("prestateTracer") 171 if err != nil { 172 t.Fatalf("failed to create call tracer: %v", err) 173 } 174 evm := vm.NewEVM(context, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) 175 176 msg, err := tx.AsMessage(signer) 177 if err != nil { 178 t.Fatalf("failed to prepare transaction for tracing: %v", err) 179 } 180 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 181 if _, _, _, err = st.TransitionDb(); err != nil { 182 t.Fatalf("failed to execute transaction: %v", err) 183 } 184 //检索跟踪结果并与标准具进行比较 185 res, err := tracer.GetResult() 186 if err != nil { 187 t.Fatalf("failed to retrieve trace result: %v", err) 188 } 189 ret := make(map[string]interface{}) 190 if err := json.Unmarshal(res, &ret); err != nil { 191 t.Fatalf("failed to unmarshal trace result: %v", err) 192 } 193 if _, has := ret["0x60f3f640a8508fc6a86d45df051962668e1e8ac7"]; !has { 194 t.Fatalf("Expected 0x60f3f640a8508fc6a86d45df051962668e1e8ac7 in result") 195 } 196 } 197 198 //迭代跟踪测试工具中的所有输入输出数据集,并 199 //对它们运行javascript跟踪程序。 200 func TestCallTracer(t *testing.T) { 201 files, err := ioutil.ReadDir("testdata") 202 if err != nil { 203 t.Fatalf("failed to retrieve tracer test suite: %v", err) 204 } 205 for _, file := range files { 206 if !strings.HasPrefix(file.Name(), "call_tracer_") { 207 continue 208 } 209 file := file //捕获范围变量 210 t.Run(camel(strings.TrimSuffix(strings.TrimPrefix(file.Name(), "call_tracer_"), ".json")), func(t *testing.T) { 211 t.Parallel() 212 213 //找到呼叫追踪测试,从磁盘读取 214 blob, err := ioutil.ReadFile(filepath.Join("testdata", file.Name())) 215 if err != nil { 216 t.Fatalf("failed to read testcase: %v", err) 217 } 218 test := new(callTracerTest) 219 if err := json.Unmarshal(blob, test); err != nil { 220 t.Fatalf("failed to parse testcase: %v", err) 221 } 222 //使用给定的预状态配置区块链 223 tx := new(types.Transaction) 224 if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil { 225 t.Fatalf("failed to parse testcase input: %v", err) 226 } 227 signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number))) 228 origin, _ := signer.Sender(tx) 229 230 context := vm.Context{ 231 CanTransfer: core.CanTransfer, 232 Transfer: core.Transfer, 233 Origin: origin, 234 Coinbase: test.Context.Miner, 235 BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), 236 Time: new(big.Int).SetUint64(uint64(test.Context.Time)), 237 Difficulty: (*big.Int)(test.Context.Difficulty), 238 GasLimit: uint64(test.Context.GasLimit), 239 GasPrice: tx.GasPrice(), 240 } 241 statedb := tests.MakePreState(ethdb.NewMemDatabase(), test.Genesis.Alloc) 242 243 //创建跟踪程序、EVM环境并运行它 244 tracer, err := New("callTracer") 245 if err != nil { 246 t.Fatalf("failed to create call tracer: %v", err) 247 } 248 evm := vm.NewEVM(context, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) 249 250 msg, err := tx.AsMessage(signer) 251 if err != nil { 252 t.Fatalf("failed to prepare transaction for tracing: %v", err) 253 } 254 st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) 255 if _, _, _, err = st.TransitionDb(); err != nil { 256 t.Fatalf("failed to execute transaction: %v", err) 257 } 258 //检索跟踪结果并与标准具进行比较 259 res, err := tracer.GetResult() 260 if err != nil { 261 t.Fatalf("failed to retrieve trace result: %v", err) 262 } 263 ret := new(callTrace) 264 if err := json.Unmarshal(res, ret); err != nil { 265 t.Fatalf("failed to unmarshal trace result: %v", err) 266 } 267 268 if !reflect.DeepEqual(ret, test.Result) { 269 t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, test.Result) 270 } 271 }) 272 } 273 } 274