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: ðapi.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: ðapi.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: ðapi.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: ðapi.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, ðapi.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: ðapi.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: ðapi.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