eth/gasprice: add configurable threshold to gas price oracle (#22752)

This commit is contained in:
Daniel Liu 2024-05-20 14:47:28 +08:00
parent 2b365e8112
commit f445196dcf
5 changed files with 43 additions and 20 deletions

View file

@ -128,6 +128,7 @@ var (
//utils.GpoBlocksFlag, //utils.GpoBlocksFlag,
//utils.GpoPercentileFlag, //utils.GpoPercentileFlag,
utils.GpoMaxGasPriceFlag, utils.GpoMaxGasPriceFlag,
utils.GpoIgnoreGasPriceFlag,
//utils.ExtraDataFlag, //utils.ExtraDataFlag,
configFileFlag, configFileFlag,
utils.AnnounceTxsFlag, utils.AnnounceTxsFlag,

View file

@ -196,6 +196,7 @@ var AppHelpFlagGroups = []flagGroup{
// utils.GpoBlocksFlag, // utils.GpoBlocksFlag,
// utils.GpoPercentileFlag, // utils.GpoPercentileFlag,
// utils.GpoMaxGasPriceFlag, // utils.GpoMaxGasPriceFlag,
// utils.GpoIgnoreGasPriceFlag,
// }, // },
//}, //},
//{ //{

View file

@ -560,6 +560,11 @@ var (
Usage: "Maximum gas price will be recommended by gpo", Usage: "Maximum gas price will be recommended by gpo",
Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), Value: ethconfig.Defaults.GPO.MaxPrice.Int64(),
} }
GpoIgnoreGasPriceFlag = cli.Int64Flag{
Name: "gpo.ignoreprice",
Usage: "Gas price below which gpo will ignore transactions",
Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(),
}
WhisperEnabledFlag = cli.BoolFlag{ WhisperEnabledFlag = cli.BoolFlag{
Name: "shh", Name: "shh",
Usage: "Enable Whisper", Usage: "Enable Whisper",
@ -999,6 +1004,9 @@ func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) {
if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) { if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) {
cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name)) cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name))
} }
if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) {
cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name))
}
} }
func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {

View file

@ -36,16 +36,18 @@ import (
// FullNodeGPO contains default gasprice oracle settings for full node. // FullNodeGPO contains default gasprice oracle settings for full node.
var FullNodeGPO = gasprice.Config{ var FullNodeGPO = gasprice.Config{
Blocks: 20, Blocks: 20,
Percentile: 60, Percentile: 60,
MaxPrice: gasprice.DefaultMaxPrice, MaxPrice: gasprice.DefaultMaxPrice,
IgnorePrice: gasprice.DefaultIgnorePrice,
} }
// LightClientGPO contains default gasprice oracle settings for light client. // LightClientGPO contains default gasprice oracle settings for light client.
var LightClientGPO = gasprice.Config{ var LightClientGPO = gasprice.Config{
Blocks: 2, Blocks: 2,
Percentile: 60, Percentile: 60,
MaxPrice: gasprice.DefaultMaxPrice, MaxPrice: gasprice.DefaultMaxPrice,
IgnorePrice: gasprice.DefaultIgnorePrice,
} }
// Defaults contains default settings for use on the Ethereum main net. // Defaults contains default settings for use on the Ethereum main net.

View file

@ -32,12 +32,14 @@ import (
const sampleNumber = 3 // Number of transactions sampled in a block const sampleNumber = 3 // Number of transactions sampled in a block
var DefaultMaxPrice = big.NewInt(500 * params.GWei) var DefaultMaxPrice = big.NewInt(500 * params.GWei)
var DefaultIgnorePrice = big.NewInt(2 * params.Wei)
type Config struct { type Config struct {
Blocks int Blocks int
Percentile int Percentile int
Default *big.Int `toml:",omitempty"` Default *big.Int `toml:",omitempty"`
MaxPrice *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"`
IgnorePrice *big.Int `toml:",omitempty"`
} }
// OracleBackend includes all necessary background APIs for oracle. // OracleBackend includes all necessary background APIs for oracle.
@ -50,12 +52,13 @@ type OracleBackend interface {
// Oracle recommends gas prices based on the content of recent // Oracle recommends gas prices based on the content of recent
// blocks. Suitable for both light and full clients. // blocks. Suitable for both light and full clients.
type Oracle struct { type Oracle struct {
backend OracleBackend backend OracleBackend
lastHead common.Hash lastHead common.Hash
lastPrice *big.Int lastPrice *big.Int
maxPrice *big.Int maxPrice *big.Int
cacheLock sync.RWMutex ignorePrice *big.Int
fetchLock sync.Mutex cacheLock sync.RWMutex
fetchLock sync.Mutex
checkBlocks int checkBlocks int
percentile int percentile int
@ -83,10 +86,18 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
maxPrice = DefaultMaxPrice maxPrice = DefaultMaxPrice
log.Warn("Sanitizing invalid gasprice oracle price cap", "provided", params.MaxPrice, "updated", maxPrice) log.Warn("Sanitizing invalid gasprice oracle price cap", "provided", params.MaxPrice, "updated", maxPrice)
} }
ignorePrice := params.IgnorePrice
if ignorePrice == nil || ignorePrice.Int64() <= 0 {
ignorePrice = DefaultIgnorePrice
log.Warn("Sanitizing invalid gasprice oracle ignore price", "provided", params.IgnorePrice, "updated", ignorePrice)
} else if ignorePrice.Int64() > 0 {
log.Info("Gasprice oracle is ignoring threshold set", "threshold", ignorePrice)
}
return &Oracle{ return &Oracle{
backend: backend, backend: backend,
lastPrice: params.Default, lastPrice: params.Default,
maxPrice: maxPrice, maxPrice: maxPrice,
ignorePrice: ignorePrice,
checkBlocks: blocks, checkBlocks: blocks,
percentile: percent, percentile: percent,
} }
@ -122,7 +133,7 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
txPrices []*big.Int txPrices []*big.Int
) )
for sent < gpo.checkBlocks && number > 0 { for sent < gpo.checkBlocks && number > 0 {
go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, result, quit) go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
sent++ sent++
exp++ exp++
number-- number--
@ -145,7 +156,7 @@ func (gpo *Oracle) SuggestPrice(ctx context.Context) (*big.Int, error) {
// meaningful returned, try to query more blocks. But the maximum // meaningful returned, try to query more blocks. But the maximum
// is 2*checkBlocks. // is 2*checkBlocks.
if len(res.prices) == 1 && len(txPrices)+1+exp < gpo.checkBlocks*2 && number > 0 { if len(res.prices) == 1 && len(txPrices)+1+exp < gpo.checkBlocks*2 && number > 0 {
go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, result, quit) go gpo.getBlockPrices(ctx, types.MakeSigner(gpo.backend.ChainConfig(), big.NewInt(int64(number))), number, sampleNumber, gpo.ignorePrice, result, quit)
sent++ sent++
exp++ exp++
number-- number--
@ -189,7 +200,7 @@ func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPriceCmp(t[
// and sends it to the result channel. If the block is empty or all transactions // and sends it to the result channel. If the block is empty or all transactions
// are sent by the miner itself(it doesn't make any sense to include this kind of // are sent by the miner itself(it doesn't make any sense to include this kind of
// transaction prices for sampling), nil gasprice is returned. // transaction prices for sampling), nil gasprice is returned.
func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, blockNum uint64, limit int, result chan getBlockPricesResult, quit chan struct{}) { func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, blockNum uint64, limit int, ignoreUnder *big.Int, result chan getBlockPricesResult, quit chan struct{}) {
block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) block, err := gpo.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum))
if block == nil { if block == nil {
select { select {
@ -205,7 +216,7 @@ func (gpo *Oracle) getBlockPrices(ctx context.Context, signer types.Signer, bloc
var prices []*big.Int var prices []*big.Int
for _, tx := range txs { for _, tx := range txs {
if tx.GasPrice().Cmp(common.Big1) <= 0 { if ignoreUnder != nil && tx.GasPrice().Cmp(ignoreUnder) == -1 {
continue continue
} }
sender, err := types.Sender(signer, tx) sender, err := types.Sender(signer, tx)