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] }