forked from cerc-io/plugeth
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.
This commit is contained in:
parent
3a5a5599dd
commit
b06e20bc7c
@ -49,8 +49,8 @@ var DefaultConfig = Config{
|
|||||||
|
|
||||||
TxPool: core.DefaultTxPoolConfig,
|
TxPool: core.DefaultTxPoolConfig,
|
||||||
GPO: gasprice.Config{
|
GPO: gasprice.Config{
|
||||||
Blocks: 10,
|
Blocks: 20,
|
||||||
Percentile: 50,
|
Percentile: 60,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"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)
|
ch := make(chan getBlockPricesResult, gpo.checkBlocks)
|
||||||
sent := 0
|
sent := 0
|
||||||
exp := 0
|
exp := 0
|
||||||
var txPrices []*big.Int
|
var blockPrices []*big.Int
|
||||||
for sent < gpo.checkBlocks && blockNum > 0 {
|
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++
|
sent++
|
||||||
exp++
|
exp++
|
||||||
blockNum--
|
blockNum--
|
||||||
@ -115,8 +116,8 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
|||||||
return lastPrice, res.err
|
return lastPrice, res.err
|
||||||
}
|
}
|
||||||
exp--
|
exp--
|
||||||
if len(res.prices) > 0 {
|
if res.price != nil {
|
||||||
txPrices = append(txPrices, res.prices...)
|
blockPrices = append(blockPrices, res.price)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if maxEmpty > 0 {
|
if maxEmpty > 0 {
|
||||||
@ -124,16 +125,16 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if blockNum > 0 && sent < gpo.maxBlocks {
|
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++
|
sent++
|
||||||
exp++
|
exp++
|
||||||
blockNum--
|
blockNum--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
price := lastPrice
|
price := lastPrice
|
||||||
if len(txPrices) > 0 {
|
if len(blockPrices) > 0 {
|
||||||
sort.Sort(bigIntArray(txPrices))
|
sort.Sort(bigIntArray(blockPrices))
|
||||||
price = txPrices[(len(txPrices)-1)*gpo.percentile/100]
|
price = blockPrices[(len(blockPrices)-1)*gpo.percentile/100]
|
||||||
}
|
}
|
||||||
if price.Cmp(maxPrice) > 0 {
|
if price.Cmp(maxPrice) > 0 {
|
||||||
price = new(big.Int).Set(maxPrice)
|
price = new(big.Int).Set(maxPrice)
|
||||||
@ -147,24 +148,38 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type getBlockPricesResult struct {
|
type getBlockPricesResult struct {
|
||||||
prices []*big.Int
|
price *big.Int
|
||||||
err error
|
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.
|
// 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))
|
block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
ch <- getBlockPricesResult{nil, err}
|
ch <- getBlockPricesResult{nil, err}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
txs := block.Transactions()
|
|
||||||
prices := make([]*big.Int, len(txs))
|
blockTxs := block.Transactions()
|
||||||
for i, tx := range txs {
|
txs := make([]*types.Transaction, len(blockTxs))
|
||||||
prices[i] = tx.GasPrice()
|
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
|
type bigIntArray []*big.Int
|
||||||
|
Loading…
Reference in New Issue
Block a user