ethclient_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. package ethclient
  17. import (
  18. "bytes"
  19. "context"
  20. "errors"
  21. "fmt"
  22. "math/big"
  23. "reflect"
  24. "testing"
  25. "time"
  26. "github.com/ethereum/go-ethereum"
  27. "github.com/ethereum/go-ethereum/common"
  28. "github.com/ethereum/go-ethereum/consensus/ethash"
  29. "github.com/ethereum/go-ethereum/core"
  30. "github.com/ethereum/go-ethereum/core/rawdb"
  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/node"
  35. "github.com/ethereum/go-ethereum/params"
  36. "github.com/ethereum/go-ethereum/rpc"
  37. )
  38. // Verify that Client implements the ethereum interfaces.
  39. var (
  40. _ = ethereum.ChainReader(&Client{})
  41. _ = ethereum.TransactionReader(&Client{})
  42. _ = ethereum.ChainStateReader(&Client{})
  43. _ = ethereum.ChainSyncReader(&Client{})
  44. _ = ethereum.ContractCaller(&Client{})
  45. _ = ethereum.GasEstimator(&Client{})
  46. _ = ethereum.GasPricer(&Client{})
  47. _ = ethereum.LogFilterer(&Client{})
  48. _ = ethereum.PendingStateReader(&Client{})
  49. // _ = ethereum.PendingStateEventer(&Client{})
  50. _ = ethereum.PendingContractCaller(&Client{})
  51. )
  52. func TestToFilterArg(t *testing.T) {
  53. blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
  54. addresses := []common.Address{
  55. common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
  56. }
  57. blockHash := common.HexToHash(
  58. "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
  59. )
  60. for _, testCase := range []struct {
  61. name string
  62. input ethereum.FilterQuery
  63. output interface{}
  64. err error
  65. }{
  66. {
  67. "without BlockHash",
  68. ethereum.FilterQuery{
  69. Addresses: addresses,
  70. FromBlock: big.NewInt(1),
  71. ToBlock: big.NewInt(2),
  72. Topics: [][]common.Hash{},
  73. },
  74. map[string]interface{}{
  75. "address": addresses,
  76. "fromBlock": "0x1",
  77. "toBlock": "0x2",
  78. "topics": [][]common.Hash{},
  79. },
  80. nil,
  81. },
  82. {
  83. "with nil fromBlock and nil toBlock",
  84. ethereum.FilterQuery{
  85. Addresses: addresses,
  86. Topics: [][]common.Hash{},
  87. },
  88. map[string]interface{}{
  89. "address": addresses,
  90. "fromBlock": "0x0",
  91. "toBlock": "latest",
  92. "topics": [][]common.Hash{},
  93. },
  94. nil,
  95. },
  96. {
  97. "with negative fromBlock and negative toBlock",
  98. ethereum.FilterQuery{
  99. Addresses: addresses,
  100. FromBlock: big.NewInt(-1),
  101. ToBlock: big.NewInt(-1),
  102. Topics: [][]common.Hash{},
  103. },
  104. map[string]interface{}{
  105. "address": addresses,
  106. "fromBlock": "pending",
  107. "toBlock": "pending",
  108. "topics": [][]common.Hash{},
  109. },
  110. nil,
  111. },
  112. {
  113. "with blockhash",
  114. ethereum.FilterQuery{
  115. Addresses: addresses,
  116. BlockHash: &blockHash,
  117. Topics: [][]common.Hash{},
  118. },
  119. map[string]interface{}{
  120. "address": addresses,
  121. "blockHash": blockHash,
  122. "topics": [][]common.Hash{},
  123. },
  124. nil,
  125. },
  126. {
  127. "with blockhash and from block",
  128. ethereum.FilterQuery{
  129. Addresses: addresses,
  130. BlockHash: &blockHash,
  131. FromBlock: big.NewInt(1),
  132. Topics: [][]common.Hash{},
  133. },
  134. nil,
  135. blockHashErr,
  136. },
  137. {
  138. "with blockhash and to block",
  139. ethereum.FilterQuery{
  140. Addresses: addresses,
  141. BlockHash: &blockHash,
  142. ToBlock: big.NewInt(1),
  143. Topics: [][]common.Hash{},
  144. },
  145. nil,
  146. blockHashErr,
  147. },
  148. {
  149. "with blockhash and both from / to block",
  150. ethereum.FilterQuery{
  151. Addresses: addresses,
  152. BlockHash: &blockHash,
  153. FromBlock: big.NewInt(1),
  154. ToBlock: big.NewInt(2),
  155. Topics: [][]common.Hash{},
  156. },
  157. nil,
  158. blockHashErr,
  159. },
  160. } {
  161. t.Run(testCase.name, func(t *testing.T) {
  162. output, err := toFilterArg(testCase.input)
  163. if (testCase.err == nil) != (err == nil) {
  164. t.Fatalf("expected error %v but got %v", testCase.err, err)
  165. }
  166. if testCase.err != nil {
  167. if testCase.err.Error() != err.Error() {
  168. t.Fatalf("expected error %v but got %v", testCase.err, err)
  169. }
  170. } else if !reflect.DeepEqual(testCase.output, output) {
  171. t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
  172. }
  173. })
  174. }
  175. }
  176. var (
  177. testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
  178. testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
  179. testBalance = big.NewInt(2e10)
  180. )
  181. func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
  182. // Generate test chain.
  183. genesis, blocks := generateTestChain()
  184. // Create node
  185. n, err := node.New(&node.Config{})
  186. if err != nil {
  187. t.Fatalf("can't create new node: %v", err)
  188. }
  189. // Create Ethereum Service
  190. config := &eth.Config{Genesis: genesis}
  191. config.Ethash.PowMode = ethash.ModeFake
  192. ethservice, err := eth.New(n, config)
  193. if err != nil {
  194. t.Fatalf("can't create new ethereum service: %v", err)
  195. }
  196. // Import the test chain.
  197. if err := n.Start(); err != nil {
  198. t.Fatalf("can't start test node: %v", err)
  199. }
  200. if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
  201. t.Fatalf("can't import test blocks: %v", err)
  202. }
  203. return n, blocks
  204. }
  205. func generateTestChain() (*core.Genesis, []*types.Block) {
  206. db := rawdb.NewMemoryDatabase()
  207. config := params.AllEthashProtocolChanges
  208. genesis := &core.Genesis{
  209. Config: config,
  210. Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
  211. ExtraData: []byte("test genesis"),
  212. Timestamp: 9000,
  213. }
  214. generate := func(i int, g *core.BlockGen) {
  215. g.OffsetTime(5)
  216. g.SetExtra([]byte("test"))
  217. }
  218. gblock := genesis.ToBlock(db)
  219. engine := ethash.NewFaker()
  220. blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
  221. blocks = append([]*types.Block{gblock}, blocks...)
  222. return genesis, blocks
  223. }
  224. func TestEthClient(t *testing.T) {
  225. backend, chain := newTestBackend(t)
  226. client, _ := backend.Attach()
  227. defer backend.Close()
  228. defer client.Close()
  229. tests := map[string]struct {
  230. test func(t *testing.T)
  231. }{
  232. "TestHeader": {
  233. func(t *testing.T) { testHeader(t, chain, client) },
  234. },
  235. "TestBalanceAt": {
  236. func(t *testing.T) { testBalanceAt(t, client) },
  237. },
  238. "TestTxInBlockInterrupted": {
  239. func(t *testing.T) { testTransactionInBlockInterrupted(t, client) },
  240. },
  241. "TestChainID": {
  242. func(t *testing.T) { testChainID(t, client) },
  243. },
  244. "TestGetBlock": {
  245. func(t *testing.T) { testGetBlock(t, client) },
  246. },
  247. "TestStatusFunctions": {
  248. func(t *testing.T) { testStatusFunctions(t, client) },
  249. },
  250. "TestCallContract": {
  251. func(t *testing.T) { testCallContract(t, client) },
  252. },
  253. "TestAtFunctions": {
  254. func(t *testing.T) { testAtFunctions(t, client) },
  255. },
  256. }
  257. t.Parallel()
  258. for name, tt := range tests {
  259. t.Run(name, tt.test)
  260. }
  261. }
  262. func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
  263. tests := map[string]struct {
  264. block *big.Int
  265. want *types.Header
  266. wantErr error
  267. }{
  268. "genesis": {
  269. block: big.NewInt(0),
  270. want: chain[0].Header(),
  271. },
  272. "first_block": {
  273. block: big.NewInt(1),
  274. want: chain[1].Header(),
  275. },
  276. "future_block": {
  277. block: big.NewInt(1000000000),
  278. want: nil,
  279. },
  280. }
  281. for name, tt := range tests {
  282. t.Run(name, func(t *testing.T) {
  283. ec := NewClient(client)
  284. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
  285. defer cancel()
  286. got, err := ec.HeaderByNumber(ctx, tt.block)
  287. if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
  288. t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
  289. }
  290. if got != nil && got.Number.Sign() == 0 {
  291. got.Number = big.NewInt(0) // hack to make DeepEqual work
  292. }
  293. if !reflect.DeepEqual(got, tt.want) {
  294. t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want)
  295. }
  296. })
  297. }
  298. }
  299. func testBalanceAt(t *testing.T, client *rpc.Client) {
  300. tests := map[string]struct {
  301. account common.Address
  302. block *big.Int
  303. want *big.Int
  304. wantErr error
  305. }{
  306. "valid_account": {
  307. account: testAddr,
  308. block: big.NewInt(1),
  309. want: testBalance,
  310. },
  311. "non_existent_account": {
  312. account: common.Address{1},
  313. block: big.NewInt(1),
  314. want: big.NewInt(0),
  315. },
  316. "future_block": {
  317. account: testAddr,
  318. block: big.NewInt(1000000000),
  319. want: big.NewInt(0),
  320. wantErr: errors.New("header not found"),
  321. },
  322. }
  323. for name, tt := range tests {
  324. t.Run(name, func(t *testing.T) {
  325. ec := NewClient(client)
  326. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
  327. defer cancel()
  328. got, err := ec.BalanceAt(ctx, tt.account, tt.block)
  329. if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
  330. t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
  331. }
  332. if got.Cmp(tt.want) != 0 {
  333. t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
  334. }
  335. })
  336. }
  337. }
  338. func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) {
  339. ec := NewClient(client)
  340. // Get current block by number
  341. block, err := ec.BlockByNumber(context.Background(), nil)
  342. if err != nil {
  343. t.Fatalf("unexpected error: %v", err)
  344. }
  345. // Test tx in block interupted
  346. ctx, cancel := context.WithCancel(context.Background())
  347. cancel()
  348. tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1)
  349. if tx != nil {
  350. t.Fatal("transaction should be nil")
  351. }
  352. if err == nil || err == ethereum.NotFound {
  353. t.Fatal("error should not be nil/notfound")
  354. }
  355. // Test tx in block not found
  356. if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 1); err != ethereum.NotFound {
  357. t.Fatal("error should be ethereum.NotFound")
  358. }
  359. }
  360. func testChainID(t *testing.T, client *rpc.Client) {
  361. ec := NewClient(client)
  362. id, err := ec.ChainID(context.Background())
  363. if err != nil {
  364. t.Fatalf("unexpected error: %v", err)
  365. }
  366. if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
  367. t.Fatalf("ChainID returned wrong number: %+v", id)
  368. }
  369. }
  370. func testGetBlock(t *testing.T, client *rpc.Client) {
  371. ec := NewClient(client)
  372. // Get current block number
  373. blockNumber, err := ec.BlockNumber(context.Background())
  374. if err != nil {
  375. t.Fatalf("unexpected error: %v", err)
  376. }
  377. if blockNumber != 1 {
  378. t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
  379. }
  380. // Get current block by number
  381. block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
  382. if err != nil {
  383. t.Fatalf("unexpected error: %v", err)
  384. }
  385. if block.NumberU64() != blockNumber {
  386. t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
  387. }
  388. // Get current block by hash
  389. blockH, err := ec.BlockByHash(context.Background(), block.Hash())
  390. if err != nil {
  391. t.Fatalf("unexpected error: %v", err)
  392. }
  393. if block.Hash() != blockH.Hash() {
  394. t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
  395. }
  396. // Get header by number
  397. header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
  398. if err != nil {
  399. t.Fatalf("unexpected error: %v", err)
  400. }
  401. if block.Header().Hash() != header.Hash() {
  402. t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
  403. }
  404. // Get header by hash
  405. headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
  406. if err != nil {
  407. t.Fatalf("unexpected error: %v", err)
  408. }
  409. if block.Header().Hash() != headerH.Hash() {
  410. t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
  411. }
  412. }
  413. func testStatusFunctions(t *testing.T, client *rpc.Client) {
  414. ec := NewClient(client)
  415. // Sync progress
  416. progress, err := ec.SyncProgress(context.Background())
  417. if err != nil {
  418. t.Fatalf("unexpected error: %v", err)
  419. }
  420. if progress != nil {
  421. t.Fatalf("unexpected progress: %v", progress)
  422. }
  423. // NetworkID
  424. networkID, err := ec.NetworkID(context.Background())
  425. if err != nil {
  426. t.Fatalf("unexpected error: %v", err)
  427. }
  428. if networkID.Cmp(big.NewInt(0)) != 0 {
  429. t.Fatalf("unexpected networkID: %v", networkID)
  430. }
  431. // SuggestGasPrice (should suggest 1 Gwei)
  432. gasPrice, err := ec.SuggestGasPrice(context.Background())
  433. if err != nil {
  434. t.Fatalf("unexpected error: %v", err)
  435. }
  436. if gasPrice.Cmp(big.NewInt(1000000000)) != 0 {
  437. t.Fatalf("unexpected gas price: %v", gasPrice)
  438. }
  439. }
  440. func testCallContract(t *testing.T, client *rpc.Client) {
  441. ec := NewClient(client)
  442. // EstimateGas
  443. msg := ethereum.CallMsg{
  444. From: testAddr,
  445. To: &common.Address{},
  446. Gas: 21000,
  447. GasPrice: big.NewInt(1),
  448. Value: big.NewInt(1),
  449. }
  450. gas, err := ec.EstimateGas(context.Background(), msg)
  451. if err != nil {
  452. t.Fatalf("unexpected error: %v", err)
  453. }
  454. if gas != 21000 {
  455. t.Fatalf("unexpected gas price: %v", gas)
  456. }
  457. // CallContract
  458. if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil {
  459. t.Fatalf("unexpected error: %v", err)
  460. }
  461. // PendingCallCOntract
  462. if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
  463. t.Fatalf("unexpected error: %v", err)
  464. }
  465. }
  466. func testAtFunctions(t *testing.T, client *rpc.Client) {
  467. ec := NewClient(client)
  468. // send a transaction for some interesting pending status
  469. sendTransaction(ec)
  470. time.Sleep(100 * time.Millisecond)
  471. // Check pending transaction count
  472. pending, err := ec.PendingTransactionCount(context.Background())
  473. if err != nil {
  474. t.Fatalf("unexpected error: %v", err)
  475. }
  476. if pending != 1 {
  477. t.Fatalf("unexpected pending, wanted 1 got: %v", pending)
  478. }
  479. // Query balance
  480. balance, err := ec.BalanceAt(context.Background(), testAddr, nil)
  481. if err != nil {
  482. t.Fatalf("unexpected error: %v", err)
  483. }
  484. penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr)
  485. if err != nil {
  486. t.Fatalf("unexpected error: %v", err)
  487. }
  488. if balance.Cmp(penBalance) == 0 {
  489. t.Fatalf("unexpected balance: %v %v", balance, penBalance)
  490. }
  491. // NonceAt
  492. nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
  493. if err != nil {
  494. t.Fatalf("unexpected error: %v", err)
  495. }
  496. penNonce, err := ec.PendingNonceAt(context.Background(), testAddr)
  497. if err != nil {
  498. t.Fatalf("unexpected error: %v", err)
  499. }
  500. if penNonce != nonce+1 {
  501. t.Fatalf("unexpected nonce: %v %v", nonce, penNonce)
  502. }
  503. // StorageAt
  504. storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil)
  505. if err != nil {
  506. t.Fatalf("unexpected error: %v", err)
  507. }
  508. penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{})
  509. if err != nil {
  510. t.Fatalf("unexpected error: %v", err)
  511. }
  512. if !bytes.Equal(storage, penStorage) {
  513. t.Fatalf("unexpected storage: %v %v", storage, penStorage)
  514. }
  515. // CodeAt
  516. code, err := ec.CodeAt(context.Background(), testAddr, nil)
  517. if err != nil {
  518. t.Fatalf("unexpected error: %v", err)
  519. }
  520. penCode, err := ec.PendingCodeAt(context.Background(), testAddr)
  521. if err != nil {
  522. t.Fatalf("unexpected error: %v", err)
  523. }
  524. if !bytes.Equal(code, penCode) {
  525. t.Fatalf("unexpected code: %v %v", code, penCode)
  526. }
  527. }
  528. func sendTransaction(ec *Client) error {
  529. // Retrieve chainID
  530. chainID, err := ec.ChainID(context.Background())
  531. if err != nil {
  532. return err
  533. }
  534. // Create transaction
  535. tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
  536. signer := types.NewEIP155Signer(chainID)
  537. signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
  538. if err != nil {
  539. return err
  540. }
  541. signedTx, err := tx.WithSignature(signer, signature)
  542. if err != nil {
  543. return err
  544. }
  545. // Send transaction
  546. return ec.SendTransaction(context.Background(), signedTx)
  547. }