github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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/scroll-tech/go-ethereum/common" 33 "github.com/scroll-tech/go-ethereum/common/hexutil" 34 "github.com/scroll-tech/go-ethereum/consensus" 35 "github.com/scroll-tech/go-ethereum/consensus/ethash" 36 "github.com/scroll-tech/go-ethereum/core" 37 "github.com/scroll-tech/go-ethereum/core/rawdb" 38 "github.com/scroll-tech/go-ethereum/core/state" 39 "github.com/scroll-tech/go-ethereum/core/types" 40 "github.com/scroll-tech/go-ethereum/core/vm" 41 "github.com/scroll-tech/go-ethereum/crypto" 42 "github.com/scroll-tech/go-ethereum/ethdb" 43 "github.com/scroll-tech/go-ethereum/internal/ethapi" 44 "github.com/scroll-tech/go-ethereum/params" 45 "github.com/scroll-tech/go-ethereum/rollup/fees" 46 "github.com/scroll-tech/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 TrieCleanLimit: 256, 80 TrieDirtyLimit: 256, 81 TrieTimeLimit: 5 * time.Minute, 82 SnapshotLimit: 0, 83 TrieDirtyDisabled: true, // Archive mode 84 } 85 chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil, false) 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) CacheConfig() *core.CacheConfig { 135 return b.chain.CacheConfig() 136 } 137 138 func (b *testBackend) Engine() consensus.Engine { 139 return b.engine 140 } 141 142 func (b *testBackend) ChainDb() ethdb.Database { 143 return b.chaindb 144 } 145 146 func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (*state.StateDB, error) { 147 statedb, err := b.chain.StateAt(block.Root()) 148 if err != nil { 149 return nil, errStateNotFound 150 } 151 return statedb, nil 152 } 153 154 func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) { 155 parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) 156 if parent == nil { 157 return nil, vm.BlockContext{}, nil, errBlockNotFound 158 } 159 statedb, err := b.chain.StateAt(parent.Root()) 160 if err != nil { 161 return nil, vm.BlockContext{}, nil, errStateNotFound 162 } 163 if txIndex == 0 && len(block.Transactions()) == 0 { 164 return nil, vm.BlockContext{}, statedb, nil 165 } 166 // Recompute transactions up to the target index. 167 signer := types.MakeSigner(b.chainConfig, block.Number()) 168 for idx, tx := range block.Transactions() { 169 msg, _ := tx.AsMessage(signer, block.BaseFee()) 170 txContext := core.NewEVMTxContext(msg) 171 context := core.NewEVMBlockContext(block.Header(), b.chain, b.chainConfig, nil) 172 if idx == txIndex { 173 return msg, context, statedb, nil 174 } 175 vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) 176 l1DataFee, err := fees.CalculateL1DataFee(tx, statedb) 177 if err != nil { 178 return nil, vm.BlockContext{}, nil, err 179 } 180 if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()), l1DataFee); err != nil { 181 return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 182 } 183 statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) 184 } 185 return nil, vm.BlockContext{}, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) 186 } 187 188 func TestTraceCall(t *testing.T) { 189 t.Parallel() 190 191 // Initialize test accounts 192 accounts := newAccounts(3) 193 genesis := &core.Genesis{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 genBlocks := 10 199 signer := types.HomesteadSigner{} 200 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 201 // Transfer from account[0] to account[1] 202 // value: 1000 wei 203 // fee: 0 wei 204 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 205 b.AddTx(tx) 206 })) 207 208 var testSuite = []struct { 209 blockNumber rpc.BlockNumber 210 call ethapi.TransactionArgs 211 config *TraceCallConfig 212 expectErr error 213 expect interface{} 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: &types.ExecutionResult{ 226 L1DataFee: (*hexutil.Big)(big.NewInt(0)), 227 Gas: params.TxGas, 228 Failed: false, 229 ReturnValue: "", 230 StructLogs: []*types.StructLogRes{}, 231 }, 232 }, 233 // Standard JSON trace upon the head, plain transfer. 234 { 235 blockNumber: rpc.BlockNumber(genBlocks), 236 call: ethapi.TransactionArgs{ 237 From: &accounts[0].addr, 238 To: &accounts[1].addr, 239 Value: (*hexutil.Big)(big.NewInt(1000)), 240 }, 241 config: nil, 242 expectErr: nil, 243 expect: &types.ExecutionResult{ 244 L1DataFee: (*hexutil.Big)(big.NewInt(0)), 245 Gas: params.TxGas, 246 Failed: false, 247 ReturnValue: "", 248 StructLogs: []*types.StructLogRes{}, 249 }, 250 }, 251 // Standard JSON trace upon the non-existent block, error expects 252 { 253 blockNumber: rpc.BlockNumber(genBlocks + 1), 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: fmt.Errorf("block #%d not found", genBlocks+1), 261 expect: nil, 262 }, 263 // Standard JSON trace upon the latest block 264 { 265 blockNumber: rpc.LatestBlockNumber, 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: nil, 273 expect: &types.ExecutionResult{ 274 L1DataFee: (*hexutil.Big)(big.NewInt(0)), 275 Gas: params.TxGas, 276 Failed: false, 277 ReturnValue: "", 278 StructLogs: []*types.StructLogRes{}, 279 }, 280 }, 281 // Standard JSON trace upon the pending block 282 { 283 blockNumber: rpc.PendingBlockNumber, 284 call: ethapi.TransactionArgs{ 285 From: &accounts[0].addr, 286 To: &accounts[1].addr, 287 Value: (*hexutil.Big)(big.NewInt(1000)), 288 }, 289 config: nil, 290 expectErr: nil, 291 expect: &types.ExecutionResult{ 292 L1DataFee: (*hexutil.Big)(big.NewInt(0)), 293 Gas: params.TxGas, 294 Failed: false, 295 ReturnValue: "", 296 StructLogs: []*types.StructLogRes{}, 297 }, 298 }, 299 } 300 for _, testspec := range testSuite { 301 result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config) 302 if testspec.expectErr != nil { 303 if err == nil { 304 t.Errorf("Expect error %v, get nothing", testspec.expectErr) 305 continue 306 } 307 if !reflect.DeepEqual(err, testspec.expectErr) { 308 t.Errorf("Error mismatch, want %v, get %v", testspec.expectErr, err) 309 } 310 } else { 311 if err != nil { 312 t.Errorf("Expect no error, get %v", err) 313 continue 314 } 315 if !reflect.DeepEqual(result, testspec.expect) { 316 t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result) 317 } 318 } 319 } 320 } 321 322 func TestTraceTransaction(t *testing.T) { 323 t.Parallel() 324 325 // Initialize test accounts 326 accounts := newAccounts(2) 327 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 328 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 329 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 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 if !reflect.DeepEqual(result, &types.ExecutionResult{ 346 L1DataFee: (*hexutil.Big)(big.NewInt(0)), 347 Gas: params.TxGas, 348 Failed: false, 349 ReturnValue: "", 350 StructLogs: []*types.StructLogRes{}, 351 }) { 352 t.Error("Transaction tracing result is different") 353 } 354 } 355 356 func TestTraceBlock(t *testing.T) { 357 t.Parallel() 358 359 // Initialize test accounts 360 accounts := newAccounts(3) 361 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 362 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 363 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 364 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 365 }} 366 genBlocks := 10 367 signer := types.HomesteadSigner{} 368 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 369 // Transfer from account[0] to account[1] 370 // value: 1000 wei 371 // fee: 0 wei 372 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 373 b.AddTx(tx) 374 })) 375 376 var testSuite = []struct { 377 blockNumber rpc.BlockNumber 378 config *TraceConfig 379 want string 380 expectErr error 381 }{ 382 // Trace genesis block, expect error 383 { 384 blockNumber: rpc.BlockNumber(0), 385 expectErr: errors.New("genesis is not traceable"), 386 }, 387 // Trace head block 388 { 389 blockNumber: rpc.BlockNumber(genBlocks), 390 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 391 }, 392 // Trace non-existent block 393 { 394 blockNumber: rpc.BlockNumber(genBlocks + 1), 395 expectErr: fmt.Errorf("block #%d not found", genBlocks+1), 396 }, 397 // Trace latest block 398 { 399 blockNumber: rpc.LatestBlockNumber, 400 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 401 }, 402 // Trace pending block 403 { 404 blockNumber: rpc.PendingBlockNumber, 405 want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, 406 }, 407 } 408 for i, tc := range testSuite { 409 result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config) 410 if tc.expectErr != nil { 411 if err == nil { 412 t.Errorf("test %d, want error %v", i, tc.expectErr) 413 continue 414 } 415 if !reflect.DeepEqual(err, tc.expectErr) { 416 t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err) 417 } 418 continue 419 } 420 if err != nil { 421 t.Errorf("test %d, want no error, have %v", i, err) 422 continue 423 } 424 have, _ := json.Marshal(result) 425 want := tc.want 426 if string(have) != want { 427 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want) 428 } 429 } 430 } 431 432 func TestTracingWithOverrides(t *testing.T) { 433 t.Parallel() 434 // Initialize test accounts 435 accounts := newAccounts(3) 436 genesis := &core.Genesis{Alloc: core.GenesisAlloc{ 437 accounts[0].addr: {Balance: big.NewInt(params.Ether)}, 438 accounts[1].addr: {Balance: big.NewInt(params.Ether)}, 439 accounts[2].addr: {Balance: big.NewInt(params.Ether)}, 440 }} 441 genBlocks := 10 442 signer := types.HomesteadSigner{} 443 api := NewAPI(newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { 444 // Transfer from account[0] to account[1] 445 // value: 1000 wei 446 // fee: 0 wei 447 tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) 448 b.AddTx(tx) 449 })) 450 randomAccounts := newAccounts(3) 451 type res struct { 452 Gas int 453 Failed bool 454 returnValue string 455 } 456 var testSuite = []struct { 457 blockNumber rpc.BlockNumber 458 call ethapi.TransactionArgs 459 config *TraceCallConfig 460 expectErr error 461 want string 462 }{ 463 // Call which can only succeed if state is state overridden 464 { 465 blockNumber: rpc.PendingBlockNumber, 466 call: ethapi.TransactionArgs{ 467 From: &randomAccounts[0].addr, 468 To: &randomAccounts[1].addr, 469 Value: (*hexutil.Big)(big.NewInt(1000)), 470 }, 471 config: &TraceCallConfig{ 472 StateOverrides: ðapi.StateOverride{ 473 randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, 474 }, 475 }, 476 want: `{"gas":21000,"failed":false,"returnValue":""}`, 477 }, 478 // Invalid call without state overriding 479 { 480 blockNumber: rpc.PendingBlockNumber, 481 call: ethapi.TransactionArgs{ 482 From: &randomAccounts[0].addr, 483 To: &randomAccounts[1].addr, 484 Value: (*hexutil.Big)(big.NewInt(1000)), 485 }, 486 config: &TraceCallConfig{}, 487 expectErr: core.ErrInsufficientFunds, 488 }, 489 // Successful simple contract call 490 // 491 // // SPDX-License-Identifier: GPL-3.0 492 // 493 // pragma solidity >=0.7.0 <0.8.0; 494 // 495 // /** 496 // * @title Storage 497 // * @dev Store & retrieve value in a variable 498 // */ 499 // contract Storage { 500 // uint256 public number; 501 // constructor() { 502 // number = block.number; 503 // } 504 // } 505 { 506 blockNumber: rpc.PendingBlockNumber, 507 call: ethapi.TransactionArgs{ 508 From: &randomAccounts[0].addr, 509 To: &randomAccounts[2].addr, 510 Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number() 511 }, 512 config: &TraceCallConfig{ 513 //Tracer: &tracer, 514 StateOverrides: ðapi.StateOverride{ 515 randomAccounts[2].addr: ethapi.OverrideAccount{ 516 Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")), 517 StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}), 518 }, 519 }, 520 }, 521 want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`, 522 }, 523 } 524 for i, tc := range testSuite { 525 result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config) 526 if tc.expectErr != nil { 527 if err == nil { 528 t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) 529 continue 530 } 531 if !errors.Is(err, tc.expectErr) { 532 t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err) 533 } 534 continue 535 } 536 if err != nil { 537 t.Errorf("test %d: want no error, have %v", i, err) 538 continue 539 } 540 // Turn result into res-struct 541 var ( 542 have res 543 want res 544 ) 545 resBytes, _ := json.Marshal(result) 546 json.Unmarshal(resBytes, &have) 547 json.Unmarshal([]byte(tc.want), &want) 548 if !reflect.DeepEqual(have, want) { 549 t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(resBytes), want) 550 } 551 } 552 } 553 554 type Account struct { 555 key *ecdsa.PrivateKey 556 addr common.Address 557 } 558 559 type Accounts []Account 560 561 func (a Accounts) Len() int { return len(a) } 562 func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 563 func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } 564 565 func newAccounts(n int) (accounts Accounts) { 566 for i := 0; i < n; i++ { 567 key, _ := crypto.GenerateKey() 568 addr := crypto.PubkeyToAddress(key.PublicKey) 569 accounts = append(accounts, Account{key: key, addr: addr}) 570 } 571 sort.Sort(accounts) 572 return accounts 573 } 574 575 func newRPCBalance(balance *big.Int) **hexutil.Big { 576 rpcBalance := (*hexutil.Big)(balance) 577 return &rpcBalance 578 } 579 580 func newRPCBytes(bytes []byte) *hexutil.Bytes { 581 rpcBytes := hexutil.Bytes(bytes) 582 return &rpcBytes 583 } 584 585 func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash { 586 if len(keys) != len(vals) { 587 panic("invalid input") 588 } 589 m := make(map[common.Hash]common.Hash) 590 for i := 0; i < len(keys); i++ { 591 m[keys[i]] = vals[i] 592 } 593 return &m 594 }