github.com/carter-ya/go-ethereum@v0.0.0-20230628080049-d2309be3983b/eth/tracers/api_test.go (about) 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 17 package tracers 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/ecdsa" 23 "encoding/json" 24 "errors" 25 "fmt" 26 "math/big" 27 "reflect" 28 "sort" 29 "sync/atomic" 30 "testing" 31 "time" 32 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/common/hexutil" 35 "github.com/ethereum/go-ethereum/consensus" 36 "github.com/ethereum/go-ethereum/consensus/ethash" 37 "github.com/ethereum/go-ethereum/core" 38 "github.com/ethereum/go-ethereum/core/rawdb" 39 "github.com/ethereum/go-ethereum/core/state" 40 "github.com/ethereum/go-ethereum/core/types" 41 "github.com/ethereum/go-ethereum/core/vm" 42 "github.com/ethereum/go-ethereum/crypto" 43 "github.com/ethereum/go-ethereum/eth/tracers/logger" 44 "github.com/ethereum/go-ethereum/ethdb" 45 "github.com/ethereum/go-ethereum/internal/ethapi" 46 "github.com/ethereum/go-ethereum/params" 47 "github.com/ethereum/go-ethereum/rpc" 48 ) 49 50 var ( 51 errStateNotFound = errors.New("state not found") 52 errBlockNotFound = errors.New("block not found") 53 errTransactionNotFound = errors.New("transaction not found") 54 ) 55 56 type testBackend struct { 57 chainConfig *params.ChainConfig 58 engine consensus.Engine 59 chaindb ethdb.Database 60 chain *core.BlockChain 61 62 refHook func() // Hook is invoked when the requested state is referenced 63 relHook func() // Hook is invoked when the requested state is released 64 } 65 66 func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { 67 backend := &testBackend{ 68 chainConfig: gspec.Config, 69 engine: ethash.NewFaker(), 70 chaindb: rawdb.NewMemoryDatabase(), 71 } 72 // Generate blocks for testing 73 _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) 74 75 // Import the canonical chain 76 cacheConfig := &core.CacheConfig{ 77 TrieCleanLimit: 256, 78 TrieDirtyLimit: 256, 79 TrieTimeLimit: 5 * time.Minute, 80 SnapshotLimit: 0, 81 TrieDirtyDisabled: true, // Archive mode 82 } 83 chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) 84 if err != nil { 85 t.Fatalf("failed to create tester chain: %v", err) 86 } 87 if n, err := chain.InsertChain(blocks); err != nil { 88 t.Fatalf("block %d: failed to insert into chain: %v", n, err) 89 } 90 backend.chain = chain 91 return backend 92 } 93 94 func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 95 return b.chain.GetHeaderByHash(hash), nil 96 } 97 98 func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { 99 if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber { 100 return b.chain.CurrentHeader(), nil 101 } 102 return b.chain.GetHeaderByNumber(uint64(number)), nil 103 } 104 105 func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 106 return b.chain.GetBlockByHash(hash), nil 107 } 108 109 func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { 110 if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber { 111 return b.chain.CurrentBlock(), nil 112 } 113 return b.chain.GetBlockByNumber(uint64(number)), nil 114 } 115 116 func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { 117 tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash) 118 if tx == nil { 119 return nil, common.Hash{}, 0, 0, errTransactionNotFound 120 } 121 return tx, hash, blockNumber, index, nil 122 } 123 124 func (b *testBackend) RPCGasCap() uint64 { 125 return 25000000 126 } 127 128 func (b *testBackend) ChainConfig() *params.ChainConfig { 129 return b.chainConfig 130 } 131 132 func (b *testBackend) Engine() consensus.Engine { 133 return b.engine 134 } 135 136 func (b *testBackend) ChainDb() ethdb.Database { 137 return b.chaindb 138 } 139 140 func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) { 141 statedb, err := b.chain.StateAt(block.Root()) 142 if err != nil { 143 return nil, nil, errStateNotFound 144 } 145 if b.refHook != nil { 146 b.refHook() 147 } 148 release := func() { 149 if b.relHook != nil { 150 b.relHook() 151 } 152 } 153 return statedb, release, nil 154 } 155 156 func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) { 157 parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) 158 if parent == nil { 159 return nil, vm.BlockContext{}, nil, nil, errBlockNotFound 160 } 161 statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false) 162 if err != nil { 163 return nil, vm.BlockContext{}, nil, nil, errStateNotFound 164 } 165 if txIndex == 0 && len(block.Transactions()) == 0 { 166 return nil, vm.BlockContext{}, statedb, release, nil 167 } 168 // Recompute transactions up to the target index. 169 signer := types.MakeSigner(b.chainConfig, block.Number()) 170 for idx, tx := range block.Transactions() { 171 msg, _ := tx.AsMessage(signer, block.BaseFee()) 172 txContext := core.NewEVMTxContext(msg) 173 context := core.NewEVMBlockContext(block.Header(), b.chain, nil) 174 if idx == txIndex { 175 return msg, context, statedb, release, nil 176 } 177 vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) 178 if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { 179 return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 180 } 181 statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) 182 } 183 return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) 184 } 185 186 func TestTraceCall(t *testing.T) { 187 t.Parallel() 188 189 // Initialize test accounts 190 accounts := newAccounts(3) 191 genesis := &core.Genesis{ 192 Config: params.TestChainConfig, 193 Alloc: core.GenesisAlloc{ 194 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 195 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 196 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 197 }, 198 } 199 genBlocks := 10 200 signer := types.HomesteadSigner{} 201 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 202 // Transfer from account[0] to account[1] 203 // value: 1000 wei 204 // fee: 0 wei 205 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 206 b.AddTx(tx) 207 })) 208 var testSuite = []struct { 209 blockNumber rpc.BlockNumber 210 call ethapi.TransactionArgs 211 config *TraceCallConfig 212 expectErr error 213 expect string 214 }{ 215 // Standard JSON trace upon the genesis, plain transfer. 216 { 217 blockNumber: rpc.BlockNumber(0), 218 call: ethapi.TransactionArgs{ 219 From: &accounts[0].addr, 220 To: &accounts[1].addr, 221 Value: (*hexutil.Big)(big.NewInt(1000)), 222 }, 223 config: nil, 224 expectErr: nil, 225 expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, 226 }, 227 // Standard JSON trace upon the head, plain transfer. 228 { 229 blockNumber: rpc.BlockNumber(genBlocks), 230 call: ethapi.TransactionArgs{ 231 From: &accounts[0].addr, 232 To: &accounts[1].addr, 233 Value: (*hexutil.Big)(big.NewInt(1000)), 234 }, 235 config: nil, 236 expectErr: nil, 237 expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, 238 }, 239 // Standard JSON trace upon the non-existent block, error expects 240 { 241 blockNumber: rpc.BlockNumber(genBlocks + 1), 242 call: ethapi.TransactionArgs{ 243 From: &accounts[0].addr, 244 To: &accounts[1].addr, 245 Value: (*hexutil.Big)(big.NewInt(1000)), 246 }, 247 config: nil, 248 expectErr: fmt.Errorf("block #%d not found", genBlocks+1), 249 //expect: nil, 250 }, 251 // Standard JSON trace upon the latest block 252 { 253 blockNumber: rpc.LatestBlockNumber, 254 call: ethapi.TransactionArgs{ 255 From: &accounts[0].addr, 256 To: &accounts[1].addr, 257 Value: (*hexutil.Big)(big.NewInt(1000)), 258 }, 259 config: nil, 260 expectErr: nil, 261 expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, 262 }, 263 // Tracing on 'pending' should fail: 264 { 265 blockNumber: rpc.PendingBlockNumber, 266 call: ethapi.TransactionArgs{ 267 From: &accounts[0].addr, 268 To: &accounts[1].addr, 269 Value: (*hexutil.Big)(big.NewInt(1000)), 270 }, 271 config: nil, 272 expectErr: errors.New("tracing on top of pending is not supported"), 273 }, 274 { 275 blockNumber: rpc.LatestBlockNumber, 276 call: ethapi.TransactionArgs{ 277 From: &accounts[0].addr, 278 Input: &hexutil.Bytes{0x43}, // blocknumber 279 }, 280 config: &TraceCallConfig{ 281 BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, 282 }, 283 expectErr: nil, 284 expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[ 285 {"pc":0,"op":"NUMBER","gas":24946984,"gasCost":2,"depth":1,"stack":[]}, 286 {"pc":1,"op":"STOP","gas":24946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`, 287 }, 288 } 289 for i, testspec := range testSuite { 290 result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) 291 if testspec.expectErr != nil { 292 if err == nil { 293 t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr) 294 continue 295 } 296 if !reflect.DeepEqual(err, testspec.expectErr) { 297 t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err) 298 } 299 } else { 300 if err != nil { 301 t.Errorf("test %d: expect no error, got %v", i, err) 302 continue 303 } 304 var have *logger.ExecutionResult 305 if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil { 306 t.Errorf("test %d: failed to unmarshal result %v", i, err) 307 } 308 var want *logger.ExecutionResult 309 if err := json.Unmarshal([]byte(testspec.expect), &want); err != nil { 310 t.Errorf("test %d: failed to unmarshal result %v", i, err) 311 } 312 if !reflect.DeepEqual(have, want) { 313 t.Errorf("test %d: result mismatch, want %v, got %v", i, testspec.expect, string(result.(json.RawMessage))) 314 } 315 } 316 } 317 } 318 319 func TestTraceTransaction(t *testing.T) { 320 t.Parallel() 321 322 // Initialize test accounts 323 accounts := newAccounts(2) 324 genesis := &core.Genesis{ 325 Config: params.TestChainConfig, 326 Alloc: core.GenesisAlloc{ 327 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 328 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 329 }, 330 } 331 target := common.Hash{} 332 signer := types.HomesteadSigner{} 333 api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { 334 // Transfer from account[0] to account[1] 335 // value: 1000 wei 336 // fee: 0 wei 337 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 338 b.AddTx(tx) 339 target = tx.Hash() 340 })) 341 result, err := api.TraceTransaction(context.Background(), target, nil) 342 if err != nil { 343 t.Errorf("Failed to trace transaction %v", err) 344 } 345 var have *logger.ExecutionResult 346 if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil { 347 t.Errorf("failed to unmarshal result %v", err) 348 } 349 if !reflect.DeepEqual(have, &logger.ExecutionResult{ 350 Gas: params.TxGas, 351 Failed: false, 352 ReturnValue: "", 353 StructLogs: []logger.StructLogRes{}, 354 }) { 355 t.Error("Transaction tracing result is different") 356 } 357 } 358 359 func TestTraceBlock(t *testing.T) { 360 t.Parallel() 361 362 // Initialize test accounts 363 accounts := newAccounts(3) 364 genesis := &core.Genesis{ 365 Config: params.TestChainConfig, 366 Alloc: core.GenesisAlloc{ 367 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 368 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 369 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 370 }, 371 } 372 genBlocks := 10 373 signer := types.HomesteadSigner{} 374 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 375 // Transfer from account[0] to account[1] 376 // value: 1000 wei 377 // fee: 0 wei 378 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 379 b.AddTx(tx) 380 })) 381 382 var testSuite = []struct { 383 blockNumber rpc.BlockNumber 384 config *TraceConfig 385 want string 386 expectErr error 387 }{ 388 // Trace genesis block, expect error 389 { 390 blockNumber: rpc.BlockNumber(0), 391 expectErr: errors.New("genesis is not traceable"), 392 }, 393 // Trace head block 394 { 395 blockNumber: rpc.BlockNumber(genBlocks), 396 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 397 }, 398 // Trace non-existent block 399 { 400 blockNumber: rpc.BlockNumber(genBlocks + 1), 401 expectErr: fmt.Errorf("block #%d not found", genBlocks+1), 402 }, 403 // Trace latest block 404 { 405 blockNumber: rpc.LatestBlockNumber, 406 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 407 }, 408 // Trace pending block 409 { 410 blockNumber: rpc.PendingBlockNumber, 411 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 412 }, 413 } 414 for i, tc := range testSuite { 415 result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config) 416 if tc.expectErr != nil { 417 if err == nil { 418 t.Errorf("test %d, want error %v", i, tc.expectErr) 419 continue 420 } 421 if !reflect.DeepEqual(err, tc.expectErr) { 422 t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err) 423 } 424 continue 425 } 426 if err != nil { 427 t.Errorf("test %d, want no error, have %v", i, err) 428 continue 429 } 430 have, _ := json.Marshal(result) 431 want := tc.want 432 if string(have) != want { 433 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want) 434 } 435 } 436 } 437 438 func TestTracingWithOverrides(t *testing.T) { 439 t.Parallel() 440 // Initialize test accounts 441 accounts := newAccounts(3) 442 genesis := &core.Genesis{ 443 Config: params.TestChainConfig, 444 Alloc: core.GenesisAlloc{ 445 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 446 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 447 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 448 }, 449 } 450 genBlocks := 10 451 signer := types.HomesteadSigner{} 452 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 453 // Transfer from account[0] to account[1] 454 // value: 1000 wei 455 // fee: 0 wei 456 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 457 b.AddTx(tx) 458 })) 459 randomAccounts := newAccounts(3) 460 type res struct { 461 Gas int 462 Failed bool 463 ReturnValue string 464 } 465 var testSuite = []struct { 466 blockNumber rpc.BlockNumber 467 call ethapi.TransactionArgs 468 config *TraceCallConfig 469 expectErr error 470 want string 471 }{ 472 // Call which can only succeed if state is state overridden 473 { 474 blockNumber: rpc.LatestBlockNumber, 475 call: ethapi.TransactionArgs{ 476 From: &randomAccounts[0].addr, 477 To: &randomAccounts[1].addr, 478 Value: (*hexutil.Big)(big.NewInt(1000)), 479 }, 480 config: &TraceCallConfig{ 481 StateOverrides: ðapi.StateOverride{ 482 randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 483 }, 484 }, 485 want: `{"gas":21000,"failed":false,"returnValue":""}`, 486 }, 487 // Invalid call without state overriding 488 { 489 blockNumber: rpc.LatestBlockNumber, 490 call: ethapi.TransactionArgs{ 491 From: &randomAccounts[0].addr, 492 To: &randomAccounts[1].addr, 493 Value: (*hexutil.Big)(big.NewInt(1000)), 494 }, 495 config: &TraceCallConfig{}, 496 expectErr: core.ErrInsufficientFunds, 497 }, 498 // Successful simple contract call 499 // 500 // // SPDX-License-Identifier: GPL-3.0 501 // 502 // pragma solidity >=0.7.0 <0.8.0; 503 // 504 // /** 505 // * @title Storage 506 // * @dev Store & retrieve value in a variable 507 // */ 508 // contract Storage { 509 // uint256 public number; 510 // constructor() { 511 // number = block.number; 512 // } 513 // } 514 { 515 blockNumber: rpc.LatestBlockNumber, 516 call: ethapi.TransactionArgs{ 517 From: &randomAccounts[0].addr, 518 To: &randomAccounts[2].addr, 519 Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number() 520 }, 521 config: &TraceCallConfig{ 522 //Tracer: &tracer, 523 StateOverrides: ðapi.StateOverride{ 524 randomAccounts[2].addr: ethapi.OverrideAccount{ 525 Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), 526 StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), 527 }, 528 }, 529 }, 530 want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`, 531 }, 532 { // Override blocknumber 533 blockNumber: rpc.LatestBlockNumber, 534 call: ethapi.TransactionArgs{ 535 From: &accounts[0].addr, 536 // BLOCKNUMBER PUSH1 MSTORE 537 Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")), 538 //&hexutil.Bytes{0x43}, // blocknumber 539 }, 540 config: &TraceCallConfig{ 541 BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, 542 }, 543 want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`, 544 }, 545 { // Override blocknumber, and query a blockhash 546 blockNumber: rpc.LatestBlockNumber, 547 call: ethapi.TransactionArgs{ 548 From: &accounts[0].addr, 549 Input: &hexutil.Bytes{ 550 0x60, 0x00, 0x40, // BLOCKHASH(0) 551 0x60, 0x00, 0x52, // STORE memory offset 0 552 0x61, 0x13, 0x36, 0x40, // BLOCKHASH(0x1336) 553 0x60, 0x20, 0x52, // STORE memory offset 32 554 0x61, 0x13, 0x37, 0x40, // BLOCKHASH(0x1337) 555 0x60, 0x40, 0x52, // STORE memory offset 64 556 0x60, 0x60, 0x60, 0x00, 0xf3, // RETURN (0-96) 557 558 }, // blocknumber 559 }, 560 config: &TraceCallConfig{ 561 BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))}, 562 }, 563 want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`, 564 }, 565 } 566 for i, tc := range testSuite { 567 result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) 568 if tc.expectErr != nil { 569 if err == nil { 570 t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) 571 continue 572 } 573 if !errors.Is(err, tc.expectErr) { 574 t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) 575 } 576 continue 577 } 578 if err != nil { 579 t.Errorf("test %d: want no error, have %v", i, err) 580 continue 581 } 582 // Turn result into res-struct 583 var ( 584 have res 585 want res 586 ) 587 resBytes, _ := json.Marshal(result) 588 json.Unmarshal(resBytes, &have) 589 json.Unmarshal([]byte(tc.want), &want) 590 if !reflect.DeepEqual(have, want) { 591 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(resBytes), want) 592 } 593 } 594 } 595 596 type Account struct { 597 key *ecdsa.PrivateKey 598 addr common.Address 599 } 600 601 type Accounts []Account 602 603 func (a Accounts) Len() int { return len(a) } 604 func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 605 func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } 606 607 func newAccounts(n int) (accounts Accounts) { 608 for i := 0; i < n; i++ { 609 key, _ := crypto.GenerateKey() 610 addr := crypto.PubkeyToAddress(key.PublicKey) 611 accounts = append(accounts, Account{key: key, addr: addr}) 612 } 613 sort.Sort(accounts) 614 return accounts 615 } 616 617 func newRPCBalance(balance *big.Int) **hexutil.Big { 618 rpcBalance := (*hexutil.Big)(balance) 619 return &rpcBalance 620 } 621 622 func newRPCBytes(bytes []byte) *hexutil.Bytes { 623 rpcBytes := hexutil.Bytes(bytes) 624 return &rpcBytes 625 } 626 627 func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash { 628 if len(keys) != len(vals) { 629 panic("invalid input") 630 } 631 m := make(map[common.Hash]common.Hash) 632 for i := 0; i < len(keys); i++ { 633 m[keys[i]] = vals[i] 634 } 635 return &m 636 } 637 638 func TestTraceChain(t *testing.T) { 639 // Initialize test accounts 640 accounts := newAccounts(3) 641 genesis := &core.Genesis{ 642 Config: params.TestChainConfig, 643 Alloc: core.GenesisAlloc{ 644 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 645 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 646 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 647 }, 648 } 649 genBlocks := 50 650 signer := types.HomesteadSigner{} 651 652 var ( 653 ref uint32 // total refs has made 654 rel uint32 // total rels has made 655 nonce uint64 656 ) 657 backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 658 // Transfer from account[0] to account[1] 659 // value: 1000 wei 660 // fee: 0 wei 661 for j := 0; j < i+1; j++ { 662 tx, _ := types.SignTx(types.NewTransaction(nonce, accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 663 b.AddTx(tx) 664 nonce += 1 665 } 666 }) 667 backend.refHook = func() { atomic.AddUint32(&ref, 1) } 668 backend.relHook = func() { atomic.AddUint32(&rel, 1) } 669 api := NewAPI(backend) 670 671 single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` 672 var cases = []struct { 673 start uint64 674 end uint64 675 config *TraceConfig 676 }{ 677 {0, 50, nil}, // the entire chain range, blocks [1, 50] 678 {10, 20, nil}, // the middle chain range, blocks [11, 20] 679 } 680 for _, c := range cases { 681 ref, rel = 0, 0 // clean up the counters 682 683 from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) 684 to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) 685 resCh := api.traceChain(from, to, c.config, nil) 686 687 next := c.start + 1 688 for result := range resCh { 689 if next != uint64(result.Block) { 690 t.Error("Unexpected tracing block") 691 } 692 if len(result.Traces) != int(next) { 693 t.Error("Unexpected tracing result") 694 } 695 for _, trace := range result.Traces { 696 blob, _ := json.Marshal(trace) 697 if string(blob) != single { 698 t.Error("Unexpected tracing result") 699 } 700 } 701 next += 1 702 } 703 if next != c.end+1 { 704 t.Error("Missing tracing block") 705 } 706 if ref != rel { 707 t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel) 708 } 709 } 710 }