github.com/cgcardona/r-subnet-evm@v0.1.5/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/cgcardona/r-subnet-evm/commontype" 12 "github.com/cgcardona/r-subnet-evm/core/types" 13 "github.com/cgcardona/r-subnet-evm/params" 14 "github.com/ethereum/go-ethereum/common/math" 15 "github.com/ethereum/go-ethereum/log" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 var testMinBaseFee = big.NewInt(75_000_000_000) 20 21 func testRollup(t *testing.T, longs []uint64, roll int) { 22 slice := make([]byte, len(longs)*8) 23 numLongs := len(longs) 24 for i := 0; i < numLongs; i++ { 25 binary.BigEndian.PutUint64(slice[8*i:], longs[i]) 26 } 27 28 newSlice, err := rollLongWindow(slice, roll) 29 if err != nil { 30 t.Fatal(err) 31 } 32 // numCopies is the number of longs that should have been copied over from the previous 33 // slice as opposed to being left empty. 34 numCopies := numLongs - roll 35 for i := 0; i < numLongs; i++ { 36 // Extract the long value that is encoded at position [i] in [newSlice] 37 num := binary.BigEndian.Uint64(newSlice[8*i:]) 38 // If the current index is past the point where we should have copied the value 39 // over from the previous slice, assert that the value encoded in [newSlice] 40 // is 0 41 if i >= numCopies { 42 if num != 0 { 43 t.Errorf("Expected num encoded in newSlice at position %d to be 0, but found %d", i, num) 44 } 45 } else { 46 // Otherwise, check that the value was copied over correctly 47 prevIndex := i + roll 48 prevNum := longs[prevIndex] 49 if prevNum != num { 50 t.Errorf("Expected num encoded in new slice at position %d to be %d, but found %d", i, prevNum, num) 51 } 52 } 53 } 54 } 55 56 func TestRollupWindow(t *testing.T) { 57 type test struct { 58 longs []uint64 59 roll int 60 } 61 62 var tests []test = []test{ 63 { 64 []uint64{1, 2, 3, 4}, 65 0, 66 }, 67 { 68 []uint64{1, 2, 3, 4}, 69 1, 70 }, 71 { 72 []uint64{1, 2, 3, 4}, 73 2, 74 }, 75 { 76 []uint64{1, 2, 3, 4}, 77 3, 78 }, 79 { 80 []uint64{1, 2, 3, 4}, 81 4, 82 }, 83 { 84 []uint64{1, 2, 3, 4}, 85 5, 86 }, 87 { 88 []uint64{121, 232, 432}, 89 2, 90 }, 91 } 92 93 for _, test := range tests { 94 testRollup(t, test.longs, test.roll) 95 } 96 } 97 98 type blockDefinition struct { 99 timestamp uint64 100 gasUsed uint64 101 } 102 103 type test struct { 104 baseFee *big.Int 105 genBlocks func() []blockDefinition 106 minFee *big.Int 107 } 108 109 func TestDynamicFees(t *testing.T) { 110 spacedTimestamps := []uint64{1, 1, 2, 5, 15, 120} 111 112 var tests []test = []test{ 113 // Test minimal gas usage 114 { 115 baseFee: nil, 116 minFee: testMinBaseFee, 117 genBlocks: func() []blockDefinition { 118 blocks := make([]blockDefinition, 0, len(spacedTimestamps)) 119 for _, timestamp := range spacedTimestamps { 120 blocks = append(blocks, blockDefinition{ 121 timestamp: timestamp, 122 gasUsed: 21000, 123 }) 124 } 125 return blocks 126 }, 127 }, 128 // Test overflow handling 129 { 130 baseFee: nil, 131 minFee: testMinBaseFee, 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 // Test update increase handling 144 { 145 baseFee: big.NewInt(50_000_000_000), 146 minFee: testMinBaseFee, 147 genBlocks: func() []blockDefinition { 148 blocks := make([]blockDefinition, 0, len(spacedTimestamps)) 149 for _, timestamp := range spacedTimestamps { 150 blocks = append(blocks, blockDefinition{ 151 timestamp: timestamp, 152 gasUsed: math.MaxUint64, 153 }) 154 } 155 return blocks 156 }, 157 }, 158 { 159 baseFee: nil, 160 minFee: testMinBaseFee, 161 genBlocks: func() []blockDefinition { 162 return []blockDefinition{ 163 { 164 timestamp: 1, 165 gasUsed: 1_000_000, 166 }, 167 { 168 timestamp: 3, 169 gasUsed: 1_000_000, 170 }, 171 { 172 timestamp: 5, 173 gasUsed: 2_000_000, 174 }, 175 { 176 timestamp: 5, 177 gasUsed: 6_000_000, 178 }, 179 { 180 timestamp: 7, 181 gasUsed: 6_000_000, 182 }, 183 { 184 timestamp: 1000, 185 gasUsed: 6_000_000, 186 }, 187 { 188 timestamp: 1001, 189 gasUsed: 6_000_000, 190 }, 191 { 192 timestamp: 1002, 193 gasUsed: 6_000_000, 194 }, 195 } 196 }, 197 }, 198 } 199 200 for _, test := range tests { 201 testDynamicFeesStaysWithinRange(t, test) 202 } 203 } 204 205 func testDynamicFeesStaysWithinRange(t *testing.T, test test) { 206 blocks := test.genBlocks() 207 initialBlock := blocks[0] 208 header := &types.Header{ 209 Time: initialBlock.timestamp, 210 GasUsed: initialBlock.gasUsed, 211 Number: big.NewInt(0), 212 BaseFee: test.baseFee, 213 } 214 215 for index, block := range blocks[1:] { 216 testFeeConfig := commontype.FeeConfig{ 217 GasLimit: big.NewInt(8_000_000), 218 TargetBlockRate: 2, // in seconds 219 220 MinBaseFee: test.minFee, 221 TargetGas: big.NewInt(15_000_000), 222 BaseFeeChangeDenominator: big.NewInt(36), 223 224 MinBlockGasCost: big.NewInt(0), 225 MaxBlockGasCost: big.NewInt(1_000_000), 226 BlockGasCostStep: big.NewInt(200_000), 227 } 228 229 nextExtraData, nextBaseFee, err := CalcBaseFee(params.TestChainConfig, testFeeConfig, header, block.timestamp) 230 if err != nil { 231 t.Fatalf("Failed to calculate base fee at index %d: %s", index, err) 232 } 233 if nextBaseFee.Cmp(test.minFee) < 0 { 234 t.Fatalf("Expected fee to stay greater than %d, but found %d", test.minFee, nextBaseFee) 235 } 236 log.Info("Update", "baseFee", nextBaseFee) 237 header = &types.Header{ 238 Time: block.timestamp, 239 GasUsed: block.gasUsed, 240 Number: big.NewInt(int64(index) + 1), 241 BaseFee: nextBaseFee, 242 Extra: nextExtraData, 243 } 244 } 245 } 246 247 func TestLongWindow(t *testing.T) { 248 longs := []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 249 sumLongs := uint64(0) 250 longWindow := make([]byte, 10*8) 251 for i, long := range longs { 252 sumLongs = sumLongs + long 253 binary.BigEndian.PutUint64(longWindow[i*8:], long) 254 } 255 256 sum := sumLongWindow(longWindow, 10) 257 if sum != sumLongs { 258 t.Fatalf("Expected sum to be %d but found %d", sumLongs, sum) 259 } 260 261 for i := uint64(0); i < 10; i++ { 262 updateLongWindow(longWindow, i*8, i) 263 sum = sumLongWindow(longWindow, 10) 264 sumLongs += i 265 266 if sum != sumLongs { 267 t.Fatalf("Expected sum to be %d but found %d (iteration: %d)", sumLongs, sum, i) 268 } 269 } 270 } 271 272 func TestLongWindowOverflow(t *testing.T) { 273 longs := []uint64{0, 0, 0, 0, 0, 0, 0, 0, 2, math.MaxUint64 - 1} 274 longWindow := make([]byte, 10*8) 275 for i, long := range longs { 276 binary.BigEndian.PutUint64(longWindow[i*8:], long) 277 } 278 279 sum := sumLongWindow(longWindow, 10) 280 if sum != math.MaxUint64 { 281 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 282 } 283 284 for i := uint64(0); i < 10; i++ { 285 updateLongWindow(longWindow, i*8, i) 286 sum = sumLongWindow(longWindow, 10) 287 288 if sum != math.MaxUint64 { 289 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 290 } 291 } 292 } 293 294 func TestSelectBigWithinBounds(t *testing.T) { 295 type test struct { 296 lower, value, upper, expected *big.Int 297 } 298 299 tests := map[string]test{ 300 "value within bounds": { 301 lower: big.NewInt(0), 302 value: big.NewInt(5), 303 upper: big.NewInt(10), 304 expected: big.NewInt(5), 305 }, 306 "value below lower bound": { 307 lower: big.NewInt(0), 308 value: big.NewInt(-1), 309 upper: big.NewInt(10), 310 expected: big.NewInt(0), 311 }, 312 "value above upper bound": { 313 lower: big.NewInt(0), 314 value: big.NewInt(11), 315 upper: big.NewInt(10), 316 expected: big.NewInt(10), 317 }, 318 "value matches lower bound": { 319 lower: big.NewInt(0), 320 value: big.NewInt(0), 321 upper: big.NewInt(10), 322 expected: big.NewInt(0), 323 }, 324 "value matches upper bound": { 325 lower: big.NewInt(0), 326 value: big.NewInt(10), 327 upper: big.NewInt(10), 328 expected: big.NewInt(10), 329 }, 330 } 331 332 for name, test := range tests { 333 t.Run(name, func(t *testing.T) { 334 v := selectBigWithinBounds(test.lower, test.value, test.upper) 335 if v.Cmp(test.expected) != 0 { 336 t.Fatalf("Expected (%d), found (%d)", test.expected, v) 337 } 338 }) 339 } 340 } 341 342 func TestCalcBlockGasCost(t *testing.T) { 343 tests := map[string]struct { 344 parentBlockGasCost *big.Int 345 parentTime, currentTime uint64 346 347 expected *big.Int 348 }{ 349 "Nil parentBlockGasCost": { 350 parentBlockGasCost: nil, 351 parentTime: 1, 352 currentTime: 1, 353 expected: params.DefaultFeeConfig.MinBlockGasCost, 354 }, 355 "Same timestamp from 0": { 356 parentBlockGasCost: big.NewInt(0), 357 parentTime: 1, 358 currentTime: 1, 359 expected: big.NewInt(100_000), 360 }, 361 "1s from 0": { 362 parentBlockGasCost: big.NewInt(0), 363 parentTime: 1, 364 currentTime: 2, 365 expected: big.NewInt(50_000), 366 }, 367 "Same timestamp from non-zero": { 368 parentBlockGasCost: big.NewInt(50_000), 369 parentTime: 1, 370 currentTime: 1, 371 expected: big.NewInt(150_000), 372 }, 373 "0s Difference (MAX)": { 374 parentBlockGasCost: big.NewInt(1_000_000), 375 parentTime: 1, 376 currentTime: 1, 377 expected: big.NewInt(1_000_000), 378 }, 379 "1s Difference (MAX)": { 380 parentBlockGasCost: big.NewInt(1_000_000), 381 parentTime: 1, 382 currentTime: 2, 383 expected: big.NewInt(1_000_000), 384 }, 385 "2s Difference": { 386 parentBlockGasCost: big.NewInt(900_000), 387 parentTime: 1, 388 currentTime: 3, 389 expected: big.NewInt(900_000), 390 }, 391 "3s Difference": { 392 parentBlockGasCost: big.NewInt(1_000_000), 393 parentTime: 1, 394 currentTime: 4, 395 expected: big.NewInt(950_000), 396 }, 397 "10s Difference": { 398 parentBlockGasCost: big.NewInt(1_000_000), 399 parentTime: 1, 400 currentTime: 11, 401 expected: big.NewInt(600_000), 402 }, 403 "20s Difference": { 404 parentBlockGasCost: big.NewInt(1_000_000), 405 parentTime: 1, 406 currentTime: 21, 407 expected: big.NewInt(100_000), 408 }, 409 "22s Difference": { 410 parentBlockGasCost: big.NewInt(1_000_000), 411 parentTime: 1, 412 currentTime: 23, 413 expected: big.NewInt(0), 414 }, 415 "23s Difference": { 416 parentBlockGasCost: big.NewInt(1_000_000), 417 parentTime: 1, 418 currentTime: 24, 419 expected: big.NewInt(0), 420 }, 421 "-1s Difference": { 422 parentBlockGasCost: big.NewInt(50_000), 423 parentTime: 1, 424 currentTime: 0, 425 expected: big.NewInt(150_000), 426 }, 427 } 428 429 for name, test := range tests { 430 t.Run(name, func(t *testing.T) { 431 assert.Zero(t, test.expected.Cmp(calcBlockGasCost( 432 params.DefaultFeeConfig.TargetBlockRate, 433 params.DefaultFeeConfig.MinBlockGasCost, 434 params.DefaultFeeConfig.MaxBlockGasCost, 435 testBlockGasCostStep, 436 test.parentBlockGasCost, 437 test.parentTime, 438 test.currentTime, 439 ))) 440 }) 441 } 442 }