github.com/dim4egster/coreth@v0.10.2/plugin/evm/gasprice_update_test.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "math/big" 8 "sync" 9 "testing" 10 "time" 11 12 "github.com/dim4egster/coreth/params" 13 ) 14 15 type mockGasPriceSetter struct { 16 lock sync.Mutex 17 price, minFee *big.Int 18 } 19 20 func (m *mockGasPriceSetter) SetGasPrice(price *big.Int) { 21 m.lock.Lock() 22 defer m.lock.Unlock() 23 24 m.price = price 25 } 26 27 func (m *mockGasPriceSetter) SetMinFee(minFee *big.Int) { 28 m.lock.Lock() 29 defer m.lock.Unlock() 30 31 m.minFee = minFee 32 } 33 34 func (m *mockGasPriceSetter) GetStatus() (*big.Int, *big.Int) { 35 m.lock.Lock() 36 defer m.lock.Unlock() 37 38 return m.price, m.minFee 39 } 40 41 func attemptAwait(t *testing.T, wg *sync.WaitGroup, delay time.Duration) { 42 ticker := make(chan struct{}) 43 44 // Wait for [wg] and then close [ticket] to indicate that 45 // the wait group has finished. 46 go func() { 47 wg.Wait() 48 close(ticker) 49 }() 50 51 select { 52 case <-time.After(delay): 53 t.Fatal("Timed out waiting for wait group to complete") 54 case <-ticker: 55 // The wait group completed without issue 56 } 57 } 58 59 func TestUpdateGasPriceShutsDown(t *testing.T) { 60 shutdownChan := make(chan struct{}) 61 wg := &sync.WaitGroup{} 62 config := *params.TestChainConfig 63 // Set ApricotPhase3BlockTime one hour in the future so that it will 64 // create a goroutine waiting for an hour before updating the gas price 65 config.ApricotPhase3BlockTimestamp = big.NewInt(time.Now().Add(time.Hour).Unix()) 66 gpu := &gasPriceUpdater{ 67 setter: &mockGasPriceSetter{price: big.NewInt(1)}, 68 chainConfig: &config, 69 shutdownChan: shutdownChan, 70 wg: wg, 71 } 72 73 gpu.start() 74 // Close [shutdownChan] and ensure that the wait group finishes in a reasonable 75 // amount of time. 76 close(shutdownChan) 77 attemptAwait(t, wg, 5*time.Second) 78 } 79 80 func TestUpdateGasPriceInitializesPrice(t *testing.T) { 81 shutdownChan := make(chan struct{}) 82 wg := &sync.WaitGroup{} 83 gpu := &gasPriceUpdater{ 84 setter: &mockGasPriceSetter{price: big.NewInt(1)}, 85 chainConfig: params.TestChainConfig, 86 shutdownChan: shutdownChan, 87 wg: wg, 88 } 89 90 gpu.start() 91 // The wait group should finish immediately since no goroutine 92 // should be created when all prices should be set from the start 93 attemptAwait(t, wg, time.Millisecond) 94 95 if gpu.setter.(*mockGasPriceSetter).price.Cmp(big.NewInt(0)) != 0 { 96 t.Fatalf("Expected price to match minimum base fee for apricot phase3") 97 } 98 if minFee := gpu.setter.(*mockGasPriceSetter).minFee; minFee == nil || minFee.Cmp(big.NewInt(params.ApricotPhase4MinBaseFee)) != 0 { 99 t.Fatalf("Expected min fee to match minimum fee for apricotPhase4, but found: %d", minFee) 100 } 101 } 102 103 func TestUpdateGasPriceUpdatesPrice(t *testing.T) { 104 shutdownChan := make(chan struct{}) 105 wg := &sync.WaitGroup{} 106 config := *params.TestChainConfig 107 // Set ApricotPhase3BlockTime 250ms in the future so that it will 108 // create a goroutine waiting for the time to update the gas price 109 config.ApricotPhase3BlockTimestamp = big.NewInt(time.Now().Add(250 * time.Millisecond).Unix()) 110 config.ApricotPhase4BlockTimestamp = big.NewInt(time.Now().Add(3 * time.Second).Unix()) 111 gpu := &gasPriceUpdater{ 112 setter: &mockGasPriceSetter{price: big.NewInt(1)}, 113 chainConfig: &config, 114 shutdownChan: shutdownChan, 115 wg: wg, 116 } 117 118 gpu.start() 119 120 // With ApricotPhase3 set slightly in the future, the gas price updater should create a 121 // goroutine to sleep until its time to update and mark the wait group as done when it has 122 // completed the update. 123 time.Sleep(1 * time.Second) 124 price, minFee := gpu.setter.(*mockGasPriceSetter).GetStatus() 125 if price.Cmp(big.NewInt(0)) != 0 { 126 t.Fatalf("Expected price to match minimum base fee for apricot phase3") 127 } 128 if minFee == nil || minFee.Cmp(big.NewInt(params.ApricotPhase3MinBaseFee)) != 0 { 129 t.Fatalf("Expected min fee to match minimum fee for apricotPhase3, but found: %d", minFee) 130 } 131 132 // Confirm ApricotPhase4 settings are applied at the very end. 133 attemptAwait(t, wg, 5*time.Second) 134 price, minFee = gpu.setter.(*mockGasPriceSetter).GetStatus() 135 if price.Cmp(big.NewInt(0)) != 0 { 136 t.Fatalf("Expected price to match minimum base fee for apricot phase4") 137 } 138 if minFee == nil || minFee.Cmp(big.NewInt(params.ApricotPhase4MinBaseFee)) != 0 { 139 t.Fatalf("Expected min fee to match minimum fee for apricotPhase4, but found: %d", minFee) 140 } 141 }