github.com/dim4egster/coreth@v0.10.2/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/dim4egster/coreth/core/types" 12 "github.com/dim4egster/coreth/params" 13 "github.com/ethereum/go-ethereum/common/math" 14 "github.com/ethereum/go-ethereum/log" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 func testRollup(t *testing.T, longs []uint64, roll int) { 19 slice := make([]byte, len(longs)*8) 20 numLongs := len(longs) 21 for i := 0; i < numLongs; i++ { 22 binary.BigEndian.PutUint64(slice[8*i:], longs[i]) 23 } 24 25 newSlice, err := rollLongWindow(slice, roll) 26 if err != nil { 27 t.Fatal(err) 28 } 29 // numCopies is the number of longs that should have been copied over from the previous 30 // slice as opposed to being left empty. 31 numCopies := numLongs - roll 32 for i := 0; i < numLongs; i++ { 33 // Extract the long value that is encoded at position [i] in [newSlice] 34 num := binary.BigEndian.Uint64(newSlice[8*i:]) 35 // If the current index is past the point where we should have copied the value 36 // over from the previous slice, assert that the value encoded in [newSlice] 37 // is 0 38 if i >= numCopies { 39 if num != 0 { 40 t.Errorf("Expected num encoded in newSlice at position %d to be 0, but found %d", i, num) 41 } 42 } else { 43 // Otherwise, check that the value was copied over correctly 44 prevIndex := i + roll 45 prevNum := longs[prevIndex] 46 if prevNum != num { 47 t.Errorf("Expected num encoded in new slice at position %d to be %d, but found %d", i, prevNum, num) 48 } 49 } 50 } 51 } 52 53 func TestRollupWindow(t *testing.T) { 54 type test struct { 55 longs []uint64 56 roll int 57 } 58 59 var tests []test = []test{ 60 { 61 []uint64{1, 2, 3, 4}, 62 0, 63 }, 64 { 65 []uint64{1, 2, 3, 4}, 66 1, 67 }, 68 { 69 []uint64{1, 2, 3, 4}, 70 2, 71 }, 72 { 73 []uint64{1, 2, 3, 4}, 74 3, 75 }, 76 { 77 []uint64{1, 2, 3, 4}, 78 4, 79 }, 80 { 81 []uint64{1, 2, 3, 4}, 82 5, 83 }, 84 { 85 []uint64{121, 232, 432}, 86 2, 87 }, 88 } 89 90 for _, test := range tests { 91 testRollup(t, test.longs, test.roll) 92 } 93 } 94 95 type blockDefinition struct { 96 timestamp uint64 97 gasUsed uint64 98 extDataGasUsed *big.Int 99 } 100 101 type test struct { 102 extraData []byte 103 baseFee *big.Int 104 genBlocks func() []blockDefinition 105 minFee, maxFee *big.Int 106 } 107 108 func TestDynamicFees(t *testing.T) { 109 spacedTimestamps := []uint64{1, 1, 2, 5, 15, 120} 110 var tests []test = []test{ 111 // Test minimal gas usage 112 { 113 extraData: nil, 114 baseFee: nil, 115 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 116 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 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 extraData: nil, 131 baseFee: nil, 132 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 133 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 134 genBlocks: func() []blockDefinition { 135 blocks := make([]blockDefinition, 0, len(spacedTimestamps)) 136 for _, timestamp := range spacedTimestamps { 137 blocks = append(blocks, blockDefinition{ 138 timestamp: timestamp, 139 gasUsed: math.MaxUint64, 140 }) 141 } 142 return blocks 143 }, 144 }, 145 { 146 extraData: nil, 147 baseFee: nil, 148 minFee: big.NewInt(params.ApricotPhase3MinBaseFee), 149 maxFee: big.NewInt(params.ApricotPhase3MaxBaseFee), 150 genBlocks: func() []blockDefinition { 151 return []blockDefinition{ 152 { 153 timestamp: 1, 154 gasUsed: 1_000_000, 155 }, 156 { 157 timestamp: 3, 158 gasUsed: 1_000_000, 159 }, 160 { 161 timestamp: 5, 162 gasUsed: 2_000_000, 163 }, 164 { 165 timestamp: 5, 166 gasUsed: 6_000_000, 167 }, 168 { 169 timestamp: 7, 170 gasUsed: 6_000_000, 171 }, 172 { 173 timestamp: 1000, 174 gasUsed: 6_000_000, 175 }, 176 { 177 timestamp: 1001, 178 gasUsed: 6_000_000, 179 }, 180 { 181 timestamp: 1002, 182 gasUsed: 6_000_000, 183 }, 184 } 185 }, 186 }, 187 } 188 189 for _, test := range tests { 190 testDynamicFeesStaysWithinRange(t, test) 191 } 192 } 193 194 func testDynamicFeesStaysWithinRange(t *testing.T, test test) { 195 blocks := test.genBlocks() 196 initialBlock := blocks[0] 197 header := &types.Header{ 198 Time: initialBlock.timestamp, 199 GasUsed: initialBlock.gasUsed, 200 Number: big.NewInt(0), 201 BaseFee: test.baseFee, 202 Extra: test.extraData, 203 } 204 205 for index, block := range blocks[1:] { 206 nextExtraData, nextBaseFee, err := CalcBaseFee(params.TestApricotPhase3Config, header, block.timestamp) 207 if err != nil { 208 t.Fatalf("Failed to calculate base fee at index %d: %s", index, err) 209 } 210 if nextBaseFee.Cmp(test.maxFee) > 0 { 211 t.Fatalf("Expected fee to stay less than %d, but found %d", test.maxFee, nextBaseFee) 212 } 213 if nextBaseFee.Cmp(test.minFee) < 0 { 214 t.Fatalf("Expected fee to stay greater than %d, but found %d", test.minFee, nextBaseFee) 215 } 216 log.Info("Update", "baseFee", nextBaseFee) 217 header = &types.Header{ 218 Time: block.timestamp, 219 GasUsed: block.gasUsed, 220 Number: big.NewInt(int64(index) + 1), 221 BaseFee: nextBaseFee, 222 Extra: nextExtraData, 223 } 224 } 225 } 226 227 func TestLongWindow(t *testing.T) { 228 longs := []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 229 sumLongs := uint64(0) 230 longWindow := make([]byte, 10*8) 231 for i, long := range longs { 232 sumLongs = sumLongs + long 233 binary.BigEndian.PutUint64(longWindow[i*8:], long) 234 } 235 236 sum := sumLongWindow(longWindow, 10) 237 if sum != sumLongs { 238 t.Fatalf("Expected sum to be %d but found %d", sumLongs, sum) 239 } 240 241 for i := uint64(0); i < 10; i++ { 242 updateLongWindow(longWindow, i*8, i) 243 sum = sumLongWindow(longWindow, 10) 244 sumLongs += i 245 246 if sum != sumLongs { 247 t.Fatalf("Expected sum to be %d but found %d (iteration: %d)", sumLongs, sum, i) 248 } 249 } 250 } 251 252 func TestLongWindowOverflow(t *testing.T) { 253 longs := []uint64{0, 0, 0, 0, 0, 0, 0, 0, 2, math.MaxUint64 - 1} 254 longWindow := make([]byte, 10*8) 255 for i, long := range longs { 256 binary.BigEndian.PutUint64(longWindow[i*8:], long) 257 } 258 259 sum := sumLongWindow(longWindow, 10) 260 if sum != math.MaxUint64 { 261 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 262 } 263 264 for i := uint64(0); i < 10; i++ { 265 updateLongWindow(longWindow, i*8, i) 266 sum = sumLongWindow(longWindow, 10) 267 268 if sum != math.MaxUint64 { 269 t.Fatalf("Expected sum to be maxUint64 (%d), but found %d", uint64(math.MaxUint64), sum) 270 } 271 } 272 } 273 274 func TestSelectBigWithinBounds(t *testing.T) { 275 type test struct { 276 lower, value, upper, expected *big.Int 277 } 278 279 var tests = map[string]test{ 280 "value within bounds": { 281 lower: big.NewInt(0), 282 value: big.NewInt(5), 283 upper: big.NewInt(10), 284 expected: big.NewInt(5), 285 }, 286 "value below lower bound": { 287 lower: big.NewInt(0), 288 value: big.NewInt(-1), 289 upper: big.NewInt(10), 290 expected: big.NewInt(0), 291 }, 292 "value above upper bound": { 293 lower: big.NewInt(0), 294 value: big.NewInt(11), 295 upper: big.NewInt(10), 296 expected: big.NewInt(10), 297 }, 298 "value matches lower bound": { 299 lower: big.NewInt(0), 300 value: big.NewInt(0), 301 upper: big.NewInt(10), 302 expected: big.NewInt(0), 303 }, 304 "value matches upper bound": { 305 lower: big.NewInt(0), 306 value: big.NewInt(10), 307 upper: big.NewInt(10), 308 expected: big.NewInt(10), 309 }, 310 } 311 312 for name, test := range tests { 313 t.Run(name, func(t *testing.T) { 314 v := selectBigWithinBounds(test.lower, test.value, test.upper) 315 if v.Cmp(test.expected) != 0 { 316 t.Fatalf("Expected (%d), found (%d)", test.expected, v) 317 } 318 }) 319 } 320 } 321 322 // TestCalcBaseFeeAP4 confirms that the inclusion of ExtDataGasUsage increases 323 // the base fee. 324 func TestCalcBaseFeeAP4(t *testing.T) { 325 events := []struct { 326 block blockDefinition 327 extDataFeeGreater bool 328 }{ 329 { 330 block: blockDefinition{ 331 timestamp: 1, 332 gasUsed: 1_000_000, 333 extDataGasUsed: big.NewInt(100_000), 334 }, 335 }, 336 { 337 block: blockDefinition{ 338 timestamp: 3, 339 gasUsed: 1_000_000, 340 extDataGasUsed: big.NewInt(10_000), 341 }, 342 extDataFeeGreater: true, 343 }, 344 { 345 block: blockDefinition{ 346 timestamp: 5, 347 gasUsed: 2_000_000, 348 extDataGasUsed: big.NewInt(50_000), 349 }, 350 extDataFeeGreater: true, 351 }, 352 { 353 block: blockDefinition{ 354 timestamp: 5, 355 gasUsed: 6_000_000, 356 extDataGasUsed: big.NewInt(50_000), 357 }, 358 extDataFeeGreater: true, 359 }, 360 { 361 block: blockDefinition{ 362 timestamp: 7, 363 gasUsed: 6_000_000, 364 extDataGasUsed: big.NewInt(0), 365 }, 366 extDataFeeGreater: true, 367 }, 368 { 369 block: blockDefinition{ 370 timestamp: 1000, 371 gasUsed: 6_000_000, 372 extDataGasUsed: big.NewInt(0), 373 }, 374 }, 375 { 376 block: blockDefinition{ 377 timestamp: 1001, 378 gasUsed: 6_000_000, 379 extDataGasUsed: big.NewInt(10_000), 380 }, 381 }, 382 { 383 block: blockDefinition{ 384 timestamp: 1002, 385 gasUsed: 6_000_000, 386 extDataGasUsed: big.NewInt(0), 387 }, 388 extDataFeeGreater: true, 389 }, 390 } 391 392 header := &types.Header{ 393 Time: 0, 394 GasUsed: 1_000_000, 395 Number: big.NewInt(0), 396 BaseFee: big.NewInt(225 * params.GWei), 397 Extra: nil, 398 } 399 extDataHeader := &types.Header{ 400 Time: 0, 401 GasUsed: 1_000_000, 402 Number: big.NewInt(0), 403 BaseFee: big.NewInt(225 * params.GWei), 404 Extra: nil, 405 // ExtDataGasUsage is set to be nil to ensure CalcBaseFee can handle the 406 // AP3/AP4 boundary. 407 } 408 409 for index, event := range events { 410 block := event.block 411 nextExtraData, nextBaseFee, err := CalcBaseFee(params.TestApricotPhase4Config, header, block.timestamp) 412 assert.NoError(t, err) 413 log.Info("Update", "baseFee", nextBaseFee) 414 header = &types.Header{ 415 Time: block.timestamp, 416 GasUsed: block.gasUsed, 417 Number: big.NewInt(int64(index) + 1), 418 BaseFee: nextBaseFee, 419 Extra: nextExtraData, 420 } 421 422 nextExtraData, nextBaseFee, err = CalcBaseFee(params.TestApricotPhase4Config, extDataHeader, block.timestamp) 423 assert.NoError(t, err) 424 log.Info("Update", "baseFee (w/extData)", nextBaseFee) 425 extDataHeader = &types.Header{ 426 Time: block.timestamp, 427 GasUsed: block.gasUsed, 428 Number: big.NewInt(int64(index) + 1), 429 BaseFee: nextBaseFee, 430 Extra: nextExtraData, 431 ExtDataGasUsed: block.extDataGasUsed, 432 } 433 434 assert.Equal(t, event.extDataFeeGreater, extDataHeader.BaseFee.Cmp(header.BaseFee) == 1, "unexpected cmp for index %d", index) 435 } 436 } 437 438 func TestCalcBlockGasCost(t *testing.T) { 439 tests := map[string]struct { 440 parentBlockGasCost *big.Int 441 parentTime, currentTime uint64 442 443 expected *big.Int 444 }{ 445 "Nil parentBlockGasCost": { 446 parentBlockGasCost: nil, 447 parentTime: 1, 448 currentTime: 1, 449 expected: ApricotPhase4MinBlockGasCost, 450 }, 451 "Same timestamp from 0": { 452 parentBlockGasCost: big.NewInt(0), 453 parentTime: 1, 454 currentTime: 1, 455 expected: big.NewInt(100_000), 456 }, 457 "1s from 0": { 458 parentBlockGasCost: big.NewInt(0), 459 parentTime: 1, 460 currentTime: 2, 461 expected: big.NewInt(50_000), 462 }, 463 "Same timestamp from non-zero": { 464 parentBlockGasCost: big.NewInt(50_000), 465 parentTime: 1, 466 currentTime: 1, 467 expected: big.NewInt(150_000), 468 }, 469 "0s Difference (MAX)": { 470 parentBlockGasCost: big.NewInt(1_000_000), 471 parentTime: 1, 472 currentTime: 1, 473 expected: big.NewInt(1_000_000), 474 }, 475 "1s Difference (MAX)": { 476 parentBlockGasCost: big.NewInt(1_000_000), 477 parentTime: 1, 478 currentTime: 2, 479 expected: big.NewInt(1_000_000), 480 }, 481 "2s Difference": { 482 parentBlockGasCost: big.NewInt(900_000), 483 parentTime: 1, 484 currentTime: 3, 485 expected: big.NewInt(900_000), 486 }, 487 "3s Difference": { 488 parentBlockGasCost: big.NewInt(1_000_000), 489 parentTime: 1, 490 currentTime: 4, 491 expected: big.NewInt(950_000), 492 }, 493 "10s Difference": { 494 parentBlockGasCost: big.NewInt(1_000_000), 495 parentTime: 1, 496 currentTime: 11, 497 expected: big.NewInt(600_000), 498 }, 499 "20s Difference": { 500 parentBlockGasCost: big.NewInt(1_000_000), 501 parentTime: 1, 502 currentTime: 21, 503 expected: big.NewInt(100_000), 504 }, 505 "22s Difference": { 506 parentBlockGasCost: big.NewInt(1_000_000), 507 parentTime: 1, 508 currentTime: 23, 509 expected: big.NewInt(0), 510 }, 511 "23s Difference": { 512 parentBlockGasCost: big.NewInt(1_000_000), 513 parentTime: 1, 514 currentTime: 24, 515 expected: big.NewInt(0), 516 }, 517 "-1s Difference": { 518 parentBlockGasCost: big.NewInt(50_000), 519 parentTime: 1, 520 currentTime: 0, 521 expected: big.NewInt(150_000), 522 }, 523 } 524 525 for name, test := range tests { 526 t.Run(name, func(t *testing.T) { 527 assert.Zero(t, test.expected.Cmp(calcBlockGasCost( 528 ApricotPhase4TargetBlockRate, 529 ApricotPhase4MinBlockGasCost, 530 ApricotPhase4MaxBlockGasCost, 531 ApricotPhase4BlockGasCostStep, 532 test.parentBlockGasCost, 533 test.parentTime, 534 test.currentTime, 535 ))) 536 }) 537 } 538 }