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