github.com/core-coin/go-core/v2@v2.1.9/les/lespay/client/valuetracker_test.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package client 18 19 import ( 20 "math" 21 "math/rand" 22 "strconv" 23 "testing" 24 "time" 25 26 "github.com/core-coin/go-core/v2/xcbdb/memorydb" 27 28 "github.com/core-coin/go-core/v2/common/mclock" 29 "github.com/core-coin/go-core/v2/p2p/enode" 30 31 "github.com/core-coin/go-core/v2/les/utils" 32 ) 33 34 const ( 35 testReqTypes = 3 36 testNodeCount = 5 37 testReqCount = 10000 38 testRounds = 10 39 ) 40 41 func TestValueTracker(t *testing.T) { 42 db := memorydb.New() 43 clock := &mclock.Simulated{} 44 requestList := make([]RequestInfo, testReqTypes) 45 relPrices := make([]float64, testReqTypes) 46 totalAmount := make([]uint64, testReqTypes) 47 for i := range requestList { 48 requestList[i] = RequestInfo{Name: "testreq" + strconv.Itoa(i), InitAmount: 1, InitValue: 1} 49 totalAmount[i] = 1 50 relPrices[i] = rand.Float64() + 0.1 51 } 52 nodes := make([]*NodeValueTracker, testNodeCount) 53 for round := 0; round < testRounds; round++ { 54 makeRequests := round < testRounds-2 55 useExpiration := round == testRounds-1 56 var expRate float64 57 if useExpiration { 58 expRate = math.Log(2) / float64(time.Hour*100) 59 } 60 61 vt := NewValueTracker(db, clock, requestList, time.Minute, 1/float64(time.Hour), expRate, expRate) 62 updateCosts := func(i int) { 63 costList := make([]uint64, testReqTypes) 64 baseCost := rand.Float64()*10000000 + 100000 65 for j := range costList { 66 costList[j] = uint64(baseCost * relPrices[j]) 67 } 68 vt.UpdateCosts(nodes[i], costList) 69 } 70 for i := range nodes { 71 nodes[i] = vt.Register(enode.ID{byte(i)}) 72 updateCosts(i) 73 } 74 if makeRequests { 75 for i := 0; i < testReqCount; i++ { 76 reqType := rand.Intn(testReqTypes) 77 reqAmount := rand.Intn(10) + 1 78 node := rand.Intn(testNodeCount) 79 respTime := time.Duration((rand.Float64() + 1) * float64(time.Second) * float64(node+1) / testNodeCount) 80 totalAmount[reqType] += uint64(reqAmount) 81 vt.Served(nodes[node], []ServedRequest{{uint32(reqType), uint32(reqAmount)}}, respTime) 82 clock.Run(time.Second) 83 } 84 } else { 85 clock.Run(time.Hour * 100) 86 if useExpiration { 87 for i, a := range totalAmount { 88 totalAmount[i] = a / 2 89 } 90 } 91 } 92 vt.Stop() 93 var sumrp, sumrv float64 94 for i, rp := range relPrices { 95 sumrp += rp 96 sumrv += vt.refBasket.reqValues[i] 97 } 98 for i, rp := range relPrices { 99 ratio := vt.refBasket.reqValues[i] * sumrp / (rp * sumrv) 100 if ratio < 0.99 || ratio > 1.01 { 101 t.Errorf("reqValues (%v) does not match relPrices (%v)", vt.refBasket.reqValues, relPrices) 102 break 103 } 104 } 105 exp := utils.ExpFactor(vt.StatsExpirer().LogOffset(clock.Now())) 106 basketAmount := make([]uint64, testReqTypes) 107 for i, bi := range vt.refBasket.basket.items { 108 basketAmount[i] += uint64(exp.Value(float64(bi.amount), vt.refBasket.basket.exp)) 109 } 110 if makeRequests { 111 // if we did not make requests in this round then we expect all amounts to be 112 // in the reference basket 113 for _, node := range nodes { 114 for i, bi := range node.basket.basket.items { 115 basketAmount[i] += uint64(exp.Value(float64(bi.amount), node.basket.basket.exp)) 116 } 117 } 118 } 119 for i, a := range basketAmount { 120 amount := a / basketFactor 121 if amount+10 < totalAmount[i] || amount > totalAmount[i]+10 { 122 t.Errorf("totalAmount[%d] mismatch in round %d (expected %d, got %d)", i, round, totalAmount[i], amount) 123 } 124 } 125 var sumValue float64 126 for _, node := range nodes { 127 s := node.RtStats() 128 sumValue += s.Value(maxResponseWeights, exp) 129 } 130 s := vt.RtStats() 131 mainValue := s.Value(maxResponseWeights, exp) 132 if sumValue < mainValue-10 || sumValue > mainValue+10 { 133 t.Errorf("Main rtStats value does not match sum of node rtStats values in round %d (main %v, sum %v)", round, mainValue, sumValue) 134 } 135 } 136 }