github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/gasprice/gasprice.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package gasprice 26 27 import ( 28 "context" 29 "math/big" 30 "sort" 31 "sync" 32 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/internal/ethapi" 36 "github.com/ethereum/go-ethereum/params" 37 "github.com/ethereum/go-ethereum/rpc" 38 ) 39 40 var maxPrice = big.NewInt(500 * params.Shannon) 41 42 type Config struct { 43 Blocks int 44 Percentile int 45 Default *big.Int `toml:",omitempty"` 46 } 47 48 //Oracle根据近期的内容建议天然气价格 49 //阻碍。适合轻客户和全客户。 50 type Oracle struct { 51 backend ethapi.Backend 52 lastHead common.Hash 53 lastPrice *big.Int 54 cacheLock sync.RWMutex 55 fetchLock sync.Mutex 56 57 checkBlocks, maxEmpty, maxBlocks int 58 percentile int 59 } 60 61 //new oracle返回新的oracle。 62 func NewOracle(backend ethapi.Backend, params Config) *Oracle { 63 blocks := params.Blocks 64 if blocks < 1 { 65 blocks = 1 66 } 67 percent := params.Percentile 68 if percent < 0 { 69 percent = 0 70 } 71 if percent > 100 { 72 percent = 100 73 } 74 return &Oracle{ 75 backend: backend, 76 lastPrice: params.Default, 77 checkBlocks: blocks, 78 maxEmpty: blocks / 2, 79 maxBlocks: blocks * 5, 80 percentile: percent, 81 } 82 } 83 84 //SuggestPrice返回建议的天然气价格。 85 func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) { 86 gpo.cacheLock.RLock() 87 lastHead := gpo.lastHead 88 lastPrice := gpo.lastPrice 89 gpo.cacheLock.RUnlock() 90 91 head, _ := gpo.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) 92 headHash := head.Hash() 93 if headHash == lastHead { 94 return lastPrice, nil 95 } 96 97 gpo.fetchLock.Lock() 98 defer gpo.fetchLock.Unlock() 99 100 //尝试再次检查缓存,可能上次获取的是我们需要的 101 gpo.cacheLock.RLock() 102 lastHead = gpo.lastHead 103 lastPrice = gpo.lastPrice 104 gpo.cacheLock.RUnlock() 105 if headHash == lastHead { 106 return lastPrice, nil 107 } 108 109 blockNum := head.Number.Uint64() 110 ch := make(chan getBlockPricesResult, gpo.checkBlocks) 111 sent := 0 112 exp := 0 113 var blockPrices []*big.Int 114 for sent < gpo.checkBlocks && blockNum > 0 { 115 go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch) 116 sent++ 117 exp++ 118 blockNum-- 119 } 120 maxEmpty := gpo.maxEmpty 121 for exp > 0 { 122 res := <-ch 123 if res.err != nil { 124 return lastPrice, res.err 125 } 126 exp-- 127 if res.price != nil { 128 blockPrices = append(blockPrices, res.price) 129 continue 130 } 131 if maxEmpty > 0 { 132 maxEmpty-- 133 continue 134 } 135 if blockNum > 0 && sent < gpo.maxBlocks { 136 go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch) 137 sent++ 138 exp++ 139 blockNum-- 140 } 141 } 142 price := lastPrice 143 if len(blockPrices) > 0 { 144 sort.Sort(bigIntArray(blockPrices)) 145 price = blockPrices[(len(blockPrices)-1)*gpo.percentile/100] 146 } 147 if price.Cmp(maxPrice) > 0 { 148 price = new(big.Int).Set(maxPrice) 149 } 150 151 gpo.cacheLock.Lock() 152 gpo.lastHead = headHash 153 gpo.lastPrice = price 154 gpo.cacheLock.Unlock() 155 return price, nil 156 } 157 158 type getBlockPricesResult struct { 159 price *big.Int 160 err error 161 } 162 163 type transactionsByGasPrice []*types.Transaction 164 165 func (t transactionsByGasPrice) Len() int { return len(t) } 166 func (t transactionsByGasPrice) Swap(i, j int) { t[i], t[j] = t[j], t[i] } 167 func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPrice().Cmp(t[j].GasPrice()) < 0 } 168 169 //GetBlockPrices计算给定区块中的最低交易天然气价格 170 //并发送到结果通道。如果块为空,则价格为零。 171 func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, blockNum uint64, ch chan getBlockPricesResult) { 172 block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) 173 if block == nil { 174 ch <- getBlockPricesResult{nil, err} 175 return 176 } 177 178 blockTxs := block.Transactions() 179 txs := make([]*types.Transaction, len(blockTxs)) 180 copy(txs, blockTxs) 181 sort.Sort(transactionsByGasPrice(txs)) 182 183 for _, tx := range txs { 184 sender, err := types.Sender(signer, tx) 185 if err == nil && sender != block.Coinbase() { 186 ch <- getBlockPricesResult{tx.GasPrice(), nil} 187 return 188 } 189 } 190 ch <- getBlockPricesResult{nil, nil} 191 } 192 193 type bigIntArray []*big.Int 194 195 func (s bigIntArray) Len() int { return len(s) } 196 func (s bigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 } 197 func (s bigIntArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }