les_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package main
  2. import (
  3. "context"
  4. "path/filepath"
  5. "testing"
  6. "time"
  7. "github.com/ethereum/go-ethereum/p2p"
  8. "github.com/ethereum/go-ethereum/rpc"
  9. )
  10. type gethrpc struct {
  11. name string
  12. rpc *rpc.Client
  13. geth *testgeth
  14. nodeInfo *p2p.NodeInfo
  15. }
  16. func (g *gethrpc) killAndWait() {
  17. g.geth.Kill()
  18. g.geth.WaitExit()
  19. }
  20. func (g *gethrpc) callRPC(result interface{}, method string, args ...interface{}) {
  21. if err := g.rpc.Call(&result, method, args...); err != nil {
  22. g.geth.Fatalf("callRPC %v: %v", method, err)
  23. }
  24. }
  25. func (g *gethrpc) addPeer(peer *gethrpc) {
  26. g.geth.Logf("%v.addPeer(%v)", g.name, peer.name)
  27. enode := peer.getNodeInfo().Enode
  28. peerCh := make(chan *p2p.PeerEvent)
  29. sub, err := g.rpc.Subscribe(context.Background(), "admin", peerCh, "peerEvents")
  30. if err != nil {
  31. g.geth.Fatalf("subscribe %v: %v", g.name, err)
  32. }
  33. defer sub.Unsubscribe()
  34. g.callRPC(nil, "admin_addPeer", enode)
  35. dur := 14 * time.Second
  36. timeout := time.After(dur)
  37. select {
  38. case ev := <-peerCh:
  39. g.geth.Logf("%v received event: type=%v, peer=%v", g.name, ev.Type, ev.Peer)
  40. case err := <-sub.Err():
  41. g.geth.Fatalf("%v sub error: %v", g.name, err)
  42. case <-timeout:
  43. g.geth.Error("timeout adding peer after", dur)
  44. }
  45. }
  46. // Use this function instead of `g.nodeInfo` directly
  47. func (g *gethrpc) getNodeInfo() *p2p.NodeInfo {
  48. if g.nodeInfo != nil {
  49. return g.nodeInfo
  50. }
  51. g.nodeInfo = &p2p.NodeInfo{}
  52. g.callRPC(&g.nodeInfo, "admin_nodeInfo")
  53. return g.nodeInfo
  54. }
  55. func (g *gethrpc) waitSynced() {
  56. // Check if it's synced now
  57. var result interface{}
  58. g.callRPC(&result, "eth_syncing")
  59. syncing, ok := result.(bool)
  60. if ok && !syncing {
  61. g.geth.Logf("%v already synced", g.name)
  62. return
  63. }
  64. // Actually wait, subscribe to the event
  65. ch := make(chan interface{})
  66. sub, err := g.rpc.Subscribe(context.Background(), "eth", ch, "syncing")
  67. if err != nil {
  68. g.geth.Fatalf("%v syncing: %v", g.name, err)
  69. }
  70. defer sub.Unsubscribe()
  71. timeout := time.After(4 * time.Second)
  72. select {
  73. case ev := <-ch:
  74. g.geth.Log("'syncing' event", ev)
  75. syncing, ok := ev.(bool)
  76. if ok && !syncing {
  77. break
  78. }
  79. g.geth.Log("Other 'syncing' event", ev)
  80. case err := <-sub.Err():
  81. g.geth.Fatalf("%v notification: %v", g.name, err)
  82. break
  83. case <-timeout:
  84. g.geth.Fatalf("%v timeout syncing", g.name)
  85. break
  86. }
  87. }
  88. func startGethWithRpc(t *testing.T, name string, args ...string) *gethrpc {
  89. g := &gethrpc{name: name}
  90. args = append([]string{"--networkid=42", "--port=0", "--nousb", "--http", "--http.port=0", "--http.api=admin,eth,les"}, args...)
  91. t.Logf("Starting %v with rpc: %v", name, args)
  92. g.geth = runGeth(t, args...)
  93. // wait before we can attach to it. TODO: probe for it properly
  94. time.Sleep(1 * time.Second)
  95. var err error
  96. ipcpath := filepath.Join(g.geth.Datadir, "geth.ipc")
  97. g.rpc, err = rpc.Dial(ipcpath)
  98. if err != nil {
  99. t.Fatalf("%v rpc connect: %v", name, err)
  100. }
  101. return g
  102. }
  103. func initGeth(t *testing.T) string {
  104. g := runGeth(t, "--networkid=42", "init", "./testdata/clique.json")
  105. datadir := g.Datadir
  106. g.WaitExit()
  107. return datadir
  108. }
  109. func startLightServer(t *testing.T) *gethrpc {
  110. datadir := initGeth(t)
  111. runGeth(t, "--datadir", datadir, "--password", "./testdata/password.txt", "account", "import", "./testdata/key.prv").WaitExit()
  112. account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105"
  113. server := startGethWithRpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1")
  114. return server
  115. }
  116. func startClient(t *testing.T, name string) *gethrpc {
  117. datadir := initGeth(t)
  118. return startGethWithRpc(t, name, "--datadir", datadir, "--nodiscover", "--syncmode=light", "--nat=extip:127.0.0.1")
  119. }
  120. func TestPriorityClient(t *testing.T) {
  121. lightServer := startLightServer(t)
  122. defer lightServer.killAndWait()
  123. // Start client and add lightServer as peer
  124. freeCli := startClient(t, "freeCli")
  125. defer freeCli.killAndWait()
  126. freeCli.addPeer(lightServer)
  127. var peers []*p2p.PeerInfo
  128. freeCli.callRPC(&peers, "admin_peers")
  129. if len(peers) != 1 {
  130. t.Errorf("Expected: # of client peers == 1, actual: %v", len(peers))
  131. return
  132. }
  133. // Set up priority client, get its nodeID, increase its balance on the lightServer
  134. prioCli := startClient(t, "prioCli")
  135. defer prioCli.killAndWait()
  136. // 3_000_000_000 once we move to Go 1.13
  137. tokens := 3000000000
  138. lightServer.callRPC(nil, "les_addBalance", prioCli.getNodeInfo().ID, tokens, "foobar")
  139. prioCli.addPeer(lightServer)
  140. // Check if priority client is actually syncing and the regular client got kicked out
  141. prioCli.callRPC(&peers, "admin_peers")
  142. if len(peers) != 1 {
  143. t.Errorf("Expected: # of prio peers == 1, actual: %v", len(peers))
  144. }
  145. nodes := map[string]*gethrpc{
  146. lightServer.getNodeInfo().ID: lightServer,
  147. freeCli.getNodeInfo().ID: freeCli,
  148. prioCli.getNodeInfo().ID: prioCli,
  149. }
  150. lightServer.callRPC(&peers, "admin_peers")
  151. peersWithNames := make(map[string]string)
  152. for _, p := range peers {
  153. peersWithNames[nodes[p.ID].name] = p.ID
  154. }
  155. if _, freeClientFound := peersWithNames[freeCli.name]; freeClientFound {
  156. t.Error("client is still a peer of lightServer", peersWithNames)
  157. }
  158. if _, prioClientFound := peersWithNames[prioCli.name]; !prioClientFound {
  159. t.Error("prio client is not among lightServer peers", peersWithNames)
  160. }
  161. }