github.com/DxChainNetwork/dxc@v0.8.1-0.20220824085222-1162e304b6e7/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/DxChainNetwork/dxc/common" 33 "github.com/DxChainNetwork/dxc/common/hexutil" 34 "github.com/DxChainNetwork/dxc/consensus" 35 "github.com/DxChainNetwork/dxc/consensus/ethash" 36 "github.com/DxChainNetwork/dxc/core" 37 "github.com/DxChainNetwork/dxc/core/rawdb" 38 "github.com/DxChainNetwork/dxc/core/state" 39 "github.com/DxChainNetwork/dxc/core/types" 40 "github.com/DxChainNetwork/dxc/core/vm" 41 "github.com/DxChainNetwork/dxc/crypto" 42 "github.com/DxChainNetwork/dxc/ethdb" 43 "github.com/DxChainNetwork/dxc/internal/ethapi" 44 "github.com/DxChainNetwork/dxc/params" 45 "github.com/DxChainNetwork/dxc/rpc" 46 ) 47 48 var ( 49 errStateNotFound = errors.New("state not found") 50 errBlockNotFound = errors.New("block not found") 51 errTransactionNotFound = errors.New("transaction not found") 52 ) 53 54 type testBackend struct { 55 chainConfig *params.ChainConfig 56 engine consensus.Engine 57 chaindb ethdb.Database 58 chain *core.BlockChain 59 } 60 61 func 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 95 func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 96 return b.chain.GetHeaderByHash(hash), nil 97 } 98 99 func (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 106 func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 107 return b.chain.GetBlockByHash(hash), nil 108 } 109 110 func (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 117 func (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 125 func (b *testBackend) RPCGasCap() uint64 { 126 return 25000000 127 } 128 129 func (b *testBackend) ChainConfig() *params.ChainConfig { 130 return b.chainConfig 131 } 132 133 func (b *testBackend) Engine() consensus.Engine { 134 return b.engine 135 } 136 137 func (b *testBackend) ChainDb() ethdb.Database { 138 return b.chaindb 139 } 140 141 func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive 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 149 func (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 179 func (b *testBackend) ChainHeaderReader() consensus.ChainHeaderReader { 180 return b.chain 181 } 182 183 func TestTraceCall(t *testing.T) { 184 t.Parallel() 185 186 // Initialize test accounts 187 accounts := newAccounts(3) 188 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 189 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 190 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 191 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 192 }} 193 genBlocks := 10 194 signer := types.HomesteadSigner{} 195 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 196 // Transfer from account[0] to account[1] 197 // value: 1000 wei 198 // fee: 0 wei 199 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 200 b.AddTx(tx) 201 })) 202 203 var testSuite = []struct { 204 blockNumber rpc.BlockNumber 205 call ethapi.TransactionArgs 206 config *TraceCallConfig 207 expectErr error 208 expect interface{} 209 }{ 210 // Standard JSON trace upon the genesis, plain transfer. 211 { 212 blockNumber: rpc.BlockNumber(0), 213 call: ethapi.TransactionArgs{ 214 From: &accounts[0].addr, 215 To: &accounts[1].addr, 216 Value: (*hexutil.Big)(big.NewInt(1000)), 217 }, 218 config: nil, 219 expectErr: nil, 220 expect: ðapi.ExecutionResult{ 221 Gas: params.TxGas, 222 Failed: false, 223 ReturnValue: "", 224 StructLogs: []ethapi.StructLogRes{}, 225 }, 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: ðapi.ExecutionResult{ 238 Gas: params.TxGas, 239 Failed: false, 240 ReturnValue: "", 241 StructLogs: []ethapi.StructLogRes{}, 242 }, 243 }, 244 // Standard JSON trace upon the non-existent block, error expects 245 { 246 blockNumber: rpc.BlockNumber(genBlocks + 1), 247 call: ethapi.TransactionArgs{ 248 From: &accounts[0].addr, 249 To: &accounts[1].addr, 250 Value: (*hexutil.Big)(big.NewInt(1000)), 251 }, 252 config: nil, 253 expectErr: fmt.Errorf("block #%d not found", genBlocks+1), 254 expect: nil, 255 }, 256 // Standard JSON trace upon the latest block 257 { 258 blockNumber: rpc.LatestBlockNumber, 259 call: ethapi.TransactionArgs{ 260 From: &accounts[0].addr, 261 To: &accounts[1].addr, 262 Value: (*hexutil.Big)(big.NewInt(1000)), 263 }, 264 config: nil, 265 expectErr: nil, 266 expect: ðapi.ExecutionResult{ 267 Gas: params.TxGas, 268 Failed: false, 269 ReturnValue: "", 270 StructLogs: []ethapi.StructLogRes{}, 271 }, 272 }, 273 // Standard JSON trace upon the pending block 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: nil, 283 expect: ðapi.ExecutionResult{ 284 Gas: params.TxGas, 285 Failed: false, 286 ReturnValue: "", 287 StructLogs: []ethapi.StructLogRes{}, 288 }, 289 }, 290 } 291 for _, testspec := range testSuite { 292 result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) 293 if testspec.expectErr != nil { 294 if err == nil { 295 t.Errorf("Expect error %v, get nothing", testspec.expectErr) 296 continue 297 } 298 if !reflect.DeepEqual(err, testspec.expectErr) { 299 t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) 300 } 301 } else { 302 if err != nil { 303 t.Errorf("Expect no error, get %v", err) 304 continue 305 } 306 if !reflect.DeepEqual(result, testspec.expect) { 307 t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result) 308 } 309 } 310 } 311 } 312 313 func TestOverriddenTraceCall(t *testing.T) { 314 t.Parallel() 315 316 // Initialize test accounts 317 accounts := newAccounts(3) 318 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 319 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 320 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 321 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 322 }} 323 genBlocks := 10 324 signer := types.HomesteadSigner{} 325 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 326 // Transfer from account[0] to account[1] 327 // value: 1000 wei 328 // fee: 0 wei 329 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 330 b.AddTx(tx) 331 })) 332 randomAccounts, tracer := newAccounts(3), "callTracer" 333 334 var testSuite = []struct { 335 blockNumber rpc.BlockNumber 336 call ethapi.TransactionArgs 337 config *TraceCallConfig 338 expectErr error 339 expect *callTrace 340 }{ 341 // Succcessful call with state overriding 342 { 343 blockNumber: rpc.PendingBlockNumber, 344 call: ethapi.TransactionArgs{ 345 From: &randomAccounts[0].addr, 346 To: &randomAccounts[1].addr, 347 Value: (*hexutil.Big)(big.NewInt(1000)), 348 }, 349 config: &TraceCallConfig{ 350 Tracer: &tracer, 351 StateOverrides: ðapi.StateOverride{ 352 randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 353 }, 354 }, 355 expectErr: nil, 356 expect: &callTrace{ 357 Type: "CALL", 358 From: randomAccounts[0].addr, 359 To: randomAccounts[1].addr, 360 Gas: newRPCUint64(24979000), 361 GasUsed: newRPCUint64(0), 362 Value: (*hexutil.Big)(big.NewInt(1000)), 363 }, 364 }, 365 // Invalid call without state overriding 366 { 367 blockNumber: rpc.PendingBlockNumber, 368 call: ethapi.TransactionArgs{ 369 From: &randomAccounts[0].addr, 370 To: &randomAccounts[1].addr, 371 Value: (*hexutil.Big)(big.NewInt(1000)), 372 }, 373 config: &TraceCallConfig{ 374 Tracer: &tracer, 375 }, 376 expectErr: core.ErrInsufficientFunds, 377 expect: nil, 378 }, 379 // Successful simple contract call 380 // 381 // // SPDX-License-Identifier: GPL-3.0 382 // 383 // pragma solidity >=0.7.0 <0.8.0; 384 // 385 // /** 386 // * @title Storage 387 // * @dev Store & retrieve value in a variable 388 // */ 389 // contract Storage { 390 // uint256 public number; 391 // constructor() { 392 // number = block.number; 393 // } 394 // } 395 { 396 blockNumber: rpc.PendingBlockNumber, 397 call: ethapi.TransactionArgs{ 398 From: &randomAccounts[0].addr, 399 To: &randomAccounts[2].addr, 400 Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number() 401 }, 402 config: &TraceCallConfig{ 403 Tracer: &tracer, 404 StateOverrides: ðapi.StateOverride{ 405 randomAccounts[2].addr: ethapi.OverrideAccount{ 406 Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), 407 StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), 408 }, 409 }, 410 }, 411 expectErr: nil, 412 expect: &callTrace{ 413 Type: "CALL", 414 From: randomAccounts[0].addr, 415 To: randomAccounts[2].addr, 416 Input: hexutil.Bytes(common.Hex2Bytes("8381f58a")), 417 Output: hexutil.Bytes(common.BigToHash(big.NewInt(123)).Bytes()), 418 Gas: newRPCUint64(24978936), 419 GasUsed: newRPCUint64(2283), 420 Value: (*hexutil.Big)(big.NewInt(0)), 421 }, 422 }, 423 } 424 for i, testspec := range testSuite { 425 result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) 426 if testspec.expectErr != nil { 427 if err == nil { 428 t.Errorf("test %d: want error %v, have nothing", i, testspec.expectErr) 429 continue 430 } 431 if !errors.Is(err, testspec.expectErr) { 432 t.Errorf("test %d: error mismatch, want %v, have %v", i, testspec.expectErr, err) 433 } 434 } else { 435 if err != nil { 436 t.Errorf("test %d: want no error, have %v", i, err) 437 continue 438 } 439 ret := new(callTrace) 440 if err := json.Unmarshal(result.(json.RawMessage), ret); err != nil { 441 t.Fatalf("test %d: failed to unmarshal trace result: %v", i, err) 442 } 443 if !jsonEqual(ret, testspec.expect) { 444 // uncomment this for easier debugging 445 //have, _ := json.MarshalIndent(ret, "", " ") 446 //want, _ := json.MarshalIndent(testspec.expect, "", " ") 447 //t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", string(have), string(want)) 448 t.Fatalf("trace mismatch: \nhave %+v\nwant %+v", ret, testspec.expect) 449 } 450 } 451 } 452 } 453 454 func TestTraceTransaction(t *testing.T) { 455 t.Parallel() 456 457 // Initialize test accounts 458 accounts := newAccounts(2) 459 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 460 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 461 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 462 }} 463 target := common.Hash{} 464 signer := types.HomesteadSigner{} 465 api := NewAPI(newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) { 466 // Transfer from account[0] to account[1] 467 // value: 1000 wei 468 // fee: 0 wei 469 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 470 b.AddTx(tx) 471 target = tx.Hash() 472 })) 473 result, err := api.TraceTransaction(context.Background(), target, nil) 474 if err != nil { 475 t.Errorf("Failed to trace transaction %v", err) 476 } 477 if !reflect.DeepEqual(result, ðapi.ExecutionResult{ 478 Gas: params.TxGas, 479 Failed: false, 480 ReturnValue: "", 481 StructLogs: []ethapi.StructLogRes{}, 482 }) { 483 t.Error("Transaction tracing result is different") 484 } 485 } 486 487 func TestTraceBlock(t *testing.T) { 488 t.Parallel() 489 490 // Initialize test accounts 491 accounts := newAccounts(3) 492 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 493 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 494 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 495 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 496 }} 497 genBlocks := 10 498 signer := types.HomesteadSigner{} 499 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 500 // Transfer from account[0] to account[1] 501 // value: 1000 wei 502 // fee: 0 wei 503 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 504 b.AddTx(tx) 505 })) 506 507 var testSuite = []struct { 508 blockNumber rpc.BlockNumber 509 config *TraceConfig 510 expect interface{} 511 expectErr error 512 }{ 513 // Trace genesis block, expect error 514 { 515 blockNumber: rpc.BlockNumber(0), 516 config: nil, 517 expect: nil, 518 expectErr: errors.New("genesis is not traceable"), 519 }, 520 // Trace head block 521 { 522 blockNumber: rpc.BlockNumber(genBlocks), 523 config: nil, 524 expectErr: nil, 525 expect: []*txTraceResult{ 526 { 527 Result: ðapi.ExecutionResult{ 528 Gas: params.TxGas, 529 Failed: false, 530 ReturnValue: "", 531 StructLogs: []ethapi.StructLogRes{}, 532 }, 533 }, 534 }, 535 }, 536 // Trace non-existent block 537 { 538 blockNumber: rpc.BlockNumber(genBlocks + 1), 539 config: nil, 540 expectErr: fmt.Errorf("block #%d not found", genBlocks+1), 541 expect: nil, 542 }, 543 // Trace latest block 544 { 545 blockNumber: rpc.LatestBlockNumber, 546 config: nil, 547 expectErr: nil, 548 expect: []*txTraceResult{ 549 { 550 Result: ðapi.ExecutionResult{ 551 Gas: params.TxGas, 552 Failed: false, 553 ReturnValue: "", 554 StructLogs: []ethapi.StructLogRes{}, 555 }, 556 }, 557 }, 558 }, 559 // Trace pending block 560 { 561 blockNumber: rpc.PendingBlockNumber, 562 config: nil, 563 expectErr: nil, 564 expect: []*txTraceResult{ 565 { 566 Result: ðapi.ExecutionResult{ 567 Gas: params.TxGas, 568 Failed: false, 569 ReturnValue: "", 570 StructLogs: []ethapi.StructLogRes{}, 571 }, 572 }, 573 }, 574 }, 575 } 576 for _, testspec := range testSuite { 577 result, err := api.TraceBlockByNumber(context.Background(), testspec.blockNumber, testspec.config) 578 if testspec.expectErr != nil { 579 if err == nil { 580 t.Errorf("Expect error %v, get nothing", testspec.expectErr) 581 continue 582 } 583 if !reflect.DeepEqual(err, testspec.expectErr) { 584 t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) 585 } 586 } else { 587 if err != nil { 588 t.Errorf("Expect no error, get %v", err) 589 continue 590 } 591 if !reflect.DeepEqual(result, testspec.expect) { 592 t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result) 593 } 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 newRPCUint64(number uint64) *hexutil.Uint64 { 625 rpcUint64 := hexutil.Uint64(number) 626 return &rpcUint64 627 } 628 629 func newRPCBytes(bytes []byte) *hexutil.Bytes { 630 rpcBytes := hexutil.Bytes(bytes) 631 return &rpcBytes 632 } 633 634 func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash { 635 if len(keys) != len(vals) { 636 panic("invalid input") 637 } 638 m := make(map[common.Hash]common.Hash) 639 for i := 0; i < len(keys); i++ { 640 m[keys[i]] = vals[i] 641 } 642 return &m 643 }