github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/les/lespay/client/requestbasket_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/rand" 21 "testing" 22 23 "github.com/cryptogateway/go-paymex/les/utils" 24 ) 25 26 func checkU64(t *testing.T, name string, value, exp uint64) { 27 if value != exp { 28 t.Errorf("Incorrect value for %s: got %d, expected %d", name, value, exp) 29 } 30 } 31 32 func checkF64(t *testing.T, name string, value, exp, tol float64) { 33 if value < exp-tol || value > exp+tol { 34 t.Errorf("Incorrect value for %s: got %f, expected %f", name, value, exp) 35 } 36 } 37 38 func TestServerBasket(t *testing.T) { 39 var s serverBasket 40 s.init(2) 41 // add some requests with different request value factors 42 s.updateRvFactor(1) 43 noexp := utils.ExpirationFactor{Factor: 1} 44 s.add(0, 1000, 10000, noexp) 45 s.add(1, 3000, 60000, noexp) 46 s.updateRvFactor(10) 47 s.add(0, 4000, 4000, noexp) 48 s.add(1, 2000, 4000, noexp) 49 s.updateRvFactor(10) 50 // check basket contents directly 51 checkU64(t, "s.basket[0].amount", s.basket.items[0].amount, 5000*basketFactor) 52 checkU64(t, "s.basket[0].value", s.basket.items[0].value, 50000) 53 checkU64(t, "s.basket[1].amount", s.basket.items[1].amount, 5000*basketFactor) 54 checkU64(t, "s.basket[1].value", s.basket.items[1].value, 100000) 55 // transfer 50% of the contents of the basket 56 transfer1 := s.transfer(0.5) 57 checkU64(t, "transfer1[0].amount", transfer1.items[0].amount, 2500*basketFactor) 58 checkU64(t, "transfer1[0].value", transfer1.items[0].value, 25000) 59 checkU64(t, "transfer1[1].amount", transfer1.items[1].amount, 2500*basketFactor) 60 checkU64(t, "transfer1[1].value", transfer1.items[1].value, 50000) 61 // add more requests 62 s.updateRvFactor(100) 63 s.add(0, 1000, 100, noexp) 64 // transfer 25% of the contents of the basket 65 transfer2 := s.transfer(0.25) 66 checkU64(t, "transfer2[0].amount", transfer2.items[0].amount, (2500+1000)/4*basketFactor) 67 checkU64(t, "transfer2[0].value", transfer2.items[0].value, (25000+10000)/4) 68 checkU64(t, "transfer2[1].amount", transfer2.items[1].amount, 2500/4*basketFactor) 69 checkU64(t, "transfer2[1].value", transfer2.items[1].value, 50000/4) 70 } 71 72 func TestConvertMapping(t *testing.T) { 73 b := requestBasket{items: []basketItem{{3, 3}, {1, 1}, {2, 2}}} 74 oldMap := []string{"req3", "req1", "req2"} 75 newMap := []string{"req1", "req2", "req3", "req4"} 76 init := requestBasket{items: []basketItem{{2, 2}, {4, 4}, {6, 6}, {8, 8}}} 77 bc := b.convertMapping(oldMap, newMap, init) 78 checkU64(t, "bc[0].amount", bc.items[0].amount, 1) 79 checkU64(t, "bc[1].amount", bc.items[1].amount, 2) 80 checkU64(t, "bc[2].amount", bc.items[2].amount, 3) 81 checkU64(t, "bc[3].amount", bc.items[3].amount, 4) // 8 should be scaled down to 4 82 } 83 84 func TestReqValueFactor(t *testing.T) { 85 var ref referenceBasket 86 ref.basket = requestBasket{items: make([]basketItem, 4)} 87 for i := range ref.basket.items { 88 ref.basket.items[i].amount = uint64(i+1) * basketFactor 89 ref.basket.items[i].value = uint64(i+1) * basketFactor 90 } 91 ref.init(4) 92 rvf := ref.reqValueFactor([]uint64{1000, 2000, 3000, 4000}) 93 // expected value is (1000000+2000000+3000000+4000000) / (1*1000+2*2000+3*3000+4*4000) = 10000000/30000 = 333.333 94 checkF64(t, "reqValueFactor", rvf, 333.333, 1) 95 } 96 97 func TestNormalize(t *testing.T) { 98 for cycle := 0; cycle < 100; cycle += 1 { 99 // Initialize data for testing 100 valueRange, lower := 1000000, 1000000 101 ref := referenceBasket{basket: requestBasket{items: make([]basketItem, 10)}} 102 for i := 0; i < 10; i++ { 103 ref.basket.items[i].amount = uint64(rand.Intn(valueRange) + lower) 104 ref.basket.items[i].value = uint64(rand.Intn(valueRange) + lower) 105 } 106 ref.normalize() 107 108 // Check whether SUM(amount) ~= SUM(value) 109 var sumAmount, sumValue uint64 110 for i := 0; i < 10; i++ { 111 sumAmount += ref.basket.items[i].amount 112 sumValue += ref.basket.items[i].value 113 } 114 var epsilon = 0.01 115 if float64(sumAmount)*(1+epsilon) < float64(sumValue) || float64(sumAmount)*(1-epsilon) > float64(sumValue) { 116 t.Fatalf("Failed to normalize sumAmount: %d sumValue: %d", sumAmount, sumValue) 117 } 118 } 119 } 120 121 func TestReqValueAdjustment(t *testing.T) { 122 var s1, s2 serverBasket 123 s1.init(3) 124 s2.init(3) 125 cost1 := []uint64{30000, 60000, 90000} 126 cost2 := []uint64{100000, 200000, 300000} 127 var ref referenceBasket 128 ref.basket = requestBasket{items: make([]basketItem, 3)} 129 for i := range ref.basket.items { 130 ref.basket.items[i].amount = 123 * basketFactor 131 ref.basket.items[i].value = 123 * basketFactor 132 } 133 ref.init(3) 134 // initial reqValues are expected to be {1, 1, 1} 135 checkF64(t, "reqValues[0]", ref.reqValues[0], 1, 0.01) 136 checkF64(t, "reqValues[1]", ref.reqValues[1], 1, 0.01) 137 checkF64(t, "reqValues[2]", ref.reqValues[2], 1, 0.01) 138 var logOffset utils.Fixed64 139 for period := 0; period < 1000; period++ { 140 exp := utils.ExpFactor(logOffset) 141 s1.updateRvFactor(ref.reqValueFactor(cost1)) 142 s2.updateRvFactor(ref.reqValueFactor(cost2)) 143 // throw in random requests into each basket using their internal pricing 144 for i := 0; i < 1000; i++ { 145 reqType, reqAmount := uint32(rand.Intn(3)), uint32(rand.Intn(10)+1) 146 reqCost := uint64(reqAmount) * cost1[reqType] 147 s1.add(reqType, reqAmount, reqCost, exp) 148 reqType, reqAmount = uint32(rand.Intn(3)), uint32(rand.Intn(10)+1) 149 reqCost = uint64(reqAmount) * cost2[reqType] 150 s2.add(reqType, reqAmount, reqCost, exp) 151 } 152 ref.add(s1.transfer(0.1)) 153 ref.add(s2.transfer(0.1)) 154 ref.normalize() 155 ref.updateReqValues() 156 logOffset += utils.Float64ToFixed64(0.1) 157 } 158 checkF64(t, "reqValues[0]", ref.reqValues[0], 0.5, 0.01) 159 checkF64(t, "reqValues[1]", ref.reqValues[1], 1, 0.01) 160 checkF64(t, "reqValues[2]", ref.reqValues[2], 1.5, 0.01) 161 }