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