1// Copyright 2021 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
17package tracers
18
19import (
20	"bytes"
21	"context"
22	"crypto/ecdsa"
23	"encoding/json"
24	"errors"
25	"fmt"
26	"math/big"
27	"reflect"
28	"sort"
29	"testing"
30	"time"
31
32	"github.com/ethereum/go-ethereum/common"
33	"github.com/ethereum/go-ethereum/common/hexutil"
34	"github.com/ethereum/go-ethereum/consensus"
35	"github.com/ethereum/go-ethereum/consensus/ethash"
36	"github.com/ethereum/go-ethereum/core"
37	"github.com/ethereum/go-ethereum/core/rawdb"
38	"github.com/ethereum/go-ethereum/core/state"
39	"github.com/ethereum/go-ethereum/core/types"
40	"github.com/ethereum/go-ethereum/core/vm"
41	"github.com/ethereum/go-ethereum/crypto"
42	"github.com/ethereum/go-ethereum/ethdb"
43	"github.com/ethereum/go-ethereum/internal/ethapi"
44	"github.com/ethereum/go-ethereum/params"
45	"github.com/ethereum/go-ethereum/rpc"
46)
47
48var (
49	errStateNotFound       = errors.New("state not found")
50	errBlockNotFound       = errors.New("block not found")
51	errTransactionNotFound = errors.New("transaction not found")
52)
53
54type testBackend struct {
55	chainConfig *params.ChainConfig
56	engine      consensus.Engine
57	chaindb     ethdb.Database
58	chain       *core.BlockChain
59}
60
61func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend {
62	backend := &testBackend{
63		chainConfig: params.TestChainConfig,
64		engine:      ethash.NewFaker(),
65		chaindb:     rawdb.NewMemoryDatabase(),
66	}
67	// Generate blocks for testing
68	gspec.Config = backend.chainConfig
69	var (
70		gendb   = rawdb.NewMemoryDatabase()
71		genesis = gspec.MustCommit(gendb)
72	)
73	blocks, _ := core.GenerateChain(backend.chainConfig, genesis, backend.engine, gendb, n, generator)
74
75	// Import the canonical chain
76	gspec.MustCommit(backend.chaindb)
77	cacheConfig := &core.CacheConfig{
78		TrieCleanLimit:    256,
79		TrieDirtyLimit:    256,
80		TrieTimeLimit:     5 * time.Minute,
81		SnapshotLimit:     0,
82		TrieDirtyDisabled: true, // Archive mode
83	}
84	chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil)
85	if err != nil {
86		t.Fatalf("failed to create tester chain: %v", err)
87	}
88	if n, err := chain.InsertChain(blocks); err != nil {
89		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
90	}
91	backend.chain = chain
92	return backend
93}
94
95func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
96	return b.chain.GetHeaderByHash(hash), nil
97}
98
99func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
100	if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
101		return b.chain.CurrentHeader(), nil
102	}
103	return b.chain.GetHeaderByNumber(uint64(number)), nil
104}
105
106func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
107	return b.chain.GetBlockByHash(hash), nil
108}
109
110func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
111	if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
112		return b.chain.CurrentBlock(), nil
113	}
114	return b.chain.GetBlockByNumber(uint64(number)), nil
115}
116
117func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
118	tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
119	if tx == nil {
120		return nil, common.Hash{}, 0, 0, errTransactionNotFound
121	}
122	return tx, hash, blockNumber, index, nil
123}
124
125func (b *testBackend) RPCGasCap() uint64 {
126	return 25000000
127}
128
129func (b *testBackend) ChainConfig() *params.ChainConfig {
130	return b.chainConfig
131}
132
133func (b *testBackend) Engine() consensus.Engine {
134	return b.engine
135}
136
137func (b *testBackend) ChainDb() ethdb.Database {
138	return b.chaindb
139}
140
141func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) {
142	statedb, err := b.chain.StateAt(block.Root())
143	if err != nil {
144		return nil, errStateNotFound
145	}
146	return statedb, nil
147}
148
149func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) {
150	parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
151	if parent == nil {
152		return nil, vm.BlockContext{}, nil, errBlockNotFound
153	}
154	statedb, err := b.chain.StateAt(parent.Root())
155	if err != nil {
156		return nil, vm.BlockContext{}, nil, errStateNotFound
157	}
158	if txIndex == 0 && len(block.Transactions()) == 0 {
159		return nil, vm.BlockContext{}, statedb, nil
160	}
161	// Recompute transactions up to the target index.
162	signer := types.MakeSigner(b.chainConfig, block.Number())
163	for idx, tx := range block.Transactions() {
164		msg, _ := tx.AsMessage(signer, block.BaseFee())
165		txContext := core.NewEVMTxContext(msg)
166		context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
167		if idx == txIndex {
168			return msg, context, statedb, nil
169		}
170		vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
171		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
172			return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
173		}
174		statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
175	}
176	return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
177}
178
179func TestTraceCall(t *testing.T) {
180	t.Parallel()
181
182	// Initialize test accounts
183	accounts := newAccounts(3)
184	genesis := &core.Genesis{Alloc: core.GenesisAlloc{
185		accounts[0].addr: {Balance: big.NewInt(params.Ether)},
186		accounts[1].addr: {Balance: big.NewInt(params.Ether)},
187		accounts[2].addr: {Balance: big.NewInt(params.Ether)},
188	}}
189	genBlocks := 10
190	signer := types.HomesteadSigner{}
191	api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
192		// Transfer from account[0] to account[1]
193		//    value: 1000 wei
194		//    fee:   0 wei
195		tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
196		b.AddTx(tx)
197	}))
198
199	var testSuite = []struct {
200		blockNumber rpc.BlockNumber
201		call        ethapi.TransactionArgs
202		config      *TraceCallConfig
203		expectErr   error
204		expect      interface{}
205	}{
206		// Standard JSON trace upon the genesis, plain transfer.
207		{
208			blockNumber: rpc.BlockNumber(0),
209			call: ethapi.TransactionArgs{
210				From:  &accounts[0].addr,
211				To:    &accounts[1].addr,
212				Value: (*hexutil.Big)(big.NewInt(1000)),
213			},
214			config:    nil,
215			expectErr: nil,
216			expect: &ethapi.ExecutionResult{
217				Gas:         params.TxGas,
218				Failed:      false,
219				ReturnValue: "",
220				StructLogs:  []ethapi.StructLogRes{},
221			},
222		},
223		// Standard JSON trace upon the head, plain transfer.
224		{
225			blockNumber: rpc.BlockNumber(genBlocks),
226			call: ethapi.TransactionArgs{
227				From:  &accounts[0].addr,
228				To:    &accounts[1].addr,
229				Value: (*hexutil.Big)(big.NewInt(1000)),
230			},
231			config:    nil,
232			expectErr: nil,
233			expect: &ethapi.ExecutionResult{
234				Gas:         params.TxGas,
235				Failed:      false,
236				ReturnValue: "",
237				StructLogs:  []ethapi.StructLogRes{},
238			},
239		},
240		// Standard JSON trace upon the non-existent block, error expects
241		{
242			blockNumber: rpc.BlockNumber(genBlocks + 1),
243			call: ethapi.TransactionArgs{
244				From:  &accounts[0].addr,
245				To:    &accounts[1].addr,
246				Value: (*hexutil.Big)(big.NewInt(1000)),
247			},
248			config:    nil,
249			expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
250			expect:    nil,
251		},
252		// Standard JSON trace upon the latest block
253		{
254			blockNumber: rpc.LatestBlockNumber,
255			call: ethapi.TransactionArgs{
256				From:  &accounts[0].addr,
257				To:    &accounts[1].addr,
258				Value: (*hexutil.Big)(big.NewInt(1000)),
259			},
260			config:    nil,
261			expectErr: nil,
262			expect: &ethapi.ExecutionResult{
263				Gas:         params.TxGas,
264				Failed:      false,
265				ReturnValue: "",
266				StructLogs:  []ethapi.StructLogRes{},
267			},
268		},
269		// Standard JSON trace upon the pending block
270		{
271			blockNumber: rpc.PendingBlockNumber,
272			call: ethapi.TransactionArgs{
273				From:  &accounts[0].addr,
274				To:    &accounts[1].addr,
275				Value: (*hexutil.Big)(big.NewInt(1000)),
276			},
277			config:    nil,
278			expectErr: nil,
279			expect: &ethapi.ExecutionResult{
280				Gas:         params.TxGas,
281				Failed:      false,
282				ReturnValue: "",
283				StructLogs:  []ethapi.StructLogRes{},
284			},
285		},
286	}
287	for _, testspec := range testSuite {
288		result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
289		if testspec.expectErr != nil {
290			if err == nil {
291				t.Errorf("Expect error %v, get nothing", testspec.expectErr)
292				continue
293			}
294			if !reflect.DeepEqual(err, testspec.expectErr) {
295				t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err)
296			}
297		} else {
298			if err != nil {
299				t.Errorf("Expect no error, get %v", err)
300				continue
301			}
302			if !reflect.DeepEqual(result, testspec.expect) {
303				t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result)
304			}
305		}
306	}
307}
308
309func TestTraceTransaction(t *testing.T) {
310	t.Parallel()
311
312	// Initialize test accounts
313	accounts := newAccounts(2)
314	genesis := &core.Genesis{Alloc: core.GenesisAlloc{
315		accounts[0].addr: {Balance: big.NewInt(params.Ether)},
316		accounts[1].addr: {Balance: big.NewInt(params.Ether)},
317	}}
318	target := common.Hash{}
319	signer := types.HomesteadSigner{}
320	api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
321		// Transfer from account[0] to account[1]
322		//    value: 1000 wei
323		//    fee:   0 wei
324		tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
325		b.AddTx(tx)
326		target = tx.Hash()
327	}))
328	result, err := api.TraceTransaction(context.Background(), target, nil)
329	if err != nil {
330		t.Errorf("Failed to trace transaction %v", err)
331	}
332	if !reflect.DeepEqual(result, &ethapi.ExecutionResult{
333		Gas:         params.TxGas,
334		Failed:      false,
335		ReturnValue: "",
336		StructLogs:  []ethapi.StructLogRes{},
337	}) {
338		t.Error("Transaction tracing result is different")
339	}
340}
341
342func TestTraceBlock(t *testing.T) {
343	t.Parallel()
344
345	// Initialize test accounts
346	accounts := newAccounts(3)
347	genesis := &core.Genesis{Alloc: core.GenesisAlloc{
348		accounts[0].addr: {Balance: big.NewInt(params.Ether)},
349		accounts[1].addr: {Balance: big.NewInt(params.Ether)},
350		accounts[2].addr: {Balance: big.NewInt(params.Ether)},
351	}}
352	genBlocks := 10
353	signer := types.HomesteadSigner{}
354	api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
355		// Transfer from account[0] to account[1]
356		//    value: 1000 wei
357		//    fee:   0 wei
358		tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
359		b.AddTx(tx)
360	}))
361
362	var testSuite = []struct {
363		blockNumber rpc.BlockNumber
364		config      *TraceConfig
365		want        string
366		expectErr   error
367	}{
368		// Trace genesis block, expect error
369		{
370			blockNumber: rpc.BlockNumber(0),
371			expectErr:   errors.New("genesis is not traceable"),
372		},
373		// Trace head block
374		{
375			blockNumber: rpc.BlockNumber(genBlocks),
376			want:        `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
377		},
378		// Trace non-existent block
379		{
380			blockNumber: rpc.BlockNumber(genBlocks + 1),
381			expectErr:   fmt.Errorf("block #%d not found", genBlocks+1),
382		},
383		// Trace latest block
384		{
385			blockNumber: rpc.LatestBlockNumber,
386			want:        `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
387		},
388		// Trace pending block
389		{
390			blockNumber: rpc.PendingBlockNumber,
391			want:        `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
392		},
393	}
394	for i, tc := range testSuite {
395		result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config)
396		if tc.expectErr != nil {
397			if err == nil {
398				t.Errorf("test %d, want error %v", i, tc.expectErr)
399				continue
400			}
401			if !reflect.DeepEqual(err, tc.expectErr) {
402				t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err)
403			}
404			continue
405		}
406		if err != nil {
407			t.Errorf("test %d, want no error, have %v", i, err)
408			continue
409		}
410		have, _ := json.Marshal(result)
411		want := tc.want
412		if string(have) != want {
413			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want)
414		}
415	}
416}
417
418func TestTracingWithOverrides(t *testing.T) {
419	t.Parallel()
420	// Initialize test accounts
421	accounts := newAccounts(3)
422	genesis := &core.Genesis{Alloc: core.GenesisAlloc{
423		accounts[0].addr: {Balance: big.NewInt(params.Ether)},
424		accounts[1].addr: {Balance: big.NewInt(params.Ether)},
425		accounts[2].addr: {Balance: big.NewInt(params.Ether)},
426	}}
427	genBlocks := 10
428	signer := types.HomesteadSigner{}
429	api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
430		// Transfer from account[0] to account[1]
431		//    value: 1000 wei
432		//    fee:   0 wei
433		tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
434		b.AddTx(tx)
435	}))
436	randomAccounts := newAccounts(3)
437	type res struct {
438		Gas         int
439		Failed      bool
440		returnValue string
441	}
442	var testSuite = []struct {
443		blockNumber rpc.BlockNumber
444		call        ethapi.TransactionArgs
445		config      *TraceCallConfig
446		expectErr   error
447		want        string
448	}{
449		// Call which can only succeed if state is state overridden
450		{
451			blockNumber: rpc.PendingBlockNumber,
452			call: ethapi.TransactionArgs{
453				From:  &randomAccounts[0].addr,
454				To:    &randomAccounts[1].addr,
455				Value: (*hexutil.Big)(big.NewInt(1000)),
456			},
457			config: &TraceCallConfig{
458				StateOverrides: &ethapi.StateOverride{
459					randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
460				},
461			},
462			want: `{"gas":21000,"failed":false,"returnValue":""}`,
463		},
464		// Invalid call without state overriding
465		{
466			blockNumber: rpc.PendingBlockNumber,
467			call: ethapi.TransactionArgs{
468				From:  &randomAccounts[0].addr,
469				To:    &randomAccounts[1].addr,
470				Value: (*hexutil.Big)(big.NewInt(1000)),
471			},
472			config:    &TraceCallConfig{},
473			expectErr: core.ErrInsufficientFunds,
474		},
475		// Successful simple contract call
476		//
477		// // SPDX-License-Identifier: GPL-3.0
478		//
479		//  pragma solidity >=0.7.0 <0.8.0;
480		//
481		//  /**
482		//   * @title Storage
483		//   * @dev Store & retrieve value in a variable
484		//   */
485		//  contract Storage {
486		//      uint256 public number;
487		//      constructor() {
488		//          number = block.number;
489		//      }
490		//  }
491		{
492			blockNumber: rpc.PendingBlockNumber,
493			call: ethapi.TransactionArgs{
494				From: &randomAccounts[0].addr,
495				To:   &randomAccounts[2].addr,
496				Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number()
497			},
498			config: &TraceCallConfig{
499				//Tracer: &tracer,
500				StateOverrides: &ethapi.StateOverride{
501					randomAccounts[2].addr: ethapi.OverrideAccount{
502						Code:      newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
503						StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}),
504					},
505				},
506			},
507			want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`,
508		},
509	}
510	for i, tc := range testSuite {
511		result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)
512		if tc.expectErr != nil {
513			if err == nil {
514				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
515				continue
516			}
517			if !errors.Is(err, tc.expectErr) {
518				t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
519			}
520			continue
521		}
522		if err != nil {
523			t.Errorf("test %d: want no error, have %v", i, err)
524			continue
525		}
526		// Turn result into res-struct
527		var (
528			have res
529			want res
530		)
531		resBytes, _ := json.Marshal(result)
532		json.Unmarshal(resBytes, &have)
533		json.Unmarshal([]byte(tc.want), &want)
534		if !reflect.DeepEqual(have, want) {
535			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(resBytes), want)
536		}
537	}
538}
539
540type Account struct {
541	key  *ecdsa.PrivateKey
542	addr common.Address
543}
544
545type Accounts []Account
546
547func (a Accounts) Len() int           { return len(a) }
548func (a Accounts) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
549func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 }
550
551func newAccounts(n int) (accounts Accounts) {
552	for i := 0; i < n; i++ {
553		key, _ := crypto.GenerateKey()
554		addr := crypto.PubkeyToAddress(key.PublicKey)
555		accounts = append(accounts, Account{key: key, addr: addr})
556	}
557	sort.Sort(accounts)
558	return accounts
559}
560
561func newRPCBalance(balance *big.Int) **hexutil.Big {
562	rpcBalance := (*hexutil.Big)(balance)
563	return &rpcBalance
564}
565
566func newRPCBytes(bytes []byte) *hexutil.Bytes {
567	rpcBytes := hexutil.Bytes(bytes)
568	return &rpcBytes
569}
570
571func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash {
572	if len(keys) != len(vals) {
573		panic("invalid input")
574	}
575	m := make(map[common.Hash]common.Hash)
576	for i := 0; i < len(keys); i++ {
577		m[keys[i]] = vals[i]
578	}
579	return &m
580}
581