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