github.com/phillinzzz/newBsc@v1.1.6/ethclient/ethclient_test.go (about) 1 // Copyright 2016 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 ethclient 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "math/big" 24 "reflect" 25 "testing" 26 "time" 27 28 "github.com/phillinzzz/newBsc" 29 "github.com/phillinzzz/newBsc/common" 30 "github.com/phillinzzz/newBsc/consensus/ethash" 31 "github.com/phillinzzz/newBsc/core" 32 "github.com/phillinzzz/newBsc/core/rawdb" 33 "github.com/phillinzzz/newBsc/core/types" 34 "github.com/phillinzzz/newBsc/core/vm" 35 "github.com/phillinzzz/newBsc/crypto" 36 "github.com/phillinzzz/newBsc/eth" 37 "github.com/phillinzzz/newBsc/eth/ethconfig" 38 "github.com/phillinzzz/newBsc/ethdb/memorydb" 39 "github.com/phillinzzz/newBsc/node" 40 "github.com/phillinzzz/newBsc/params" 41 "github.com/phillinzzz/newBsc/rpc" 42 ) 43 44 // Verify that Client implements the ethereum interfaces. 45 var ( 46 _ = ethereum.ChainReader(&Client{}) 47 _ = ethereum.TransactionReader(&Client{}) 48 _ = ethereum.ChainStateReader(&Client{}) 49 _ = ethereum.ChainSyncReader(&Client{}) 50 _ = ethereum.ContractCaller(&Client{}) 51 _ = ethereum.GasEstimator(&Client{}) 52 _ = ethereum.GasPricer(&Client{}) 53 _ = ethereum.LogFilterer(&Client{}) 54 _ = ethereum.PendingStateReader(&Client{}) 55 // _ = ethereum.PendingStateEventer(&Client{}) 56 _ = ethereum.PendingContractCaller(&Client{}) 57 ) 58 59 func TestToFilterArg(t *testing.T) { 60 blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock") 61 addresses := []common.Address{ 62 common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"), 63 } 64 blockHash := common.HexToHash( 65 "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb", 66 ) 67 68 for _, testCase := range []struct { 69 name string 70 input ethereum.FilterQuery 71 output interface{} 72 err error 73 }{ 74 { 75 "without BlockHash", 76 ethereum.FilterQuery{ 77 Addresses: addresses, 78 FromBlock: big.NewInt(1), 79 ToBlock: big.NewInt(2), 80 Topics: [][]common.Hash{}, 81 }, 82 map[string]interface{}{ 83 "address": addresses, 84 "fromBlock": "0x1", 85 "toBlock": "0x2", 86 "topics": [][]common.Hash{}, 87 }, 88 nil, 89 }, 90 { 91 "with nil fromBlock and nil toBlock", 92 ethereum.FilterQuery{ 93 Addresses: addresses, 94 Topics: [][]common.Hash{}, 95 }, 96 map[string]interface{}{ 97 "address": addresses, 98 "fromBlock": "0x0", 99 "toBlock": "latest", 100 "topics": [][]common.Hash{}, 101 }, 102 nil, 103 }, 104 { 105 "with negative fromBlock and negative toBlock", 106 ethereum.FilterQuery{ 107 Addresses: addresses, 108 FromBlock: big.NewInt(-1), 109 ToBlock: big.NewInt(-1), 110 Topics: [][]common.Hash{}, 111 }, 112 map[string]interface{}{ 113 "address": addresses, 114 "fromBlock": "pending", 115 "toBlock": "pending", 116 "topics": [][]common.Hash{}, 117 }, 118 nil, 119 }, 120 { 121 "with blockhash", 122 ethereum.FilterQuery{ 123 Addresses: addresses, 124 BlockHash: &blockHash, 125 Topics: [][]common.Hash{}, 126 }, 127 map[string]interface{}{ 128 "address": addresses, 129 "blockHash": blockHash, 130 "topics": [][]common.Hash{}, 131 }, 132 nil, 133 }, 134 { 135 "with blockhash and from block", 136 ethereum.FilterQuery{ 137 Addresses: addresses, 138 BlockHash: &blockHash, 139 FromBlock: big.NewInt(1), 140 Topics: [][]common.Hash{}, 141 }, 142 nil, 143 blockHashErr, 144 }, 145 { 146 "with blockhash and to block", 147 ethereum.FilterQuery{ 148 Addresses: addresses, 149 BlockHash: &blockHash, 150 ToBlock: big.NewInt(1), 151 Topics: [][]common.Hash{}, 152 }, 153 nil, 154 blockHashErr, 155 }, 156 { 157 "with blockhash and both from / to block", 158 ethereum.FilterQuery{ 159 Addresses: addresses, 160 BlockHash: &blockHash, 161 FromBlock: big.NewInt(1), 162 ToBlock: big.NewInt(2), 163 Topics: [][]common.Hash{}, 164 }, 165 nil, 166 blockHashErr, 167 }, 168 } { 169 t.Run(testCase.name, func(t *testing.T) { 170 output, err := toFilterArg(testCase.input) 171 if (testCase.err == nil) != (err == nil) { 172 t.Fatalf("expected error %v but got %v", testCase.err, err) 173 } 174 if testCase.err != nil { 175 if testCase.err.Error() != err.Error() { 176 t.Fatalf("expected error %v but got %v", testCase.err, err) 177 } 178 } else if !reflect.DeepEqual(testCase.output, output) { 179 t.Fatalf("expected filter arg %v but got %v", testCase.output, output) 180 } 181 }) 182 } 183 } 184 185 var ( 186 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 187 testAddr = crypto.PubkeyToAddress(testKey.PublicKey) 188 testBalance = big.NewInt(2e10) 189 testBlockNum = 128 190 testBlocks = []testBlockParam{ 191 { 192 // This txs params also used to default block. 193 blockNr: 10, 194 txs: []testTransactionParam{}, 195 }, 196 { 197 blockNr: 11, 198 txs: []testTransactionParam{ 199 { 200 to: common.Address{0x01}, 201 value: big.NewInt(1), 202 gasPrice: big.NewInt(1), 203 data: nil, 204 }, 205 }, 206 }, 207 { 208 blockNr: 12, 209 txs: []testTransactionParam{ 210 { 211 to: common.Address{0x01}, 212 value: big.NewInt(1), 213 gasPrice: big.NewInt(1), 214 data: nil, 215 }, 216 { 217 to: common.Address{0x02}, 218 value: big.NewInt(2), 219 gasPrice: big.NewInt(2), 220 data: nil, 221 }, 222 }, 223 }, 224 { 225 blockNr: 13, 226 txs: []testTransactionParam{ 227 { 228 to: common.Address{0x01}, 229 value: big.NewInt(1), 230 gasPrice: big.NewInt(1), 231 data: nil, 232 }, 233 { 234 to: common.Address{0x02}, 235 value: big.NewInt(2), 236 gasPrice: big.NewInt(2), 237 data: nil, 238 }, 239 { 240 to: common.Address{0x03}, 241 value: big.NewInt(3), 242 gasPrice: big.NewInt(3), 243 data: nil, 244 }, 245 }, 246 }, 247 } 248 ) 249 250 type testTransactionParam struct { 251 to common.Address 252 value *big.Int 253 gasPrice *big.Int 254 data []byte 255 } 256 257 type testBlockParam struct { 258 blockNr int 259 txs []testTransactionParam 260 } 261 262 func newTestBackend(t *testing.T) (*node.Node, []*types.Block) { 263 // Generate test chain. 264 genesis, blocks := generateTestChain() 265 // Create node 266 n, err := node.New(&node.Config{}) 267 if err != nil { 268 t.Fatalf("can't create new node: %v", err) 269 } 270 // Create Ethereum Service 271 config := ðconfig.Config{Genesis: genesis} 272 config.Ethash.PowMode = ethash.ModeFake 273 config.SnapshotCache = 256 274 ethservice, err := eth.New(n, config) 275 if err != nil { 276 t.Fatalf("can't create new ethereum service: %v", err) 277 } 278 // Import the test chain. 279 if err := n.Start(); err != nil { 280 t.Fatalf("can't start test node: %v", err) 281 } 282 if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil { 283 t.Fatalf("can't import test blocks: %v", err) 284 } 285 return n, blocks 286 } 287 288 func generateTestChain() (*core.Genesis, []*types.Block) { 289 signer := types.HomesteadSigner{} 290 // Create a database pre-initialize with a genesis block 291 db := rawdb.NewMemoryDatabase() 292 db.SetDiffStore(memorydb.New()) 293 config := params.AllEthashProtocolChanges 294 genesis := &core.Genesis{ 295 Config: config, 296 Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}}, 297 ExtraData: []byte("test genesis"), 298 Timestamp: 9000, 299 } 300 genesis.MustCommit(db) 301 chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, core.EnablePersistDiff(860000)) 302 generate := func(i int, block *core.BlockGen) { 303 block.OffsetTime(5) 304 block.SetExtra([]byte("test")) 305 //block.SetCoinbase(testAddr) 306 307 for idx, testBlock := range testBlocks { 308 // Specific block setting, the index in this generator has 1 diff from specified blockNr. 309 if i+1 == testBlock.blockNr { 310 for _, testTransaction := range testBlock.txs { 311 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, 312 testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) 313 if err != nil { 314 panic(err) 315 } 316 block.AddTxWithChain(chain, tx) 317 } 318 break 319 } 320 321 // Default block setting. 322 if idx == len(testBlocks)-1 { 323 // We want to simulate an empty middle block, having the same state as the 324 // first one. The last is needs a state change again to force a reorg. 325 for _, testTransaction := range testBlocks[0].txs { 326 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), testTransaction.to, 327 testTransaction.value, params.TxGas, testTransaction.gasPrice, testTransaction.data), signer, testKey) 328 if err != nil { 329 panic(err) 330 } 331 block.AddTxWithChain(chain, tx) 332 } 333 } 334 } 335 } 336 gblock := genesis.ToBlock(db) 337 engine := ethash.NewFaker() 338 blocks, _ := core.GenerateChain(config, gblock, engine, db, testBlockNum, generate) 339 blocks = append([]*types.Block{gblock}, blocks...) 340 return genesis, blocks 341 } 342 343 func TestEthClient(t *testing.T) { 344 backend, chain := newTestBackend(t) 345 client, _ := backend.Attach() 346 defer backend.Close() 347 defer client.Close() 348 349 tests := map[string]struct { 350 test func(t *testing.T) 351 }{ 352 "TestHeader": { 353 func(t *testing.T) { testHeader(t, chain, client) }, 354 }, 355 "TestBalanceAt": { 356 func(t *testing.T) { testBalanceAt(t, client) }, 357 }, 358 "TestTxInBlockInterrupted": { 359 func(t *testing.T) { testTransactionInBlockInterrupted(t, client) }, 360 }, 361 "TestChainID": { 362 func(t *testing.T) { testChainID(t, client) }, 363 }, 364 "TestGetBlock": { 365 func(t *testing.T) { testGetBlock(t, client) }, 366 }, 367 "TestStatusFunctions": { 368 func(t *testing.T) { testStatusFunctions(t, client) }, 369 }, 370 "TestCallContract": { 371 func(t *testing.T) { testCallContract(t, client) }, 372 }, 373 "TestDiffAccounts": { 374 func(t *testing.T) { testDiffAccounts(t, client) }, 375 }, 376 // DO not have TestAtFunctions now, because we do not have pending block now 377 } 378 379 t.Parallel() 380 for name, tt := range tests { 381 t.Run(name, tt.test) 382 } 383 } 384 385 func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { 386 tests := map[string]struct { 387 block *big.Int 388 want *types.Header 389 wantErr error 390 }{ 391 "genesis": { 392 block: big.NewInt(0), 393 want: chain[0].Header(), 394 }, 395 "first_block": { 396 block: big.NewInt(1), 397 want: chain[1].Header(), 398 }, 399 "future_block": { 400 block: big.NewInt(1000000000), 401 want: nil, 402 wantErr: ethereum.NotFound, 403 }, 404 } 405 for name, tt := range tests { 406 t.Run(name, func(t *testing.T) { 407 ec := NewClient(client) 408 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 409 defer cancel() 410 411 got, err := ec.HeaderByNumber(ctx, tt.block) 412 if !errors.Is(err, tt.wantErr) { 413 t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr) 414 } 415 if got != nil && got.Number != nil && got.Number.Sign() == 0 { 416 got.Number = big.NewInt(0) // hack to make DeepEqual work 417 } 418 if !reflect.DeepEqual(got, tt.want) { 419 t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want) 420 } 421 }) 422 } 423 } 424 425 func testBalanceAt(t *testing.T, client *rpc.Client) { 426 tests := map[string]struct { 427 account common.Address 428 block *big.Int 429 want *big.Int 430 wantErr error 431 }{ 432 "valid_account": { 433 account: testAddr, 434 block: big.NewInt(1), 435 want: testBalance, 436 }, 437 "non_existent_account": { 438 account: common.Address{1}, 439 block: big.NewInt(1), 440 want: big.NewInt(0), 441 }, 442 "future_block": { 443 account: testAddr, 444 block: big.NewInt(1000000000), 445 want: big.NewInt(0), 446 wantErr: errors.New("header not found"), 447 }, 448 } 449 for name, tt := range tests { 450 t.Run(name, func(t *testing.T) { 451 ec := NewClient(client) 452 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 453 defer cancel() 454 455 got, err := ec.BalanceAt(ctx, tt.account, tt.block) 456 if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) { 457 t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr) 458 } 459 if got.Cmp(tt.want) != 0 { 460 t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want) 461 } 462 }) 463 } 464 } 465 466 func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { 467 ec := NewClient(client) 468 469 // Get current block by number 470 block, err := ec.BlockByNumber(context.Background(), nil) 471 if err != nil { 472 t.Fatalf("unexpected error: %v", err) 473 } 474 // Test tx in block interupted 475 ctx, cancel := context.WithCancel(context.Background()) 476 cancel() 477 tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1) 478 if tx != nil { 479 t.Fatal("transaction should be nil") 480 } 481 if err == nil || err == ethereum.NotFound { 482 t.Fatal("error should not be nil/notfound") 483 } 484 // Test tx in block not found 485 if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 1); err != ethereum.NotFound { 486 t.Fatal("error should be ethereum.NotFound") 487 } 488 } 489 490 func testChainID(t *testing.T, client *rpc.Client) { 491 ec := NewClient(client) 492 id, err := ec.ChainID(context.Background()) 493 if err != nil { 494 t.Fatalf("unexpected error: %v", err) 495 } 496 if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 { 497 t.Fatalf("ChainID returned wrong number: %+v", id) 498 } 499 } 500 501 func testGetBlock(t *testing.T, client *rpc.Client) { 502 ec := NewClient(client) 503 // Get current block number 504 blockNumber, err := ec.BlockNumber(context.Background()) 505 if err != nil { 506 t.Fatalf("unexpected error: %v", err) 507 } 508 if blockNumber != uint64(testBlockNum) { 509 t.Fatalf("BlockNumber returned wrong number: %d", blockNumber) 510 } 511 // Get current block by number 512 block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber)) 513 if err != nil { 514 t.Fatalf("unexpected error: %v", err) 515 } 516 if block.NumberU64() != blockNumber { 517 t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64()) 518 } 519 // Get current block by hash 520 blockH, err := ec.BlockByHash(context.Background(), block.Hash()) 521 if err != nil { 522 t.Fatalf("unexpected error: %v", err) 523 } 524 if block.Hash() != blockH.Hash() { 525 t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex()) 526 } 527 // Get header by number 528 header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber)) 529 if err != nil { 530 t.Fatalf("unexpected error: %v", err) 531 } 532 if block.Header().Hash() != header.Hash() { 533 t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex()) 534 } 535 // Get header by hash 536 headerH, err := ec.HeaderByHash(context.Background(), block.Hash()) 537 if err != nil { 538 t.Fatalf("unexpected error: %v", err) 539 } 540 if block.Header().Hash() != headerH.Hash() { 541 t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex()) 542 } 543 } 544 545 func testStatusFunctions(t *testing.T, client *rpc.Client) { 546 ec := NewClient(client) 547 548 // Sync progress 549 progress, err := ec.SyncProgress(context.Background()) 550 if err != nil { 551 t.Fatalf("unexpected error: %v", err) 552 } 553 if progress != nil { 554 t.Fatalf("unexpected progress: %v", progress) 555 } 556 // NetworkID 557 networkID, err := ec.NetworkID(context.Background()) 558 if err != nil { 559 t.Fatalf("unexpected error: %v", err) 560 } 561 if networkID.Cmp(big.NewInt(0)) != 0 { 562 t.Fatalf("unexpected networkID: %v", networkID) 563 } 564 // SuggestGasPrice (should suggest 1 Gwei) 565 gasPrice, err := ec.SuggestGasPrice(context.Background()) 566 if err != nil { 567 t.Fatalf("unexpected error: %v", err) 568 } 569 if gasPrice.Cmp(big.NewInt(1000000000)) != 0 { 570 t.Fatalf("unexpected gas price: %v", gasPrice) 571 } 572 } 573 574 func testCallContract(t *testing.T, client *rpc.Client) { 575 ec := NewClient(client) 576 577 // EstimateGas 578 msg := ethereum.CallMsg{ 579 From: testAddr, 580 To: &common.Address{}, 581 Gas: 21000, 582 GasPrice: big.NewInt(1), 583 Value: big.NewInt(1), 584 } 585 gas, err := ec.EstimateGas(context.Background(), msg) 586 if err != nil { 587 t.Fatalf("unexpected error: %v", err) 588 } 589 if gas != 21000 { 590 t.Fatalf("unexpected gas price: %v", gas) 591 } 592 // CallContract 593 if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil { 594 t.Fatalf("unexpected error: %v", err) 595 } 596 // PendingCallCOntract 597 if _, err := ec.PendingCallContract(context.Background(), msg); err != nil { 598 t.Fatalf("unexpected error: %v", err) 599 } 600 } 601 602 func testDiffAccounts(t *testing.T, client *rpc.Client) { 603 ec := NewClient(client) 604 ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Millisecond) 605 defer cancel() 606 607 for _, testBlock := range testBlocks { 608 if testBlock.blockNr == 10 { 609 continue 610 } 611 diffAccounts, err := ec.GetDiffAccounts(ctx, big.NewInt(int64(testBlock.blockNr))) 612 if err != nil { 613 t.Fatalf("unexpected error: %v", err) 614 } 615 616 accounts := make([]common.Address, 0) 617 for _, tx := range testBlock.txs { 618 // tx.to should be in the accounts list. 619 for idx, account := range diffAccounts { 620 if tx.to == account { 621 break 622 } 623 624 if idx == len(diffAccounts)-1 { 625 t.Fatalf("address(%v) expected in the diff account list, but not", tx.to) 626 } 627 } 628 629 accounts = append(accounts, tx.to) 630 } 631 632 diffDetail, err := ec.GetDiffAccountsWithScope(ctx, big.NewInt(int64(testBlock.blockNr)), accounts) 633 if err != nil { 634 t.Fatalf("get diff accounts in block error: %v", err) 635 } 636 // No contract deposit tx, so expect empty transactions. 637 if len(diffDetail.Transactions) != 0 { 638 t.Fatalf("expect ignore all transactions, but some transaction has recorded") 639 } 640 } 641 }