ethclient_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. "context"
  19. "errors"
  20. "fmt"
  21. "math/big"
  22. "reflect"
  23. "testing"
  24. "time"
  25. "github.com/ethereum/go-ethereum"
  26. "github.com/ethereum/go-ethereum/common"
  27. "github.com/ethereum/go-ethereum/consensus/ethash"
  28. "github.com/ethereum/go-ethereum/core"
  29. "github.com/ethereum/go-ethereum/core/rawdb"
  30. "github.com/ethereum/go-ethereum/core/types"
  31. "github.com/ethereum/go-ethereum/crypto"
  32. "github.com/ethereum/go-ethereum/eth"
  33. "github.com/ethereum/go-ethereum/node"
  34. "github.com/ethereum/go-ethereum/params"
  35. )
  36. // Verify that Client implements the ethereum interfaces.
  37. var (
  38. _ = ethereum.ChainReader(&Client{})
  39. _ = ethereum.TransactionReader(&Client{})
  40. _ = ethereum.ChainStateReader(&Client{})
  41. _ = ethereum.ChainSyncReader(&Client{})
  42. _ = ethereum.ContractCaller(&Client{})
  43. _ = ethereum.GasEstimator(&Client{})
  44. _ = ethereum.GasPricer(&Client{})
  45. _ = ethereum.LogFilterer(&Client{})
  46. _ = ethereum.PendingStateReader(&Client{})
  47. // _ = ethereum.PendingStateEventer(&Client{})
  48. _ = ethereum.PendingContractCaller(&Client{})
  49. )
  50. func TestToFilterArg(t *testing.T) {
  51. blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
  52. addresses := []common.Address{
  53. common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
  54. }
  55. blockHash := common.HexToHash(
  56. "0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
  57. )
  58. for _, testCase := range []struct {
  59. name string
  60. input ethereum.FilterQuery
  61. output interface{}
  62. err error
  63. }{
  64. {
  65. "without BlockHash",
  66. ethereum.FilterQuery{
  67. Addresses: addresses,
  68. FromBlock: big.NewInt(1),
  69. ToBlock: big.NewInt(2),
  70. Topics: [][]common.Hash{},
  71. },
  72. map[string]interface{}{
  73. "address": addresses,
  74. "fromBlock": "0x1",
  75. "toBlock": "0x2",
  76. "topics": [][]common.Hash{},
  77. },
  78. nil,
  79. },
  80. {
  81. "with nil fromBlock and nil toBlock",
  82. ethereum.FilterQuery{
  83. Addresses: addresses,
  84. Topics: [][]common.Hash{},
  85. },
  86. map[string]interface{}{
  87. "address": addresses,
  88. "fromBlock": "0x0",
  89. "toBlock": "latest",
  90. "topics": [][]common.Hash{},
  91. },
  92. nil,
  93. },
  94. {
  95. "with negative fromBlock and negative toBlock",
  96. ethereum.FilterQuery{
  97. Addresses: addresses,
  98. FromBlock: big.NewInt(-1),
  99. ToBlock: big.NewInt(-1),
  100. Topics: [][]common.Hash{},
  101. },
  102. map[string]interface{}{
  103. "address": addresses,
  104. "fromBlock": "pending",
  105. "toBlock": "pending",
  106. "topics": [][]common.Hash{},
  107. },
  108. nil,
  109. },
  110. {
  111. "with blockhash",
  112. ethereum.FilterQuery{
  113. Addresses: addresses,
  114. BlockHash: &blockHash,
  115. Topics: [][]common.Hash{},
  116. },
  117. map[string]interface{}{
  118. "address": addresses,
  119. "blockHash": blockHash,
  120. "topics": [][]common.Hash{},
  121. },
  122. nil,
  123. },
  124. {
  125. "with blockhash and from block",
  126. ethereum.FilterQuery{
  127. Addresses: addresses,
  128. BlockHash: &blockHash,
  129. FromBlock: big.NewInt(1),
  130. Topics: [][]common.Hash{},
  131. },
  132. nil,
  133. blockHashErr,
  134. },
  135. {
  136. "with blockhash and to block",
  137. ethereum.FilterQuery{
  138. Addresses: addresses,
  139. BlockHash: &blockHash,
  140. ToBlock: big.NewInt(1),
  141. Topics: [][]common.Hash{},
  142. },
  143. nil,
  144. blockHashErr,
  145. },
  146. {
  147. "with blockhash and both from / to block",
  148. ethereum.FilterQuery{
  149. Addresses: addresses,
  150. BlockHash: &blockHash,
  151. FromBlock: big.NewInt(1),
  152. ToBlock: big.NewInt(2),
  153. Topics: [][]common.Hash{},
  154. },
  155. nil,
  156. blockHashErr,
  157. },
  158. } {
  159. t.Run(testCase.name, func(t *testing.T) {
  160. output, err := toFilterArg(testCase.input)
  161. if (testCase.err == nil) != (err == nil) {
  162. t.Fatalf("expected error %v but got %v", testCase.err, err)
  163. }
  164. if testCase.err != nil {
  165. if testCase.err.Error() != err.Error() {
  166. t.Fatalf("expected error %v but got %v", testCase.err, err)
  167. }
  168. } else if !reflect.DeepEqual(testCase.output, output) {
  169. t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
  170. }
  171. })
  172. }
  173. }
  174. var (
  175. testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
  176. testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
  177. testBalance = big.NewInt(2e10)
  178. )
  179. func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
  180. // Generate test chain.
  181. genesis, blocks := generateTestChain()
  182. // Create node
  183. n, err := node.New(&node.Config{})
  184. if err != nil {
  185. t.Fatalf("can't create new node: %v", err)
  186. }
  187. // Create Ethereum Service
  188. config := &eth.Config{Genesis: genesis}
  189. config.Ethash.PowMode = ethash.ModeFake
  190. ethservice, err := eth.New(n, config)
  191. if err != nil {
  192. t.Fatalf("can't create new ethereum service: %v", err)
  193. }
  194. // Import the test chain.
  195. if err := n.Start(); err != nil {
  196. t.Fatalf("can't start test node: %v", err)
  197. }
  198. if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
  199. t.Fatalf("can't import test blocks: %v", err)
  200. }
  201. return n, blocks
  202. }
  203. func generateTestChain() (*core.Genesis, []*types.Block) {
  204. db := rawdb.NewMemoryDatabase()
  205. config := params.AllEthashProtocolChanges
  206. genesis := &core.Genesis{
  207. Config: config,
  208. Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
  209. ExtraData: []byte("test genesis"),
  210. Timestamp: 9000,
  211. }
  212. generate := func(i int, g *core.BlockGen) {
  213. g.OffsetTime(5)
  214. g.SetExtra([]byte("test"))
  215. }
  216. gblock := genesis.ToBlock(db)
  217. engine := ethash.NewFaker()
  218. blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
  219. blocks = append([]*types.Block{gblock}, blocks...)
  220. return genesis, blocks
  221. }
  222. func TestHeader(t *testing.T) {
  223. backend, chain := newTestBackend(t)
  224. client, _ := backend.Attach()
  225. defer backend.Close()
  226. defer client.Close()
  227. tests := map[string]struct {
  228. block *big.Int
  229. want *types.Header
  230. wantErr error
  231. }{
  232. "genesis": {
  233. block: big.NewInt(0),
  234. want: chain[0].Header(),
  235. },
  236. "first_block": {
  237. block: big.NewInt(1),
  238. want: chain[1].Header(),
  239. },
  240. "future_block": {
  241. block: big.NewInt(1000000000),
  242. want: nil,
  243. },
  244. }
  245. for name, tt := range tests {
  246. t.Run(name, func(t *testing.T) {
  247. ec := NewClient(client)
  248. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
  249. defer cancel()
  250. got, err := ec.HeaderByNumber(ctx, tt.block)
  251. if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
  252. t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
  253. }
  254. if got != nil && got.Number.Sign() == 0 {
  255. got.Number = big.NewInt(0) // hack to make DeepEqual work
  256. }
  257. if !reflect.DeepEqual(got, tt.want) {
  258. t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want)
  259. }
  260. })
  261. }
  262. }
  263. func TestBalanceAt(t *testing.T) {
  264. backend, _ := newTestBackend(t)
  265. client, _ := backend.Attach()
  266. defer backend.Close()
  267. defer client.Close()
  268. tests := map[string]struct {
  269. account common.Address
  270. block *big.Int
  271. want *big.Int
  272. wantErr error
  273. }{
  274. "valid_account": {
  275. account: testAddr,
  276. block: big.NewInt(1),
  277. want: testBalance,
  278. },
  279. "non_existent_account": {
  280. account: common.Address{1},
  281. block: big.NewInt(1),
  282. want: big.NewInt(0),
  283. },
  284. "future_block": {
  285. account: testAddr,
  286. block: big.NewInt(1000000000),
  287. want: big.NewInt(0),
  288. wantErr: errors.New("header not found"),
  289. },
  290. }
  291. for name, tt := range tests {
  292. t.Run(name, func(t *testing.T) {
  293. ec := NewClient(client)
  294. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
  295. defer cancel()
  296. got, err := ec.BalanceAt(ctx, tt.account, tt.block)
  297. if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
  298. t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
  299. }
  300. if got.Cmp(tt.want) != 0 {
  301. t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
  302. }
  303. })
  304. }
  305. }
  306. func TestTransactionInBlockInterrupted(t *testing.T) {
  307. backend, _ := newTestBackend(t)
  308. client, _ := backend.Attach()
  309. defer backend.Close()
  310. defer client.Close()
  311. ec := NewClient(client)
  312. ctx, cancel := context.WithCancel(context.Background())
  313. cancel()
  314. tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
  315. if tx != nil {
  316. t.Fatal("transaction should be nil")
  317. }
  318. if err == nil {
  319. t.Fatal("error should not be nil")
  320. }
  321. }
  322. func TestChainID(t *testing.T) {
  323. backend, _ := newTestBackend(t)
  324. client, _ := backend.Attach()
  325. defer backend.Close()
  326. defer client.Close()
  327. ec := NewClient(client)
  328. id, err := ec.ChainID(context.Background())
  329. if err != nil {
  330. t.Fatalf("unexpected error: %v", err)
  331. }
  332. if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
  333. t.Fatalf("ChainID returned wrong number: %+v", id)
  334. }
  335. }