prioritypool_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright 2020 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 server
  17. import (
  18. "math/rand"
  19. "reflect"
  20. "testing"
  21. "time"
  22. "github.com/ethereum/go-ethereum/common/mclock"
  23. "github.com/ethereum/go-ethereum/p2p/enode"
  24. "github.com/ethereum/go-ethereum/p2p/enr"
  25. "github.com/ethereum/go-ethereum/p2p/nodestate"
  26. )
  27. const (
  28. testCapacityStepDiv = 100
  29. testCapacityToleranceDiv = 10
  30. testMinCap = 100
  31. )
  32. type ppTestClient struct {
  33. node *enode.Node
  34. balance, cap uint64
  35. }
  36. func (c *ppTestClient) priority(cap uint64) int64 {
  37. return int64(c.balance / cap)
  38. }
  39. func (c *ppTestClient) estimatePriority(cap uint64, addBalance int64, future, bias time.Duration, update bool) int64 {
  40. return int64(c.balance / cap)
  41. }
  42. func TestPriorityPool(t *testing.T) {
  43. clock := &mclock.Simulated{}
  44. setup := newServerSetup()
  45. setup.balanceField = setup.setup.NewField("ppTestClient", reflect.TypeOf(&ppTestClient{}))
  46. ns := nodestate.NewNodeStateMachine(nil, nil, clock, setup.setup)
  47. ns.SubscribeField(setup.capacityField, func(node *enode.Node, state nodestate.Flags, oldValue, newValue interface{}) {
  48. if n := ns.GetField(node, setup.balanceField); n != nil {
  49. c := n.(*ppTestClient)
  50. c.cap = newValue.(uint64)
  51. }
  52. })
  53. pp := newPriorityPool(ns, setup, clock, testMinCap, 0, testCapacityStepDiv, testCapacityStepDiv)
  54. ns.Start()
  55. pp.SetLimits(100, 1000000)
  56. clients := make([]*ppTestClient, 100)
  57. raise := func(c *ppTestClient) {
  58. for {
  59. var ok bool
  60. ns.Operation(func() {
  61. newCap := c.cap + c.cap/testCapacityStepDiv
  62. ok = pp.requestCapacity(c.node, newCap, newCap, 0) == newCap
  63. })
  64. if !ok {
  65. return
  66. }
  67. }
  68. }
  69. var sumBalance uint64
  70. check := func(c *ppTestClient) {
  71. expCap := 1000000 * c.balance / sumBalance
  72. capTol := expCap / testCapacityToleranceDiv
  73. if c.cap < expCap-capTol || c.cap > expCap+capTol {
  74. t.Errorf("Wrong node capacity (expected %d, got %d)", expCap, c.cap)
  75. }
  76. }
  77. for i := range clients {
  78. c := &ppTestClient{
  79. node: enode.SignNull(&enr.Record{}, enode.ID{byte(i)}),
  80. balance: 100000000000,
  81. cap: 1000,
  82. }
  83. sumBalance += c.balance
  84. clients[i] = c
  85. ns.SetField(c.node, setup.balanceField, c)
  86. ns.SetState(c.node, setup.inactiveFlag, nodestate.Flags{}, 0)
  87. raise(c)
  88. check(c)
  89. }
  90. for count := 0; count < 100; count++ {
  91. c := clients[rand.Intn(len(clients))]
  92. oldBalance := c.balance
  93. c.balance = uint64(rand.Int63n(100000000000) + 100000000000)
  94. sumBalance += c.balance - oldBalance
  95. pp.ns.SetState(c.node, setup.updateFlag, nodestate.Flags{}, 0)
  96. pp.ns.SetState(c.node, nodestate.Flags{}, setup.updateFlag, 0)
  97. if c.balance > oldBalance {
  98. raise(c)
  99. } else {
  100. for _, c := range clients {
  101. raise(c)
  102. }
  103. }
  104. // check whether capacities are proportional to balances
  105. for _, c := range clients {
  106. check(c)
  107. }
  108. if count%10 == 0 {
  109. // test available capacity calculation with capacity curve
  110. c = clients[rand.Intn(len(clients))]
  111. curve := pp.getCapacityCurve().exclude(c.node.ID())
  112. add := uint64(rand.Int63n(10000000000000))
  113. c.balance += add
  114. sumBalance += add
  115. expCap := curve.maxCapacity(func(cap uint64) int64 {
  116. return int64(c.balance / cap)
  117. })
  118. var ok bool
  119. expFail := expCap + 10
  120. if expFail < testMinCap {
  121. expFail = testMinCap
  122. }
  123. ns.Operation(func() {
  124. ok = pp.requestCapacity(c.node, expFail, expFail, 0) == expFail
  125. })
  126. if ok {
  127. t.Errorf("Request for more than expected available capacity succeeded")
  128. }
  129. if expCap >= testMinCap {
  130. ns.Operation(func() {
  131. ok = pp.requestCapacity(c.node, expCap, expCap, 0) == expCap
  132. })
  133. if !ok {
  134. t.Errorf("Request for expected available capacity failed")
  135. }
  136. }
  137. c.balance -= add
  138. sumBalance -= add
  139. pp.ns.SetState(c.node, setup.updateFlag, nodestate.Flags{}, 0)
  140. pp.ns.SetState(c.node, nodestate.Flags{}, setup.updateFlag, 0)
  141. for _, c := range clients {
  142. raise(c)
  143. }
  144. }
  145. }
  146. ns.Stop()
  147. }
  148. func TestCapacityCurve(t *testing.T) {
  149. clock := &mclock.Simulated{}
  150. setup := newServerSetup()
  151. setup.balanceField = setup.setup.NewField("ppTestClient", reflect.TypeOf(&ppTestClient{}))
  152. ns := nodestate.NewNodeStateMachine(nil, nil, clock, setup.setup)
  153. pp := newPriorityPool(ns, setup, clock, 400000, 0, 2, 2)
  154. ns.Start()
  155. pp.SetLimits(10, 10000000)
  156. clients := make([]*ppTestClient, 10)
  157. for i := range clients {
  158. c := &ppTestClient{
  159. node: enode.SignNull(&enr.Record{}, enode.ID{byte(i)}),
  160. balance: 100000000000 * uint64(i+1),
  161. cap: 1000000,
  162. }
  163. clients[i] = c
  164. ns.SetField(c.node, setup.balanceField, c)
  165. ns.SetState(c.node, setup.inactiveFlag, nodestate.Flags{}, 0)
  166. ns.Operation(func() {
  167. pp.requestCapacity(c.node, c.cap, c.cap, 0)
  168. })
  169. }
  170. curve := pp.getCapacityCurve()
  171. check := func(balance, expCap uint64) {
  172. cap := curve.maxCapacity(func(cap uint64) int64 {
  173. return int64(balance / cap)
  174. })
  175. var fail bool
  176. if cap == 0 || expCap == 0 {
  177. fail = cap != expCap
  178. } else {
  179. pri := balance / cap
  180. expPri := balance / expCap
  181. fail = pri != expPri && pri != expPri+1
  182. }
  183. if fail {
  184. t.Errorf("Incorrect capacity for %d balance (got %d, expected %d)", balance, cap, expCap)
  185. }
  186. }
  187. check(0, 0)
  188. check(10000000000, 100000)
  189. check(50000000000, 500000)
  190. check(100000000000, 1000000)
  191. check(200000000000, 1000000)
  192. check(300000000000, 1500000)
  193. check(450000000000, 1500000)
  194. check(600000000000, 2000000)
  195. check(800000000000, 2000000)
  196. check(1000000000000, 2500000)
  197. pp.SetLimits(11, 10000000)
  198. curve = pp.getCapacityCurve()
  199. check(0, 0)
  200. check(10000000000, 100000)
  201. check(50000000000, 500000)
  202. check(150000000000, 750000)
  203. check(200000000000, 1000000)
  204. check(220000000000, 1100000)
  205. check(275000000000, 1100000)
  206. check(375000000000, 1500000)
  207. check(450000000000, 1500000)
  208. check(600000000000, 2000000)
  209. check(800000000000, 2000000)
  210. check(1000000000000, 2500000)
  211. ns.Stop()
  212. }