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  }