github.com/ethereum/go-ethereum@v1.16.1/ethclient/gethclient/gethclient_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 gethclient 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "math/big" 24 "strings" 25 "testing" 26 27 "github.com/ethereum/go-ethereum" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus/ethash" 30 "github.com/ethereum/go-ethereum/core" 31 "github.com/ethereum/go-ethereum/core/types" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/eth" 34 "github.com/ethereum/go-ethereum/eth/ethconfig" 35 "github.com/ethereum/go-ethereum/eth/filters" 36 "github.com/ethereum/go-ethereum/eth/tracers" 37 "github.com/ethereum/go-ethereum/ethclient" 38 "github.com/ethereum/go-ethereum/node" 39 "github.com/ethereum/go-ethereum/params" 40 "github.com/ethereum/go-ethereum/rpc" 41 ) 42 43 var ( 44 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 45 testAddr = crypto.PubkeyToAddress(testKey.PublicKey) 46 testContract = common.HexToAddress("0xbeef") 47 testEmpty = common.HexToAddress("0xeeee") 48 testSlot = common.HexToHash("0xdeadbeef") 49 testValue = crypto.Keccak256Hash(testSlot[:]) 50 testBalance = big.NewInt(2e15) 51 testTxHashes []common.Hash 52 ) 53 54 func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { 55 // Generate test chain. 56 genesis, blocks := generateTestChain() 57 // Create node 58 n, err := node.New(&node.Config{ 59 HTTPModules: []string{"debug", "eth", "admin"}, 60 }) 61 if err != nil { 62 t.Fatalf("can't create new node: %v", err) 63 } 64 // Create Ethereum Service 65 config := ðconfig.Config{Genesis: genesis, RPCGasCap: 1000000} 66 ethservice, err := eth.New(n, config) 67 if err != nil { 68 t.Fatalf("can't create new ethereum service: %v", err) 69 } 70 n.RegisterAPIs(tracers.APIs(ethservice.APIBackend)) 71 72 filterSystem := filters.NewFilterSystem(ethservice.APIBackend, filters.Config{}) 73 n.RegisterAPIs([]rpc.API{{ 74 Namespace: "eth", 75 Service: filters.NewFilterAPI(filterSystem), 76 }}) 77 78 // Import the test chain. 79 if err := n.Start(); err != nil { 80 t.Fatalf("can't start test node: %v", err) 81 } 82 if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil { 83 t.Fatalf("can't import test blocks: %v", err) 84 } 85 return n, blocks 86 } 87 88 func generateTestChain() (*core.Genesis, []*types.Block) { 89 genesis := &core.Genesis{ 90 Config: params.AllEthashProtocolChanges, 91 Alloc: types.GenesisAlloc{ 92 testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}, 93 testContract: {Nonce: 1, Code: []byte{0x13, 0x37}}, 94 testEmpty: {Balance: big.NewInt(1)}, 95 }, 96 ExtraData: []byte("test genesis"), 97 Timestamp: 9000, 98 } 99 generate := func(i int, g *core.BlockGen) { 100 g.OffsetTime(5) 101 g.SetExtra([]byte("test")) 102 103 to := common.BytesToAddress([]byte{byte(i + 1)}) 104 tx := types.NewTx(&types.LegacyTx{ 105 Nonce: uint64(i), 106 To: &to, 107 Value: big.NewInt(int64(2*i + 1)), 108 Gas: params.TxGas, 109 GasPrice: big.NewInt(params.InitialBaseFee), 110 Data: nil, 111 }) 112 tx, _ = types.SignTx(tx, types.LatestSignerForChainID(genesis.Config.ChainID), testKey) 113 g.AddTx(tx) 114 testTxHashes = append(testTxHashes, tx.Hash()) 115 } 116 _, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 1, generate) 117 blocks = append([]*types.Block{genesis.ToBlock()}, blocks...) 118 return genesis, blocks 119 } 120 121 func TestGethClient(t *testing.T) { 122 backend, _ := newTestBackend(t) 123 client := backend.Attach() 124 defer backend.Close() 125 defer client.Close() 126 127 tests := []struct { 128 name string 129 test func(t *testing.T) 130 }{ 131 { 132 "TestGetProof1", 133 func(t *testing.T) { testGetProof(t, client, testAddr) }, 134 }, { 135 "TestGetProof2", 136 func(t *testing.T) { testGetProof(t, client, testContract) }, 137 }, { 138 "TestGetProofEmpty", 139 func(t *testing.T) { testGetProof(t, client, testEmpty) }, 140 }, { 141 "TestGetProofNonExistent", 142 func(t *testing.T) { testGetProofNonExistent(t, client) }, 143 }, { 144 "TestGetProofCanonicalizeKeys", 145 func(t *testing.T) { testGetProofCanonicalizeKeys(t, client) }, 146 }, { 147 "TestGCStats", 148 func(t *testing.T) { testGCStats(t, client) }, 149 }, { 150 "TestMemStats", 151 func(t *testing.T) { testMemStats(t, client) }, 152 }, { 153 "TestGetNodeInfo", 154 func(t *testing.T) { testGetNodeInfo(t, client) }, 155 }, { 156 "TestSubscribePendingTxHashes", 157 func(t *testing.T) { testSubscribePendingTransactions(t, client) }, 158 }, { 159 "TestCallContract", 160 func(t *testing.T) { testCallContract(t, client) }, 161 }, { 162 "TestCallContractWithBlockOverrides", 163 func(t *testing.T) { testCallContractWithBlockOverrides(t, client) }, 164 }, 165 // The testaccesslist is a bit time-sensitive: the newTestBackend imports 166 // one block. The `testAccessList` fails if the miner has not yet created a 167 // new pending-block after the import event. 168 // Hence: this test should be last, execute the tests serially. 169 { 170 "TestAccessList", 171 func(t *testing.T) { testAccessList(t, client) }, 172 }, 173 { 174 "TestTraceTransaction", 175 func(t *testing.T) { testTraceTransactions(t, client) }, 176 }, 177 { 178 "TestSetHead", 179 func(t *testing.T) { testSetHead(t, client) }, 180 }, 181 } 182 for _, tt := range tests { 183 t.Run(tt.name, tt.test) 184 } 185 } 186 187 func testAccessList(t *testing.T, client *rpc.Client) { 188 ec := New(client) 189 190 for i, tc := range []struct { 191 msg ethereum.CallMsg 192 wantGas uint64 193 wantErr string 194 wantVMErr string 195 wantAL string 196 }{ 197 { // Test transfer 198 msg: ethereum.CallMsg{ 199 From: testAddr, 200 To: &common.Address{}, 201 Gas: 21000, 202 GasPrice: big.NewInt(875000000), 203 Value: big.NewInt(1), 204 }, 205 wantGas: 21000, 206 wantAL: `[]`, 207 }, 208 { // Test reverting transaction 209 msg: ethereum.CallMsg{ 210 From: testAddr, 211 To: nil, 212 Gas: 100000, 213 GasPrice: big.NewInt(1000000000), 214 Value: big.NewInt(1), 215 Data: common.FromHex("0x608060806080608155fd"), 216 }, 217 wantGas: 77496, 218 wantVMErr: "execution reverted", 219 wantAL: `[ 220 { 221 "address": "0xdb7d6ab1f17c6b31909ae466702703daef9269cf", 222 "storageKeys": [ 223 "0x0000000000000000000000000000000000000000000000000000000000000081" 224 ] 225 } 226 ]`, 227 }, 228 { // error when gasPrice is less than baseFee 229 msg: ethereum.CallMsg{ 230 From: testAddr, 231 To: &common.Address{}, 232 Gas: 21000, 233 GasPrice: big.NewInt(1), // less than baseFee 234 Value: big.NewInt(1), 235 }, 236 wantErr: "max fee per gas less than block base fee", 237 }, 238 { // when gasPrice is not specified 239 msg: ethereum.CallMsg{ 240 From: testAddr, 241 To: &common.Address{}, 242 Gas: 21000, 243 Value: big.NewInt(1), 244 }, 245 wantGas: 21000, 246 wantAL: `[]`, 247 }, 248 } { 249 al, gas, vmErr, err := ec.CreateAccessList(context.Background(), tc.msg) 250 if tc.wantErr != "" { 251 if !strings.Contains(err.Error(), tc.wantErr) { 252 t.Fatalf("test %d: wrong error: %v", i, err) 253 } 254 continue 255 } else if err != nil { 256 t.Fatalf("test %d: wrong error: %v", i, err) 257 } 258 if have, want := vmErr, tc.wantVMErr; have != want { 259 t.Fatalf("test %d: vmErr wrong, have %v want %v", i, have, want) 260 } 261 if have, want := gas, tc.wantGas; have != want { 262 t.Fatalf("test %d: gas wrong, have %v want %v", i, have, want) 263 } 264 haveList, _ := json.MarshalIndent(al, "", " ") 265 if have, want := string(haveList), tc.wantAL; have != want { 266 t.Fatalf("test %d: access list wrong, have:\n%v\nwant:\n%v", i, have, want) 267 } 268 } 269 } 270 271 func testGetProof(t *testing.T, client *rpc.Client, addr common.Address) { 272 ec := New(client) 273 ethcl := ethclient.NewClient(client) 274 result, err := ec.GetProof(context.Background(), addr, []string{testSlot.String()}, nil) 275 if err != nil { 276 t.Fatal(err) 277 } 278 if result.Address != addr { 279 t.Fatalf("unexpected address, have: %v want: %v", result.Address, addr) 280 } 281 // test nonce 282 if nonce, _ := ethcl.NonceAt(context.Background(), addr, nil); result.Nonce != nonce { 283 t.Fatalf("invalid nonce, want: %v got: %v", nonce, result.Nonce) 284 } 285 // test balance 286 if balance, _ := ethcl.BalanceAt(context.Background(), addr, nil); result.Balance.Cmp(balance) != 0 { 287 t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance) 288 } 289 // test storage 290 if len(result.StorageProof) != 1 { 291 t.Fatalf("invalid storage proof, want 1 proof, got %v proof(s)", len(result.StorageProof)) 292 } 293 for _, proof := range result.StorageProof { 294 if proof.Key != testSlot.String() { 295 t.Fatalf("invalid storage proof key, want: %q, got: %q", testSlot.String(), proof.Key) 296 } 297 slotValue, _ := ethcl.StorageAt(context.Background(), addr, common.HexToHash(proof.Key), nil) 298 if have, want := common.BigToHash(proof.Value), common.BytesToHash(slotValue); have != want { 299 t.Fatalf("addr %x, invalid storage proof value: have: %v, want: %v", addr, have, want) 300 } 301 } 302 // test code 303 code, _ := ethcl.CodeAt(context.Background(), addr, nil) 304 if have, want := result.CodeHash, crypto.Keccak256Hash(code); have != want { 305 t.Fatalf("codehash wrong, have %v want %v ", have, want) 306 } 307 } 308 309 func testGetProofCanonicalizeKeys(t *testing.T, client *rpc.Client) { 310 ec := New(client) 311 312 // Tests with non-canon input for storage keys. 313 // Here we check that the storage key is canonicalized. 314 result, err := ec.GetProof(context.Background(), testAddr, []string{"0x0dEadbeef"}, nil) 315 if err != nil { 316 t.Fatal(err) 317 } 318 if result.StorageProof[0].Key != "0xdeadbeef" { 319 t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) 320 } 321 if result, err = ec.GetProof(context.Background(), testAddr, []string{"0x000deadbeef"}, nil); err != nil { 322 t.Fatal(err) 323 } 324 if result.StorageProof[0].Key != "0xdeadbeef" { 325 t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) 326 } 327 328 // If the requested storage key is 32 bytes long, it will be returned as is. 329 hashSizedKey := "0x00000000000000000000000000000000000000000000000000000000deadbeef" 330 result, err = ec.GetProof(context.Background(), testAddr, []string{hashSizedKey}, nil) 331 if err != nil { 332 t.Fatal(err) 333 } 334 if result.StorageProof[0].Key != hashSizedKey { 335 t.Fatalf("wrong storage key encoding in proof: %q", result.StorageProof[0].Key) 336 } 337 } 338 339 func testGetProofNonExistent(t *testing.T, client *rpc.Client) { 340 addr := common.HexToAddress("0x0001") 341 ec := New(client) 342 result, err := ec.GetProof(context.Background(), addr, nil, nil) 343 if err != nil { 344 t.Fatal(err) 345 } 346 if result.Address != addr { 347 t.Fatalf("unexpected address, have: %v want: %v", result.Address, addr) 348 } 349 // test nonce 350 if result.Nonce != 0 { 351 t.Fatalf("invalid nonce, want: %v got: %v", 0, result.Nonce) 352 } 353 // test balance 354 if result.Balance.Sign() != 0 { 355 t.Fatalf("invalid balance, want: %v got: %v", 0, result.Balance) 356 } 357 // test storage 358 if have := len(result.StorageProof); have != 0 { 359 t.Fatalf("invalid storage proof, want 0 proof, got %v proof(s)", have) 360 } 361 // test codeHash 362 if have, want := result.CodeHash, (common.Hash{}); have != want { 363 t.Fatalf("codehash wrong, have %v want %v ", have, want) 364 } 365 // test codeHash 366 if have, want := result.StorageHash, (common.Hash{}); have != want { 367 t.Fatalf("storagehash wrong, have %v want %v ", have, want) 368 } 369 } 370 371 func testGCStats(t *testing.T, client *rpc.Client) { 372 ec := New(client) 373 _, err := ec.GCStats(context.Background()) 374 if err != nil { 375 t.Fatal(err) 376 } 377 } 378 379 func testMemStats(t *testing.T, client *rpc.Client) { 380 ec := New(client) 381 stats, err := ec.MemStats(context.Background()) 382 if err != nil { 383 t.Fatal(err) 384 } 385 if stats.Alloc == 0 { 386 t.Fatal("Invalid mem stats retrieved") 387 } 388 } 389 390 func testGetNodeInfo(t *testing.T, client *rpc.Client) { 391 ec := New(client) 392 info, err := ec.GetNodeInfo(context.Background()) 393 if err != nil { 394 t.Fatal(err) 395 } 396 397 if info.Name == "" { 398 t.Fatal("Invalid node info retrieved") 399 } 400 } 401 402 func testSetHead(t *testing.T, client *rpc.Client) { 403 ec := New(client) 404 err := ec.SetHead(context.Background(), big.NewInt(0)) 405 if err != nil { 406 t.Fatal(err) 407 } 408 } 409 410 func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) { 411 ec := New(client) 412 ethcl := ethclient.NewClient(client) 413 414 // Subscribe to Transactions 415 ch1 := make(chan common.Hash) 416 ec.SubscribePendingTransactions(context.Background(), ch1) 417 418 // Subscribe to Transactions 419 ch2 := make(chan *types.Transaction) 420 ec.SubscribeFullPendingTransactions(context.Background(), ch2) 421 422 // Send a transaction 423 chainID, err := ethcl.ChainID(context.Background()) 424 if err != nil { 425 t.Fatal(err) 426 } 427 nonce, err := ethcl.NonceAt(context.Background(), testAddr, nil) 428 if err != nil { 429 t.Fatal(err) 430 } 431 // Create transaction 432 tx := types.NewTransaction(nonce, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil) 433 signer := types.LatestSignerForChainID(chainID) 434 signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey) 435 if err != nil { 436 t.Fatal(err) 437 } 438 signedTx, err := tx.WithSignature(signer, signature) 439 if err != nil { 440 t.Fatal(err) 441 } 442 // Send transaction 443 err = ethcl.SendTransaction(context.Background(), signedTx) 444 if err != nil { 445 t.Fatal(err) 446 } 447 // Check that the transaction was sent over the channel 448 hash := <-ch1 449 if hash != signedTx.Hash() { 450 t.Fatalf("Invalid tx hash received, got %v, want %v", hash, signedTx.Hash()) 451 } 452 // Check that the transaction was sent over the channel 453 tx = <-ch2 454 if tx.Hash() != signedTx.Hash() { 455 t.Fatalf("Invalid tx hash received, got %v, want %v", tx.Hash(), signedTx.Hash()) 456 } 457 } 458 459 func testCallContract(t *testing.T, client *rpc.Client) { 460 ec := New(client) 461 msg := ethereum.CallMsg{ 462 From: testAddr, 463 To: &common.Address{}, 464 Gas: 21000, 465 GasPrice: big.NewInt(1000000000), 466 Value: big.NewInt(1), 467 } 468 // CallContract without override 469 if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil { 470 t.Fatalf("unexpected error: %v", err) 471 } 472 // CallContract with override 473 override := OverrideAccount{ 474 Nonce: 1, 475 } 476 mapAcc := make(map[common.Address]OverrideAccount) 477 mapAcc[testAddr] = override 478 if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc); err != nil { 479 t.Fatalf("unexpected error: %v", err) 480 } 481 } 482 483 func testTraceTransactions(t *testing.T, client *rpc.Client) { 484 ec := New(client) 485 for _, txHash := range testTxHashes { 486 // Struct logger 487 _, err := ec.TraceTransaction(context.Background(), txHash, nil) 488 if err != nil { 489 t.Fatal(err) 490 } 491 492 // Struct logger 493 _, err = ec.TraceTransaction(context.Background(), txHash, 494 &tracers.TraceConfig{}, 495 ) 496 if err != nil { 497 t.Fatal(err) 498 } 499 } 500 } 501 502 func TestOverrideAccountMarshal(t *testing.T) { 503 om := map[common.Address]OverrideAccount{ 504 {0x11}: { 505 // Zero-valued nonce is not overridden, but simply dropped by the encoder. 506 Nonce: 0, 507 }, 508 {0xaa}: { 509 Nonce: 5, 510 }, 511 {0xbb}: { 512 Code: []byte{1}, 513 }, 514 {0xcc}: { 515 // 'code', 'balance', 'state' should be set when input is 516 // a non-nil but empty value. 517 Code: []byte{}, 518 Balance: big.NewInt(0), 519 State: map[common.Hash]common.Hash{}, 520 // For 'stateDiff' the behavior is different, empty map 521 // is ignored because it makes no difference. 522 StateDiff: map[common.Hash]common.Hash{}, 523 }, 524 } 525 526 marshalled, err := json.MarshalIndent(&om, "", " ") 527 if err != nil { 528 t.Fatalf("unexpected error: %v", err) 529 } 530 531 expected := `{ 532 "0x1100000000000000000000000000000000000000": {}, 533 "0xaa00000000000000000000000000000000000000": { 534 "nonce": "0x5" 535 }, 536 "0xbb00000000000000000000000000000000000000": { 537 "code": "0x01" 538 }, 539 "0xcc00000000000000000000000000000000000000": { 540 "code": "0x", 541 "balance": "0x0", 542 "state": {} 543 } 544 }` 545 546 if string(marshalled) != expected { 547 t.Error("wrong output:", string(marshalled)) 548 t.Error("want:", expected) 549 } 550 } 551 552 func TestBlockOverridesMarshal(t *testing.T) { 553 for i, tt := range []struct { 554 bo BlockOverrides 555 want string 556 }{ 557 { 558 bo: BlockOverrides{}, 559 want: `{}`, 560 }, 561 { 562 bo: BlockOverrides{ 563 Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), 564 }, 565 want: `{"feeRecipient":"0x1111111111111111111111111111111111111111"}`, 566 }, 567 { 568 bo: BlockOverrides{ 569 Number: big.NewInt(1), 570 Difficulty: big.NewInt(2), 571 Time: 3, 572 GasLimit: 4, 573 BaseFee: big.NewInt(5), 574 }, 575 want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFeePerGas":"0x5"}`, 576 }, 577 } { 578 marshalled, err := json.Marshal(&tt.bo) 579 if err != nil { 580 t.Fatalf("unexpected error: %v", err) 581 } 582 if string(marshalled) != tt.want { 583 t.Errorf("Testcase #%d failed. expected\n%s\ngot\n%s", i, tt.want, string(marshalled)) 584 } 585 } 586 } 587 588 func testCallContractWithBlockOverrides(t *testing.T, client *rpc.Client) { 589 ec := New(client) 590 msg := ethereum.CallMsg{ 591 From: testAddr, 592 To: &common.Address{}, 593 Gas: 50000, 594 GasPrice: big.NewInt(1000000000), 595 Value: big.NewInt(1), 596 } 597 override := OverrideAccount{ 598 // Returns coinbase address. 599 Code: common.FromHex("0x41806000526014600cf3"), 600 } 601 mapAcc := make(map[common.Address]OverrideAccount) 602 mapAcc[common.Address{}] = override 603 res, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc) 604 if err != nil { 605 t.Fatalf("unexpected error: %v", err) 606 } 607 if !bytes.Equal(res, common.FromHex("0x0000000000000000000000000000000000000000")) { 608 t.Fatalf("unexpected result: %x", res) 609 } 610 611 // Now test with block overrides 612 bo := BlockOverrides{ 613 Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"), 614 } 615 res, err = ec.CallContractWithBlockOverrides(context.Background(), msg, big.NewInt(0), &mapAcc, bo) 616 if err != nil { 617 t.Fatalf("unexpected error: %v", err) 618 } 619 if !bytes.Equal(res, common.FromHex("0x1111111111111111111111111111111111111111")) { 620 t.Fatalf("unexpected result: %x", res) 621 } 622 }