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