github.com/okex/exchain@v1.8.0/libs/tendermint/types/recommended_gasprice.go (about)

     1  package types
     2  
     3  import (
     4  	"errors"
     5  	"math/big"
     6  	"sort"
     7  )
     8  
     9  const (
    10  	sampleNumber = 3 // Number of transactions sampled in a block
    11  
    12  	CongestionHigherGpMode = 0
    13  	NormalGpMode           = 1
    14  	MinimalGpMode          = 2
    15  
    16  	NoGasUsedCap = -1
    17  )
    18  
    19  // SingleBlockGPs holds the gas price of all transactions in a block
    20  // and will sample the lower few gas prices according to sampleNumber.
    21  type SingleBlockGPs struct {
    22  	// gas price of all transactions
    23  	all []*big.Int
    24  	// gas price of transactions sampled in a block
    25  	sampled []*big.Int
    26  	// total gas of all tx in the block
    27  	gasUsed uint64
    28  }
    29  
    30  func NewSingleBlockGPs() *SingleBlockGPs {
    31  	return &SingleBlockGPs{
    32  		all:     make([]*big.Int, 0),
    33  		sampled: make([]*big.Int, 0),
    34  		gasUsed: 0,
    35  	}
    36  }
    37  
    38  func (bgp SingleBlockGPs) GetAll() []*big.Int {
    39  	return bgp.all
    40  }
    41  
    42  func (bgp SingleBlockGPs) GetSampled() []*big.Int {
    43  	return bgp.sampled
    44  }
    45  
    46  func (bgp SingleBlockGPs) GetGasUsed() uint64 {
    47  	return bgp.gasUsed
    48  }
    49  
    50  func (bgp *SingleBlockGPs) AddSampledGP(gp *big.Int) {
    51  	gpCopy := new(big.Int).Set(gp)
    52  	bgp.sampled = append(bgp.sampled, gpCopy)
    53  }
    54  
    55  func (bgp *SingleBlockGPs) Update(gp *big.Int, gas uint64) {
    56  	gpCopy := new(big.Int).Set(gp)
    57  	bgp.all = append(bgp.all, gpCopy)
    58  	bgp.gasUsed += gas
    59  }
    60  
    61  func (bgp *SingleBlockGPs) Clear() {
    62  	bgp.all = make([]*big.Int, 0)
    63  	bgp.sampled = make([]*big.Int, 0)
    64  	bgp.gasUsed = 0
    65  }
    66  
    67  func (bgp *SingleBlockGPs) Copy() *SingleBlockGPs {
    68  	return &SingleBlockGPs{
    69  		all:     bgp.all,
    70  		sampled: bgp.sampled,
    71  		gasUsed: bgp.gasUsed,
    72  	}
    73  }
    74  
    75  func (bgp *SingleBlockGPs) SampleGP(adoptHigherGp bool) {
    76  	// "len(bgp.sampled) != 0" means it has been sampled
    77  	if len(bgp.sampled) != 0 {
    78  		return
    79  	}
    80  
    81  	txGPs := make([]*big.Int, len(bgp.all))
    82  	copy(txGPs, bgp.all)
    83  	sort.Sort(BigIntArray(txGPs))
    84  
    85  	if adoptHigherGp {
    86  
    87  		rowSampledGPs := make([]*big.Int, 0)
    88  
    89  		// Addition of sampleNumber lower-priced gp
    90  		for i := 0; i < len(txGPs); i++ {
    91  			if i >= sampleNumber {
    92  				break
    93  			}
    94  			rowSampledGPs = append(rowSampledGPs, new(big.Int).Set(txGPs[i]))
    95  		}
    96  
    97  		// Addition of sampleNumber higher-priced gp
    98  		for i := len(txGPs) - 1; i >= 0; i-- {
    99  			if len(txGPs)-1-i >= sampleNumber {
   100  				break
   101  			}
   102  			rowSampledGPs = append(rowSampledGPs, new(big.Int).Set(txGPs[i]))
   103  		}
   104  
   105  		if len(rowSampledGPs) != 0 {
   106  			sampledGPLen := big.NewInt(int64(len(rowSampledGPs)))
   107  			sum := big.NewInt(0)
   108  			for _, gp := range rowSampledGPs {
   109  				sum.Add(sum, gp)
   110  			}
   111  
   112  			avgGP := new(big.Int).Quo(sum, sampledGPLen)
   113  			bgp.AddSampledGP(avgGP)
   114  		}
   115  	} else {
   116  		for _, gp := range txGPs {
   117  			bgp.AddSampledGP(gp)
   118  			if len(bgp.sampled) >= sampleNumber {
   119  				break
   120  			}
   121  		}
   122  	}
   123  }
   124  
   125  // BlockGPResults is a circular queue of SingleBlockGPs
   126  type BlockGPResults struct {
   127  	items    []*SingleBlockGPs
   128  	front    int
   129  	rear     int
   130  	capacity int
   131  }
   132  
   133  func NewBlockGPResults(checkBlocksNum int) *BlockGPResults {
   134  	circularQueue := &BlockGPResults{
   135  		items:    make([]*SingleBlockGPs, checkBlocksNum, checkBlocksNum),
   136  		front:    -1,
   137  		rear:     -1,
   138  		capacity: checkBlocksNum,
   139  	}
   140  	return circularQueue
   141  }
   142  
   143  func (rs BlockGPResults) IsFull() bool {
   144  	if rs.front == 0 && rs.rear == rs.capacity-1 {
   145  		return true
   146  	}
   147  	if rs.front == rs.rear+1 {
   148  		return true
   149  	}
   150  	return false
   151  }
   152  
   153  func (rs BlockGPResults) IsEmpty() bool {
   154  	return rs.front == -1
   155  }
   156  
   157  func (rs BlockGPResults) Front() int {
   158  	return rs.front
   159  }
   160  
   161  func (rs BlockGPResults) Rear() int {
   162  	return rs.rear
   163  }
   164  
   165  func (rs BlockGPResults) Cap() int {
   166  	return rs.capacity
   167  }
   168  
   169  func (rs *BlockGPResults) Push(gp *SingleBlockGPs) error {
   170  	if rs.IsFull() {
   171  		_, err := rs.Pop()
   172  		if err != nil {
   173  			return err
   174  		}
   175  	}
   176  	if rs.front == -1 {
   177  		rs.front = 0
   178  	}
   179  	rs.rear = (rs.rear + 1) % rs.capacity
   180  	rs.items[rs.rear] = gp
   181  	return nil
   182  }
   183  
   184  func (rs *BlockGPResults) Pop() (*SingleBlockGPs, error) {
   185  	if rs.IsEmpty() {
   186  		return nil, errors.New("pop failed: BlockGPResults is empty")
   187  	}
   188  	element := rs.items[rs.front]
   189  	if rs.front == rs.rear {
   190  		// rs has only one element,
   191  		// so we reset the queue after deleting it
   192  		rs.front = -1
   193  		rs.rear = -1
   194  	} else {
   195  		rs.front = (rs.front + 1) % rs.capacity
   196  	}
   197  	return element, nil
   198  }
   199  
   200  func (rs *BlockGPResults) ExecuteSamplingBy(lastPrice *big.Int, adoptHigherGp bool) []*big.Int {
   201  	var txPrices []*big.Int
   202  	if !rs.IsEmpty() {
   203  		// traverse the circular queue
   204  		for i := rs.front; i != rs.rear; i = (i + 1) % rs.capacity {
   205  			rs.items[i].SampleGP(adoptHigherGp)
   206  			// If block is empty, use the latest gas price for sampling.
   207  			if len(rs.items[i].sampled) == 0 {
   208  				rs.items[i].AddSampledGP(lastPrice)
   209  			}
   210  			txPrices = append(txPrices, rs.items[i].sampled...)
   211  		}
   212  		rs.items[rs.rear].SampleGP(adoptHigherGp)
   213  		if len(rs.items[rs.rear].sampled) == 0 {
   214  			rs.items[rs.rear].AddSampledGP(lastPrice)
   215  		}
   216  		txPrices = append(txPrices, rs.items[rs.rear].sampled...)
   217  	}
   218  	return txPrices
   219  }
   220  
   221  type BigIntArray []*big.Int
   222  
   223  func (s BigIntArray) Len() int           { return len(s) }
   224  func (s BigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 }
   225  func (s BigIntArray) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }