Преглед изворни кода

eth/gasprice: set default percentile to 60%, count blocks instead of transactions (#15828)

The first should address a long term issue where we recommend a gas
price that is greater than that required for 50% of transactions in
recent blocks, which can lead to gas price inflation as people take
this figure and add a margin to it, resulting in a positive feedback
loop.
Nick Johnson пре 7 година
родитељ
комит
b06e20bc7c
2 измењених фајлова са 34 додато и 19 уклоњено
  1. 2 2
      eth/config.go
  2. 32 17
      eth/gasprice/gasprice.go

+ 2 - 2
eth/config.go

@@ -49,8 +49,8 @@ var DefaultConfig = Config{
 
 	TxPool: core.DefaultTxPoolConfig,
 	GPO: gasprice.Config{
-		Blocks:     10,
-		Percentile: 50,
+		Blocks:     20,
+		Percentile: 60,
 	},
 }
 

+ 32 - 17
eth/gasprice/gasprice.go

@@ -23,6 +23,7 @@ import (
 	"sync"
 
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rpc"
@@ -101,9 +102,9 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
 	ch := make(chan getBlockPricesResult, gpo.checkBlocks)
 	sent := 0
 	exp := 0
-	var txPrices []*big.Int
+	var blockPrices []*big.Int
 	for sent < gpo.checkBlocks && blockNum > 0 {
-		go gpo.getBlockPrices(ctx, blockNum, ch)
+		go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
 		sent++
 		exp++
 		blockNum--
@@ -115,8 +116,8 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
 			return lastPrice, res.err
 		}
 		exp--
-		if len(res.prices) > 0 {
-			txPrices = append(txPrices, res.prices...)
+		if res.price != nil {
+			blockPrices = append(blockPrices, res.price)
 			continue
 		}
 		if maxEmpty > 0 {
@@ -124,16 +125,16 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
 			continue
 		}
 		if blockNum > 0 && sent < gpo.maxBlocks {
-			go gpo.getBlockPrices(ctx, blockNum, ch)
+			go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(blockNum))), blockNum, ch)
 			sent++
 			exp++
 			blockNum--
 		}
 	}
 	price := lastPrice
-	if len(txPrices) > 0 {
-		sort.Sort(bigIntArray(txPrices))
-		price = txPrices[(len(txPrices)-1)*gpo.percentile/100]
+	if len(blockPrices) > 0 {
+		sort.Sort(bigIntArray(blockPrices))
+		price = blockPrices[(len(blockPrices)-1)*gpo.percentile/100]
 	}
 	if price.Cmp(maxPrice) > 0 {
 		price = new(big.Int).Set(maxPrice)
@@ -147,24 +148,38 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
 }
 
 type getBlockPricesResult struct {
-	prices []*big.Int
-	err    error
+	price *big.Int
+	err   error
 }
 
-// getLowestPrice calculates the lowest transaction gas price in a given block
+type transactionsByGasPrice []*types.Transaction
+
+func (t transactionsByGasPrice) Len() int           { return len(t) }
+func (t transactionsByGasPrice) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
+func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPrice().Cmp(t[j].GasPrice()) < 0 }
+
+// getBlockPrices calculates the lowest transaction gas price in a given block
 // and sends it to the result channel. If the block is empty, price is nil.
-func (gpo *Oracle) getBlockPrices(ctx context.Context, blockNum uint64, ch chan getBlockPricesResult) {
+func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, blockNum uint64, ch chan getBlockPricesResult) {
 	block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
 	if block == nil {
 		ch <- getBlockPricesResult{nil, err}
 		return
 	}
-	txs := block.Transactions()
-	prices := make([]*big.Int, len(txs))
-	for i, tx := range txs {
-		prices[i] = tx.GasPrice()
+
+	blockTxs := block.Transactions()
+	txs := make([]*types.Transaction, len(blockTxs))
+	copy(txs, blockTxs)
+	sort.Sort(transactionsByGasPrice(txs))
+
+	for _, tx := range txs {
+		sender, err := types.Sender(signer, tx)
+		if err == nil && sender != block.Coinbase() {
+			ch <- getBlockPricesResult{tx.GasPrice(), nil}
+			return
+		}
 	}
-	ch <- getBlockPricesResult{prices, nil}
+	ch <- getBlockPricesResult{nil, nil}
 }
 
 type bigIntArray []*big.Int