gitlab.com/flarenetwork/coreth@v0.1.1/consensus/dummy/dynamic_fees_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package dummy 5 6 import ( 7 "encoding/binary" 8 "math/big" 9 "testing" 10 11 "github.com/ethereum/go-ethereum/common/math" 12 "github.com/ethereum/go-ethereum/log" 13 "gitlab.com/flarenetwork/coreth/core/types" 14 "gitlab.com/flarenetwork/coreth/params" 15 ) 16 17 func testRollup(t *testing.T, longs []uint64, roll int) { 18 slice := make([]byte, len(longs)*8) 19 numLongs := len(longs) 20 for i := 0; i < numLongs; i++ { 21 binary.BigEndian.PutUint64(slice[8*i:], longs[i]) 22 } 23 24 newSlice, err := rollLongWindow(slice, roll) 25 if err != nil { 26 t.Fatal(err) 27 } 28 // numCopies is the number of longs that should have been copied over from the previous 29 // slice as opposed to being left empty. 30 numCopies := numLongs - roll 31 for i := 0; i < numLongs; i++ { 32 // Extract the long value that is encoded at position [i] in [newSlice] 33 num := binary.BigEndian.Uint64(newSlice[8*i:]) 34 // If the current index is past the point where we should have copied the value 35 // over from the previous slice, assert that the value encoded in [newSlice] 36 // is 0 37 if i >= numCopies { 38 if num != 0 { 39 t.Errorf("Expected num encoded in newSlice at position %d to be 0, but found %d", i, num) 40 } 41 } else { 42 // Otherwise, check that the value was copied over correctly 43 prevIndex := i + roll 44 prevNum := longs[prevIndex] 45 if prevNum != num { 46 t.Errorf("Expected num encoded in new slice at position %d to be %d, but found %d", i, prevNum, num) 47 } 48 } 49 } 50 } 51 52 func TestRollupWindow(t *testing.T) { 53 type test struct { 54 longs []uint64 55 roll int 56 } 57 58 var tests []test = []test{ 59 { 60 []uint64{1, 2, 3, 4}, 61 0, 62 }, 63 { 64 []uint64{1, 2, 3, 4}, 65 1, 66 }, 67 { 68 []uint64{1, 2, 3, 4}, 69 2, 70 }, 71 { 72 []uint64{1, 2, 3, 4}, 73 3, 74 }, 75 { 76 []uint64{1, 2, 3, 4}, 77 4, 78 }, 79 { 80 []uint64{1, 2, 3, 4}, 81 5, 82 }, 83 { 84 []uint64{121, 232, 432}, 85 2, 86 }, 87 } 88 89 for _, test := range tests { 90 testRollup(t, test.longs, test.roll) 91 } 92 } 93 94 type blockDefinition struct { 95 timestamp uint64 96 gasUsed uint64 97 } 98 99 type test struct { 100 extraData []byte 101 baseFee *big.Int 102 genBlocks func() []blockDefinition 103 minFee, maxFee *big.Int 104 } 105 106 func TestDynamicFees(t *testing.T) { 107 spacedTimestamps := []uint64{1, 1, 2, 5, 15, 120} 108 var tests []test = []test{ 109 // Test minimal gas usage 110 { 111 extraData: nil, 112 baseFee: nil, 113 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 114 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 115 genBlocks: func() []blockDefinition { 116 blocks := make([]blockDefinition, 0, len(spacedTimestamps)) 117 for _, timestamp := range spacedTimestamps { 118 blocks = append(blocks, blockDefinition{ 119 timestamp: timestamp, 120 gasUsed: 21000, 121 }) 122 } 123 return blocks 124 }, 125 }, 126 // Test overflow handling 127 { 128 extraData: nil, 129 baseFee: nil, 130 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 131 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 132 genBlocks: func() []blockDefinition { 133 blocks := make([]blockDefinition, 0, len(spacedTimestamps)) 134 for _, timestamp := range spacedTimestamps { 135 blocks = append(blocks, blockDefinition{ 136 timestamp: timestamp, 137 gasUsed: math.MaxUint64, 138 }) 139 } 140 return blocks 141 }, 142 }, 143 { 144 extraData: nil, 145 baseFee: nil, 146 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 147 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 148 genBlocks: func() []blockDefinition { 149 return []blockDefinition{ 150 { 151 timestamp: 1, 152 gasUsed: 1_000_000, 153 }, 154 { 155 timestamp: 3, 156 gasUsed: 1_000_000, 157 }, 158 { 159 timestamp: 5, 160 gasUsed: 2_000_000, 161 }, 162 { 163 timestamp: 5, 164 gasUsed: 6_000_000, 165 }, 166 { 167 timestamp: 7, 168 gasUsed: 6_000_000, 169 }, 170 { 171 timestamp: 1000, 172 gasUsed: 6_000_000, 173 }, 174 { 175 timestamp: 1001, 176 gasUsed: 6_000_000, 177 }, 178 { 179 timestamp: 1002, 180 gasUsed: 6_000_000, 181 }, 182 } 183 }, 184 }, 185 } 186 187 for _, test := range tests { 188 testDynamicFeesStaysWithinRange(t, test) 189 } 190 } 191 192 func testDynamicFeesStaysWithinRange(t *testing.T, test test) { 193 blocks := test.genBlocks() 194 initialBlock := blocks[0] 195 header := &types.Header{ 196 Time: initialBlock.timestamp, 197 GasUsed: initialBlock.gasUsed, 198 Number: big.NewInt(0), 199 BaseFee: test.baseFee, 200 Extra: test.extraData, 201 } 202 203 for index, block := range blocks[1:] { 204 nextExtraData, nextBaseFee, err := CalcBaseFee(params.TestChainConfig, header, block.timestamp) 205 if err != nil { 206 t.Fatalf("Failed to calculate base fee at index %d: %s", index, err) 207 } 208 if nextBaseFee.Cmp(test.maxFee) > 0 { 209 t.Fatalf("Expected fee to stay less than %d, but found %d", test.maxFee, nextBaseFee) 210 } 211 if nextBaseFee.Cmp(test.minFee) < 0 { 212 t.Fatalf("Expected fee to stay greater than %d, but found %d", test.minFee, nextBaseFee) 213 } 214 log.Info("Update", "baseFee", nextBaseFee) 215 header = &types.Header{ 216 Time: block.timestamp, 217 GasUsed: block.gasUsed, 218 Number: big.NewInt(int64(index) + 1), 219 BaseFee: nextBaseFee, 220 Extra: nextExtraData, 221 } 222 } 223 } 224 225 func TestLongWindow(t *testing.T) { 226 longs := []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 227 sumLongs := uint64(0) 228 longWindow := make([]byte, 10*8) 229 for i, long := range longs { 230 sumLongs = sumLongs + long 231 binary.BigEndian.PutUint64(longWindow[i*8:], long) 232 } 233 234 sum := sumLongWindow(longWindow, 10) 235 if sum != sumLongs { 236 t.Fatalf("Expected sum to be %d but found %d", sumLongs, sum) 237 } 238 239 for i := uint64(0); i < 10; i++ { 240 updateLongWindow(longWindow, i*8, i) 241 sum = sumLongWindow(longWindow, 10) 242 sumLongs += i 243 244 if sum != sumLongs { 245 t.Fatalf("Expected sum to be %d but found %d (iteration: %d)", sumLongs, sum, i) 246 } 247 } 248 } 249 250 func TestLongWindowOverflow(t *testing.T) { 251 longs := []uint64{0, 0, 0, 0, 0, 0, 0, 0, 2, math.MaxUint64 - 1} 252 longWindow := make([]byte, 10*8) 253 for i, long := range longs { 254 binary.BigEndian.PutUint64(longWindow[i*8:], long) 255 } 256 257 sum := sumLongWindow(longWindow, 10) 258 if sum != math.MaxUint64 { 259 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 260 } 261 262 for i := uint64(0); i < 10; i++ { 263 updateLongWindow(longWindow, i*8, i) 264 sum = sumLongWindow(longWindow, 10) 265 266 if sum != math.MaxUint64 { 267 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 268 } 269 } 270 } 271 272 func TestSelectBigWithinBounds(t *testing.T) { 273 type test struct { 274 lower, value, upper, expected *big.Int 275 } 276 277 var tests = map[string]test{ 278 "value within bounds": { 279 lower: big.NewInt(0), 280 value: big.NewInt(5), 281 upper: big.NewInt(10), 282 expected: big.NewInt(5), 283 }, 284 "value below lower bound": { 285 lower: big.NewInt(0), 286 value: big.NewInt(-1), 287 upper: big.NewInt(10), 288 expected: big.NewInt(0), 289 }, 290 "value above upper bound": { 291 lower: big.NewInt(0), 292 value: big.NewInt(11), 293 upper: big.NewInt(10), 294 expected: big.NewInt(10), 295 }, 296 "value matches lower bound": { 297 lower: big.NewInt(0), 298 value: big.NewInt(0), 299 upper: big.NewInt(10), 300 expected: big.NewInt(0), 301 }, 302 "value matches upper bound": { 303 lower: big.NewInt(0), 304 value: big.NewInt(10), 305 upper: big.NewInt(10), 306 expected: big.NewInt(10), 307 }, 308 } 309 310 for name, test := range tests { 311 t.Run(name, func(t *testing.T) { 312 v := selectBigWithinBounds(test.lower, test.value, test.upper) 313 if v.Cmp(test.expected) != 0 { 314 t.Fatalf("Expected (%d), found (%d)", test.expected, v) 315 } 316 }) 317 } 318 }