tracers_test.go 10 KB

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