From 8db2a6f798196cb9259aa48cc380ee1996c2bbfb Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Wed, 8 Sep 2021 11:53:54 +0800 Subject: [PATCH 1/2] eth, ethstats, graphql, internal, les: fix gasprice limit --- eth/api_backend.go | 8 ++++++-- eth/gasprice/gasprice.go | 8 ++++++++ ethclient/ethclient_test.go | 2 +- ethstats/ethstats.go | 7 +++++-- graphql/graphql.go | 14 ++++++++++---- internal/ethapi/api.go | 13 +++++++++---- internal/ethapi/backend.go | 3 +-- internal/ethapi/transaction_args.go | 13 +++++++++---- les/api_backend.go | 8 ++++++-- 9 files changed, 55 insertions(+), 21 deletions(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 1af33414cda4..692522a90792 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -284,8 +284,12 @@ func (b *EthAPIBackend) SyncProgress() ethereum.SyncProgress { return b.eth.Downloader().Progress() } -func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return b.gpo.SuggestTipCap(ctx) +func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, *big.Int, error) { + suggestion, err := b.gpo.SuggestTipCap(ctx) + if err != nil { + return nil, nil, err + } + return suggestion, b.gpo.MaxTransactionPrice(), nil } func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 8feb5ef24ba4..9cfcde7de236 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -212,6 +212,14 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { return new(big.Int).Set(price), nil } +// MaxTransactionPrice returns the user-configured maximum transaction price +// they can afford. Before the london it's only applied for the transaction +// tip but after the london the sum of tip and baseFee should be applied with +// this limitation. +func (oracle *Oracle) MaxTransactionPrice() *big.Int { + return oracle.maxPrice +} + type results struct { values []*big.Int err error diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index a958c1e32ad1..9c38c1c00544 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -458,7 +458,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if gasPrice.Cmp(big.NewInt(1875000000)) != 0 { // 1 gwei tip + 0.875 basefee after a 1 gwei fee empty block + if gasPrice.Cmp(big.NewInt(1765625000)) != 0 { // 1 gwei tip + 0.765625 basefee after two 1 gwei fee empty blocks(genesis, block1) t.Fatalf("unexpected gas price: %v", gasPrice) } // SuggestGasTipCap (should suggest 1 Gwei) diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 55c0c880f33c..716376ec2d0e 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -77,7 +77,7 @@ type fullNodeBackend interface { Miner() *miner.Miner BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) CurrentBlock() *types.Block - SuggestGasTipCap(ctx context.Context) (*big.Int, error) + SuggestGasTipCap(ctx context.Context) (*big.Int, *big.Int, error) } // Service implements an Ethereum netstats reporting daemon that pushes local @@ -780,9 +780,12 @@ func (s *Service) reportStats(conn *connWrapper) error { sync := fullBackend.SyncProgress() syncing = fullBackend.CurrentHeader().Number.Uint64() >= sync.HighestBlock - price, _ := fullBackend.SuggestGasTipCap(context.Background()) + price, _, _ := fullBackend.SuggestGasTipCap(context.Background()) gasprice = int(price.Uint64()) if basefee := fullBackend.CurrentHeader().BaseFee; basefee != nil { + // In theory, the baseFee of pending block should be applied, + // but the accuracy requirement in ethstat is not that high. It's + // fine to use the head block basefee instead here. gasprice += int(basefee.Uint64()) } } else { diff --git a/graphql/graphql.go b/graphql/graphql.go index 0da9faa95bc5..4a3d651c74fa 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/filters" @@ -1191,18 +1192,23 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria } func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) { - tipcap, err := r.backend.SuggestGasTipCap(ctx) + tipcap, maxPrice, err := r.backend.SuggestGasTipCap(ctx) if err != nil { return hexutil.Big{}, err } - if head := r.backend.CurrentHeader(); head.BaseFee != nil { - tipcap.Add(tipcap, head.BaseFee) + head := r.backend.CurrentHeader() + if r.backend.ChainConfig().IsLondon(new(big.Int).Add(head.Number, common.Big1)) { + baseFee := misc.CalcBaseFee(r.backend.ChainConfig(), head) + tipcap.Add(tipcap, baseFee) + if tipcap.Cmp(maxPrice) > 0 { + tipcap = maxPrice + } } return (hexutil.Big)(*tipcap), nil } func (r *Resolver) MaxPriorityFeePerGas(ctx context.Context) (hexutil.Big, error) { - tipcap, err := r.backend.SuggestGasTipCap(ctx) + tipcap, _, err := r.backend.SuggestGasTipCap(ctx) if err != nil { return hexutil.Big{}, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4f00370cbbbe..26d4e7c506bc 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -61,19 +61,24 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI { // GasPrice returns a suggestion for a gas price for legacy transactions. func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) + tipcap, maxPrice, err := s.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } - if head := s.b.CurrentHeader(); head.BaseFee != nil { - tipcap.Add(tipcap, head.BaseFee) + head := s.b.CurrentHeader() + if s.b.ChainConfig().IsLondon(new(big.Int).Add(head.Number, common.Big1)) { + baseFee := misc.CalcBaseFee(s.b.ChainConfig(), head) + tipcap.Add(tipcap, baseFee) + if tipcap.Cmp(maxPrice) > 0 { + tipcap = maxPrice + } } return (*hexutil.Big)(tipcap), err } // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) + tipcap, _, err := s.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 1624f49635b3..e12bb4323693 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -41,8 +41,7 @@ import ( type Backend interface { // General Ethereum API SyncProgress() ethereum.SyncProgress - - SuggestGasTipCap(ctx context.Context) (*big.Int, error) + SuggestGasTipCap(ctx context.Context) (*big.Int, *big.Int, error) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) ChainDb() ethdb.Database AccountManager() *accounts.Manager diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 2d08d3008f38..9401a757bd6e 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -86,7 +87,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { // In this clause, user left some fields unspecified. if b.ChainConfig().IsLondon(head.Number) && args.GasPrice == nil { if args.MaxPriorityFeePerGas == nil { - tip, err := b.SuggestGasTipCap(ctx) + tip, _, err := b.SuggestGasTipCap(ctx) if err != nil { return err } @@ -107,15 +108,19 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") } if args.GasPrice == nil { - price, err := b.SuggestGasTipCap(ctx) + price, maxPrice, err := b.SuggestGasTipCap(ctx) if err != nil { return err } - if b.ChainConfig().IsLondon(head.Number) { + if b.ChainConfig().IsLondon(new(big.Int).Add(head.Number, common.Big1)) { // The legacy tx gas price suggestion should not add 2x base fee // because all fees are consumed, so it would result in a spiral // upwards. - price.Add(price, head.BaseFee) + baseFee := misc.CalcBaseFee(b.ChainConfig(), head) + price.Add(price, baseFee) + if price.Cmp(maxPrice) > 0 { + price = maxPrice + } } args.GasPrice = (*hexutil.Big)(price) } diff --git a/les/api_backend.go b/les/api_backend.go index e12984cb49e3..d6a3c2983996 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -265,8 +265,12 @@ func (b *LesApiBackend) ProtocolVersion() int { return b.eth.LesVersion() + 10000 } -func (b *LesApiBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return b.gpo.SuggestTipCap(ctx) +func (b *LesApiBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, *big.Int, error) { + suggestion, err := b.gpo.SuggestTipCap(ctx) + if err != nil { + return nil, nil, err + } + return suggestion, b.gpo.MaxTransactionPrice(), nil } func (b *LesApiBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { From 09da1a89e7f380b258a26fd8aab798bad78fb76c Mon Sep 17 00:00:00 2001 From: Gary rong Date: Wed, 13 Oct 2021 11:10:22 +0800 Subject: [PATCH 2/2] internal/ethapi: cap tip with maxprice --- internal/ethapi/transaction_args.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 9401a757bd6e..f72b7bbc066c 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -87,10 +87,18 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { // In this clause, user left some fields unspecified. if b.ChainConfig().IsLondon(head.Number) && args.GasPrice == nil { if args.MaxPriorityFeePerGas == nil { - tip, _, err := b.SuggestGasTipCap(ctx) + tip, maxprice, err := b.SuggestGasTipCap(ctx) if err != nil { return err } + paid := new(big.Int).Add(tip, head.BaseFee) + if paid.Cmp(maxprice) > 0 { + if maxprice.Cmp(head.BaseFee) > 0 { + tip = new(big.Int).Sub(maxprice, head.BaseFee) + } else { + tip = big.NewInt(0) + } + } args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) } if args.MaxFeePerGas == nil {