decred.org/dcrdex@v1.0.5/dex/txfee/feefetcher_test.go (about)

     1  package txfee
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"decred.org/dcrdex/dex"
     8  )
     9  
    10  func TestGroupedSources(t *testing.T) {
    11  	log := dex.StdOutLogger("T", dex.LevelTrace)
    12  	checkSort := func(sources []*SourceConfig, groupSizes ...int) {
    13  		t.Helper()
    14  		groups := groupedSources(sources, log)
    15  		if len(groups) != len(groupSizes) {
    16  			t.Fatalf("expected %d groups, got %d", len(groupSizes), len(groups))
    17  		}
    18  		for i, group := range groups {
    19  			if len(group) != groupSizes[i] {
    20  				t.Fatalf("%d'th group has %d members. expected %d", i, len(group), groupSizes[i])
    21  			}
    22  		}
    23  	}
    24  	sources := func(ranks ...uint) (srcs []*SourceConfig) {
    25  		for _, rank := range ranks {
    26  			srcs = append(srcs, &SourceConfig{Rank: rank})
    27  		}
    28  		return
    29  	}
    30  	checkSort(sources(1, 1), 2)
    31  	checkSort(sources(1, 2), 1, 1)
    32  	checkSort(sources(1, 1, 2), 2, 1)
    33  	checkSort(sources(4, 4, 4, 2, 1, 1), 2, 1, 3)
    34  }
    35  
    36  func TestPrioritizedFeeRate(t *testing.T) {
    37  	feeFetchers := func(priorityRates [][2]uint) [][]*feeFetchSource {
    38  		sources := make([]*feeFetchSource, len(priorityRates))
    39  		for i, rr := range priorityRates {
    40  			rank, rate := rr[0], rr[1]
    41  			sources[i] = &feeFetchSource{
    42  				SourceConfig: &SourceConfig{Rank: rank},
    43  				rate:         uint64(rate),
    44  				stamp:        time.Now(),
    45  			}
    46  		}
    47  		return groupSources(sources)
    48  	}
    49  
    50  	var fetchers [][]*feeFetchSource
    51  	checkRate := func(expRate uint64) {
    52  		t.Helper()
    53  		if r := prioritizedFeeRate(fetchers); r != expRate {
    54  			t.Fatalf("expected rate %d, got %d", expRate, r)
    55  		}
    56  	}
    57  
    58  	// just one
    59  	fetchers = feeFetchers([][2]uint{
    60  		{1, 10},
    61  	})
    62  	checkRate(10)
    63  
    64  	// good until expired
    65  	f0 := fetchers[0][0]
    66  	f0.stamp = time.Now().Add(-feeExpiration + time.Second*10)
    67  	checkRate(10)
    68  	// expired
    69  	f0.stamp = time.Now().Add(-feeExpiration)
    70  	checkRate(0)
    71  
    72  	// two at different priorities
    73  	fetchers = feeFetchers([][2]uint{
    74  		{1, 10},
    75  		{2, 20},
    76  	})
    77  	// Only first is considered if not expired or failed.
    78  	checkRate(10)
    79  	// expire first
    80  	f0, f1 := fetchers[0][0], fetchers[1][0]
    81  	f0.stamp = time.Now().Add(-feeExpiration)
    82  	checkRate(20)
    83  	// first failed
    84  	f0.stamp = time.Now()
    85  	f0.failUntil = time.Now()
    86  	checkRate(20)
    87  	// both failed
    88  	f1.failUntil = time.Now()
    89  	checkRate(0)
    90  
    91  	// first group has multiple
    92  	fetchers = feeFetchers([][2]uint{
    93  		{1, 10}, {1, 30},
    94  		{2, 250},
    95  	})
    96  	checkRate(20)
    97  	// expire second from group 1
    98  	f0, f1 = fetchers[0][0], fetchers[0][1]
    99  	f1.failUntil = time.Now()
   100  	checkRate(10)
   101  	// second from group 1 half-decayed
   102  	f1.failUntil = time.Time{}
   103  	f1.stamp = time.Now().Add(-1 * (feeFetchFullValidityPeriod + (feeFetchValidityDecayPeriod / 2)))
   104  	checkRate(17) // (10 + (0.5 * 30)) / 1.5 = 16.6666
   105  	// first from group 1  decayed by 75%
   106  	f1.stamp = time.Now()
   107  	f0.stamp = time.Now().Add(-1 * (feeFetchFullValidityPeriod + (feeFetchValidityDecayPeriod * 3 / 4)))
   108  	checkRate(26) // (30 + (0.25 * 10)) / 1.25 = 26
   109  	// group 1 unusable
   110  	f0.failUntil = time.Now()
   111  	f1.failUntil = time.Now()
   112  	checkRate(250)
   113  }