clientpool_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2019 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 les
  17. import (
  18. "fmt"
  19. "math/rand"
  20. "testing"
  21. "time"
  22. "github.com/ethereum/go-ethereum/common/mclock"
  23. "github.com/ethereum/go-ethereum/core/rawdb"
  24. "github.com/ethereum/go-ethereum/p2p/enode"
  25. )
  26. func TestClientPoolL10C100Free(t *testing.T) {
  27. testClientPool(t, 10, 100, 0, true)
  28. }
  29. func TestClientPoolL40C200Free(t *testing.T) {
  30. testClientPool(t, 40, 200, 0, true)
  31. }
  32. func TestClientPoolL100C300Free(t *testing.T) {
  33. testClientPool(t, 100, 300, 0, true)
  34. }
  35. func TestClientPoolL10C100P4(t *testing.T) {
  36. testClientPool(t, 10, 100, 4, false)
  37. }
  38. func TestClientPoolL40C200P30(t *testing.T) {
  39. testClientPool(t, 40, 200, 30, false)
  40. }
  41. func TestClientPoolL100C300P20(t *testing.T) {
  42. testClientPool(t, 100, 300, 20, false)
  43. }
  44. const testClientPoolTicks = 500000
  45. type poolTestPeer int
  46. func (i poolTestPeer) ID() enode.ID {
  47. return enode.ID{byte(i % 256), byte(i >> 8)}
  48. }
  49. func (i poolTestPeer) freeClientId() string {
  50. return fmt.Sprintf("addr #%d", i)
  51. }
  52. func (i poolTestPeer) updateCapacity(uint64) {}
  53. func testClientPool(t *testing.T, connLimit, clientCount, paidCount int, randomDisconnect bool) {
  54. rand.Seed(time.Now().UnixNano())
  55. var (
  56. clock mclock.Simulated
  57. db = rawdb.NewMemoryDatabase()
  58. connected = make([]bool, clientCount)
  59. connTicks = make([]int, clientCount)
  60. disconnCh = make(chan int, clientCount)
  61. disconnFn = func(id enode.ID) {
  62. disconnCh <- int(id[0]) + int(id[1])<<8
  63. }
  64. pool = newClientPool(db, 1, 10000, &clock, disconnFn)
  65. )
  66. pool.setLimits(connLimit, uint64(connLimit))
  67. pool.setPriceFactors(priceFactors{1, 0, 1}, priceFactors{1, 0, 1})
  68. // pool should accept new peers up to its connected limit
  69. for i := 0; i < connLimit; i++ {
  70. if pool.connect(poolTestPeer(i), 0) {
  71. connected[i] = true
  72. } else {
  73. t.Fatalf("Test peer #%d rejected", i)
  74. }
  75. }
  76. // since all accepted peers are new and should not be kicked out, the next one should be rejected
  77. if pool.connect(poolTestPeer(connLimit), 0) {
  78. connected[connLimit] = true
  79. t.Fatalf("Peer accepted over connected limit")
  80. }
  81. // randomly connect and disconnect peers, expect to have a similar total connection time at the end
  82. for tickCounter := 0; tickCounter < testClientPoolTicks; tickCounter++ {
  83. clock.Run(1 * time.Second)
  84. //time.Sleep(time.Microsecond * 100)
  85. if tickCounter == testClientPoolTicks/4 {
  86. // give a positive balance to some of the peers
  87. amount := uint64(testClientPoolTicks / 2 * 1000000000) // enough for half of the simulation period
  88. for i := 0; i < paidCount; i++ {
  89. pool.addBalance(poolTestPeer(i).ID(), amount, false)
  90. }
  91. }
  92. i := rand.Intn(clientCount)
  93. if connected[i] {
  94. if randomDisconnect {
  95. pool.disconnect(poolTestPeer(i))
  96. connected[i] = false
  97. connTicks[i] += tickCounter
  98. }
  99. } else {
  100. if pool.connect(poolTestPeer(i), 0) {
  101. connected[i] = true
  102. connTicks[i] -= tickCounter
  103. }
  104. }
  105. pollDisconnects:
  106. for {
  107. select {
  108. case i := <-disconnCh:
  109. pool.disconnect(poolTestPeer(i))
  110. if connected[i] {
  111. connTicks[i] += tickCounter
  112. connected[i] = false
  113. }
  114. default:
  115. break pollDisconnects
  116. }
  117. }
  118. }
  119. expTicks := testClientPoolTicks/2*connLimit/clientCount + testClientPoolTicks/2*(connLimit-paidCount)/(clientCount-paidCount)
  120. expMin := expTicks - expTicks/10
  121. expMax := expTicks + expTicks/10
  122. paidTicks := testClientPoolTicks/2*connLimit/clientCount + testClientPoolTicks/2
  123. paidMin := paidTicks - paidTicks/10
  124. paidMax := paidTicks + paidTicks/10
  125. // check if the total connected time of peers are all in the expected range
  126. for i, c := range connected {
  127. if c {
  128. connTicks[i] += testClientPoolTicks
  129. }
  130. min, max := expMin, expMax
  131. if i < paidCount {
  132. // expect a higher amount for clients with a positive balance
  133. min, max = paidMin, paidMax
  134. }
  135. if connTicks[i] < min || connTicks[i] > max {
  136. t.Errorf("Total connected time of test node #%d (%d) outside expected range (%d to %d)", i, connTicks[i], min, max)
  137. }
  138. }
  139. // a previously unknown peer should be accepted now
  140. if !pool.connect(poolTestPeer(54321), 0) {
  141. t.Fatalf("Previously unknown peer rejected")
  142. }
  143. // close and restart pool
  144. pool.stop()
  145. pool = newClientPool(db, 1, 10000, &clock, func(id enode.ID) {})
  146. pool.setLimits(connLimit, uint64(connLimit))
  147. // try connecting all known peers (connLimit should be filled up)
  148. for i := 0; i < clientCount; i++ {
  149. pool.connect(poolTestPeer(i), 0)
  150. }
  151. // expect pool to remember known nodes and kick out one of them to accept a new one
  152. if !pool.connect(poolTestPeer(54322), 0) {
  153. t.Errorf("Previously unknown peer rejected after restarting pool")
  154. }
  155. pool.stop()
  156. }