gasprice.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2015 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package eth
  17. import (
  18. "math/big"
  19. "math/rand"
  20. "sync"
  21. "github.com/ethereum/go-ethereum/core"
  22. "github.com/ethereum/go-ethereum/core/types"
  23. "github.com/ethereum/go-ethereum/event"
  24. "github.com/ethereum/go-ethereum/logger"
  25. "github.com/ethereum/go-ethereum/logger/glog"
  26. )
  27. const gpoProcessPastBlocks = 100
  28. type blockPriceInfo struct {
  29. baseGasPrice *big.Int
  30. }
  31. type GasPriceOracle struct {
  32. eth *Ethereum
  33. chain *core.BlockChain
  34. events event.Subscription
  35. blocks map[uint64]*blockPriceInfo
  36. firstProcessed, lastProcessed uint64
  37. lastBaseMutex sync.Mutex
  38. lastBase, minBase *big.Int
  39. }
  40. func NewGasPriceOracle(eth *Ethereum) (self *GasPriceOracle) {
  41. self = &GasPriceOracle{}
  42. self.blocks = make(map[uint64]*blockPriceInfo)
  43. self.eth = eth
  44. self.chain = eth.blockchain
  45. self.events = eth.EventMux().Subscribe(
  46. core.ChainEvent{},
  47. core.ChainSplitEvent{},
  48. )
  49. minbase := new(big.Int).Mul(self.eth.GpoMinGasPrice, big.NewInt(100))
  50. minbase = minbase.Div(minbase, big.NewInt(int64(self.eth.GpobaseCorrectionFactor)))
  51. self.minBase = minbase
  52. self.processPastBlocks()
  53. go self.listenLoop()
  54. return
  55. }
  56. func (self *GasPriceOracle) processPastBlocks() {
  57. last := int64(-1)
  58. cblock := self.chain.CurrentBlock()
  59. if cblock != nil {
  60. last = int64(cblock.NumberU64())
  61. }
  62. first := int64(0)
  63. if last > gpoProcessPastBlocks {
  64. first = last - gpoProcessPastBlocks
  65. }
  66. self.firstProcessed = uint64(first)
  67. for i := first; i <= last; i++ {
  68. block := self.chain.GetBlockByNumber(uint64(i))
  69. if block != nil {
  70. self.processBlock(block)
  71. }
  72. }
  73. }
  74. func (self *GasPriceOracle) listenLoop() {
  75. defer self.events.Unsubscribe()
  76. for event := range self.events.Chan() {
  77. switch event := event.Data.(type) {
  78. case core.ChainEvent:
  79. self.processBlock(event.Block)
  80. case core.ChainSplitEvent:
  81. self.processBlock(event.Block)
  82. }
  83. }
  84. }
  85. func (self *GasPriceOracle) processBlock(block *types.Block) {
  86. i := block.NumberU64()
  87. if i > self.lastProcessed {
  88. self.lastProcessed = i
  89. }
  90. lastBase := self.eth.GpoMinGasPrice
  91. bpl := self.blocks[i-1]
  92. if bpl != nil {
  93. lastBase = bpl.baseGasPrice
  94. }
  95. if lastBase == nil {
  96. return
  97. }
  98. var corr int
  99. lp := self.lowestPrice(block)
  100. if lp == nil {
  101. return
  102. }
  103. if lastBase.Cmp(lp) < 0 {
  104. corr = self.eth.GpobaseStepUp
  105. } else {
  106. corr = -self.eth.GpobaseStepDown
  107. }
  108. crand := int64(corr * (900 + rand.Intn(201)))
  109. newBase := new(big.Int).Mul(lastBase, big.NewInt(1000000+crand))
  110. newBase.Div(newBase, big.NewInt(1000000))
  111. if newBase.Cmp(self.minBase) < 0 {
  112. newBase = self.minBase
  113. }
  114. bpi := self.blocks[i]
  115. if bpi == nil {
  116. bpi = &blockPriceInfo{}
  117. self.blocks[i] = bpi
  118. }
  119. bpi.baseGasPrice = newBase
  120. self.lastBaseMutex.Lock()
  121. self.lastBase = newBase
  122. self.lastBaseMutex.Unlock()
  123. glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", block.NumberU64(), newBase.Int64())
  124. }
  125. // returns the lowers possible price with which a tx was or could have been included
  126. func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
  127. gasUsed := big.NewInt(0)
  128. receipts := self.eth.BlockProcessor().GetBlockReceipts(block.Hash())
  129. if len(receipts) > 0 {
  130. if cgu := receipts[len(receipts)-1].CumulativeGasUsed; cgu != nil {
  131. gasUsed = receipts[len(receipts)-1].CumulativeGasUsed
  132. }
  133. }
  134. if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.GasLimit(),
  135. big.NewInt(int64(self.eth.GpoFullBlockRatio)))) < 0 {
  136. // block is not full, could have posted a tx with MinGasPrice
  137. return big.NewInt(0)
  138. }
  139. txs := block.Transactions()
  140. if len(txs) == 0 {
  141. return big.NewInt(0)
  142. }
  143. // block is full, find smallest gasPrice
  144. minPrice := txs[0].GasPrice()
  145. for i := 1; i < len(txs); i++ {
  146. price := txs[i].GasPrice()
  147. if price.Cmp(minPrice) < 0 {
  148. minPrice = price
  149. }
  150. }
  151. return minPrice
  152. }
  153. func (self *GasPriceOracle) SuggestPrice() *big.Int {
  154. self.lastBaseMutex.Lock()
  155. base := self.lastBase
  156. self.lastBaseMutex.Unlock()
  157. if base == nil {
  158. base = self.eth.GpoMinGasPrice
  159. }
  160. if base == nil {
  161. return big.NewInt(10000000000000) // apparently MinGasPrice is not initialized during some tests
  162. }
  163. baseCorr := new(big.Int).Mul(base, big.NewInt(int64(self.eth.GpobaseCorrectionFactor)))
  164. baseCorr.Div(baseCorr, big.NewInt(100))
  165. if baseCorr.Cmp(self.eth.GpoMinGasPrice) < 0 {
  166. return self.eth.GpoMinGasPrice
  167. }
  168. if baseCorr.Cmp(self.eth.GpoMaxGasPrice) > 0 {
  169. return self.eth.GpoMaxGasPrice
  170. }
  171. return baseCorr
  172. }