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