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  }